All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.com.ionic.sdk.agent.request.getkey.GetKeysTransaction Maven / Gradle / Ivy

Go to download

The Ionic Java SDK provides an easy-to-use interface to the Ionic Platform.

There is a newer version: 2.9.0
Show newest version
package com.ionic.sdk.agent.request.getkey;

import com.ionic.sdk.agent.Agent;
import com.ionic.sdk.agent.config.AgentConfig;
import com.ionic.sdk.agent.key.KeyAttributesMap;
import com.ionic.sdk.agent.key.KeyObligationsMap;
import com.ionic.sdk.agent.request.base.AgentRequestBase;
import com.ionic.sdk.agent.request.base.AgentResponseBase;
import com.ionic.sdk.agent.request.base.AgentTransactionBase;
import com.ionic.sdk.agent.service.IDC;
import com.ionic.sdk.agent.transaction.AgentTransactionUtil;
import com.ionic.sdk.cipher.aes.AesGcmCipher;
import com.ionic.sdk.core.codec.Transcoder;
import com.ionic.sdk.core.value.Value;
import com.ionic.sdk.crypto.CryptoUtils;
import com.ionic.sdk.device.profile.DeviceProfile;
import com.ionic.sdk.error.IonicException;
import com.ionic.sdk.error.SdkError;
import com.ionic.sdk.httpclient.Http;
import com.ionic.sdk.httpclient.HttpRequest;
import com.ionic.sdk.httpclient.HttpResponse;
import com.ionic.sdk.json.JsonIO;
import com.ionic.sdk.json.JsonSource;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonValue;
import java.io.ByteArrayInputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;

/**
 * An object encapsulating the server request and response for an Agent.getKeys() request.
 */
public class GetKeysTransaction extends AgentTransactionBase {

    /**
     * Class scoped logger.
     */
    private final Logger logger = Logger.getLogger(getClass().getName());

    /**
     * Helper object for serialization of request to json for submission to KeyServices implementation.
     */
    private GetKeysMessage message;

    /**
     * The device profile associated with this GetKeys transaction.
     * 

* In order to support multi-keyspace requests, * this {@link DeviceProfile} corresponds to a profile (with matching keyspace) contained in the * {@link com.ionic.sdk.device.profile.persistor.ProfilePersistor} associated with the in-use {@link Agent}, and * not necessarily the Agent's active profile. */ private DeviceProfile deviceProfile; /** * Constructor. * * @param agent the persistent data associated with the device's Secure Enrollment Profile * @param requestBase the client request * @param responseBase the server response */ public GetKeysTransaction( final Agent agent, final AgentRequestBase requestBase, final AgentResponseBase responseBase) { super(agent, requestBase, responseBase); } /** * Assemble a client request for submission to the IDC infrastructure. * * @param fingerprint authentication data associated with the client state to be included in the request * @return a request object, ready for submission to the server * @throws IonicException on failure to assemble the request */ @Override protected final HttpRequest buildHttpRequest(final Properties fingerprint) throws IonicException { // check for one or the other, protection keys or external ids, must have one final GetKeysRequest request = (GetKeysRequest) getRequestBase(); final List externalIds = request.getExternalIds(); final List keyIds = request.getKeyIds(); if ((externalIds.isEmpty()) && (keyIds.isEmpty())) { throw new IonicException(SdkError.ISAGENT_BADREQUEST, "No key ids or external ids in get key request."); } final String firstKeyId = (keyIds.isEmpty() ? "" : keyIds.iterator().next()); final Agent agent = getAgent(); final String autoSelectProfile = agent.getConfig().getProperty( AgentConfig.Key.AUTOSELECT_PROFILE, Boolean.FALSE.toString()); this.deviceProfile = getRelevantProfileForKeyId(agent, firstKeyId, Boolean.parseBoolean(autoSelectProfile)); this.message = new GetKeysMessage(agent, this.deviceProfile); final JsonObject jsonMessage = message.getJsonMessage(request, fingerprint); final String cid = message.getCid(); final String resource = String.format(IDC.Resource.KEYS_GET, IDC.Resource.SERVER_API_V24); final String envelope = JsonIO.write(jsonMessage, false); //logger.finest(envelope); // plaintext json; IDC http entity (for debugging) // assemble the secured (outer) HTTP payload final AesGcmCipher cipher = new AesGcmCipher(); cipher.setKey(this.deviceProfile.getAesCdIdcProfileKey()); cipher.setAuthData(Transcoder.utf8().decode(cid)); final String envelopeSecureBase64 = cipher.encryptToBase64(envelope); final JsonObject payload = Json.createObjectBuilder() .add(IDC.Payload.CID, cid) .add(IDC.Payload.ENVELOPE, envelopeSecureBase64) .build(); final String entitySecure = JsonIO.write(payload, false); logger.fine(entitySecure); // assemble the HTTP request to be sent to the server final URL url = AgentTransactionUtil.getProfileUrl(this.deviceProfile); final ByteArrayInputStream bis = new ByteArrayInputStream( Transcoder.utf8().decode(JsonIO.write(payload, false))); return new HttpRequest(url, Http.Method.POST, resource, getHttpHeaders(), bis); } /** * Resolve the {@link DeviceProfile} to be used in the context of this transaction. *

* To determine the DeviceProfile to use for this request, the {@link AgentConfig} boolean * property "autoselectprofile" is examined. *

    *
  • If set to "true", the most recently created device profile with a matching keyspace is returned.
  • *
  • Otherwise, the agent's active profile is used.
  • *
*

* Note that only one server request is issued for a given GetKeys transaction. In particular, it is not valid to * request keys from multiple key servers in a single GetKeys request. To request keys from multiple keyspaces, * one GetKeys request should be made for each unique keyspace. * * @param agent the persistent data associated with the device's Secure Enrollment Profile * @param keyId the identifier associated with the first record in the request key ID list * @param autoSelect true iff all profile records should be considered * @return the relevant {@link DeviceProfile} record for the request */ private DeviceProfile getRelevantProfileForKeyId(final Agent agent, final String keyId, final boolean autoSelect) { return autoSelect ? agent.getDeviceProfileForKeyId(keyId) : agent.getActiveProfile(); } /** * Parse and process the server response to the client request. * * @param httpRequest the server request * @param httpResponse the server response * @throws IonicException on errors in the server response */ @Override protected final void parseHttpResponse( final HttpRequest httpRequest, final HttpResponse httpResponse) throws IonicException { final Agent agent = getAgent(); // unwrap the server response parseHttpResponseBase(httpRequest, httpResponse, message.getCid(), deviceProfile); // apply logic specific to the response type //final GetKeysRequest request = (GetKeysRequest) getRequestBase(); final GetKeysResponse response = (GetKeysResponse) getResponseBase(); final String cid = response.getConversationId(); final JsonObject jsonPayload = response.getJsonPayload(); final JsonObject jsonData = JsonSource.getJsonObject(jsonPayload, IDC.Payload.DATA); final JsonArray jsonProtectionKeys = JsonSource.getJsonArray(jsonData, IDC.Payload.PROTECTION_KEYS); for (JsonValue value : jsonProtectionKeys) { // deserialize each response key into a user-consumable object final JsonObject jsonProtectionKey = JsonSource.toJsonObject(value, IDC.Payload.PROTECTION_KEYS); final String id = JsonSource.getString(jsonProtectionKey, IDC.Payload.ID); final String keyHex = JsonSource.getString(jsonProtectionKey, IDC.Payload.KEY); final String cattrs = JsonSource.getString(jsonProtectionKey, IDC.Payload.CATTRS); final String mattrs = JsonSource.getString(jsonProtectionKey, IDC.Payload.MATTRS); final String csig = JsonSource.getString(jsonProtectionKey, IDC.Payload.CSIG); final String msig = JsonSource.getString(jsonProtectionKey, IDC.Payload.MSIG); final String authData = Value.join(IDC.Signature.DELIMITER, cid, id, csig, msig); // verify each received response key final AesGcmCipher cipherEi = new AesGcmCipher(); cipherEi.setKey(deviceProfile.getAesCdEiProfileKey()); cipherEi.setAuthData(Transcoder.utf8().decode(authData)); final byte[] clearBytesKey = cipherEi.decrypt(CryptoUtils.hexToBin(keyHex)); // verify each received response attributes message.verifySignature(IDC.Payload.CSIG, csig, cattrs, clearBytesKey); message.verifySignature(IDC.Payload.MSIG, msig, mattrs, clearBytesKey); final String deviceId = agent.getActiveProfile().getDeviceId(); final KeyAttributesMap cattrsKey = message.getJsonAttrs(cattrs, id, clearBytesKey); final KeyAttributesMap mattrsKey = message.getJsonAttrs(mattrs, id, clearBytesKey); response.add(new GetKeysResponse.Key(id, clearBytesKey, deviceId, cattrsKey, mattrsKey, new KeyObligationsMap(), IDC.Metadata.KEYORIGIN_IONIC, csig, msig)); } // populate the errors into the response final JsonObject jsonErrors = JsonSource.getJsonObjectNullable(jsonData, IDC.Payload.ERROR_MAP); if (jsonErrors != null) { final Iterator> iterator = JsonSource.getIterator(jsonErrors); while (iterator.hasNext()) { final Map.Entry entry = iterator.next(); // deserialize each response key into a user-consumable object final String keyId = entry.getKey(); final JsonObject error = JsonSource.toJsonObject(entry.getValue(), IDC.Payload.ERROR_MAP); final int serverCode = JsonSource.getInt(error, IDC.Payload.CODE); final String serverMessage = JsonSource.getString(error, IDC.Payload.MESSAGE); response.add(new GetKeysResponse.IonicError(keyId, 0, serverCode, serverMessage)); } } // optional query results map final JsonObject jsonQueries = JsonSource.getJsonObjectNullable(jsonData, IDC.Payload.QUERY_RESULTS); if (jsonQueries != null) { // grab the request final GetKeysRequest request = (GetKeysRequest) getRequestBase(); // for each external id we requested, see if there's optional errors or key'd responses for (String extId : request.getExternalIds()) { // response reference for each external id must exist (even if empty) final JsonObject queryResult = JsonSource.getJsonObject(jsonQueries, extId); // mapped key ids are optional final JsonArray keyArray = JsonSource.getJsonArrayNullable(queryResult, IDC.Payload.IDS); if (keyArray != null) { final List values = new ArrayList(); for (final JsonValue jsonValue : keyArray) { values.add(JsonSource.toString(jsonValue)); } response.add(new GetKeysResponse.QueryResult(extId, values)); } // errors are optional final JsonObject errorObj = JsonSource.getJsonObjectNullable(queryResult, IDC.Payload.ERROR); if (errorObj != null) { final int errorCode = JsonSource.getInt(errorObj, IDC.Payload.CODE); final String errorMessage = JsonSource.getString(errorObj, IDC.Payload.MESSAGE); response.add(new GetKeysResponse.QueryResult(extId, errorCode, errorMessage)); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy