package at.gv.egiz.eaaf.modules.auth.sl20.utils; import java.io.UnsupportedEncodingException; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Base64; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import at.gv.egiz.eaaf.modules.auth.sl20.Constants; import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoBuildException; public class SL20JsonBuilderUtils { private static JsonMapper mapper = new JsonMapper(); /** * Create command request. * * @param name Commando name * @param params Commando parameters * @return JSON Object * @throws SlCommandoBuildException In case of a build error */ public static ObjectNode createCommand(final String name, final ObjectNode params) throws SlCommandoBuildException { final ObjectNode command = mapper.getMapper().createObjectNode(); addSingleStringElement(command, SL20Constants.SL20_COMMAND_CONTAINER_NAME, name, true); addSingleJsonElement(command, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, params, true); return command; } /** * Create signed command request. * * @param name Commando name * @param params commando parameter * @param signer JWS signer implementation * @return Serialized JWS * @throws SlCommandoBuildException In case of a build error */ public static String createSignedCommand(final String name, final ObjectNode params, final IJoseTools signer) throws SlCommandoBuildException { final ObjectNode command = mapper.getMapper().createObjectNode(); addSingleStringElement(command, SL20Constants.SL20_COMMAND_CONTAINER_NAME, name, true); addSingleJsonElement(command, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, params, true); return signer.createSignature(command.toString()); } /** * Create encrypted command result. * * @param result JSON to encrypt * @param encrypter JWE encrypter implementation * @return Serialized JWE * @throws SlCommandoBuildException In case of a processing error */ public static String createEncryptedCommandoResult(final ObjectNode result, final JsonSecurityUtils encrypter) throws SlCommandoBuildException { // TODO: add real implementation // create header and footer final String dummyHeader = createJsonEncryptionHeader().toString(); final String payLoad = result.toString(); final String dummyFooter = createJsonSignedFooter(); try { return Base64.getUrlEncoder().encodeToString(dummyHeader.getBytes("UTF-8")) + "." + Base64.getUrlEncoder().encodeToString(payLoad.getBytes("UTF-8")) + "." + Base64.getUrlEncoder().encodeToString(dummyFooter.getBytes("UTF-8")); } catch (final UnsupportedEncodingException e) { throw new SlCommandoBuildException("No UTF-8 encoding", e); } } /** * Create command result. * * @param name Commando name * @param result commande result * @param encryptedResult encrypted commando result * @return Result json * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createCommandResponse(final String name, final ObjectNode result, final String encryptedResult) throws SlCommandoBuildException { final ObjectNode command = mapper.getMapper().createObjectNode(); addSingleStringElement(command, SL20Constants.SL20_COMMAND_CONTAINER_NAME, name, true); addOnlyOnceOfTwo(command, SL20Constants.SL20_COMMAND_CONTAINER_RESULT, SL20Constants.SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT, result, encryptedResult); return command; } /** * Create signed command result. * * @param name commando name * @param result commando result * @param encryptedResult encrypted commando result * @return JWS in serialized form * @throws SlCommandoBuildException in case of an error * */ public static String createSignedCommandResponse(final String name, final ObjectNode result, final String encryptedResult, final JsonSecurityUtils signer) throws SlCommandoBuildException { final ObjectNode command = mapper.getMapper().createObjectNode(); addSingleStringElement(command, SL20Constants.SL20_COMMAND_CONTAINER_NAME, name, true); addOnlyOnceOfTwo(command, SL20Constants.SL20_COMMAND_CONTAINER_RESULT, SL20Constants.SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT, result, encryptedResult); final String encodedCommand = command.toString(); // TODO: add real implementation // create header and footer final String dummyHeader = createJsonSignedHeader().toString(); final String dummyFooter = createJsonSignedFooter(); try { return Base64.getUrlEncoder().encodeToString(dummyHeader.getBytes("UTF-8")) + "." + Base64.getUrlEncoder().encodeToString(encodedCommand.getBytes("UTF-8")) + "." + Base64.getUrlEncoder().encodeToString(dummyFooter.getBytes("UTF-8")); } catch (final UnsupportedEncodingException e) { throw new SlCommandoBuildException("No UTF-8 encoding", e); } } /** * Create parameters for Redirect command. * * @param url redirect URL * @param command embedded command * @param signedCommand Signed embedded command * @param ipcRedirect IPC redirect flag * @return result JSON * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createRedirectCommandParameters(final String url, final ObjectNode command, final ObjectNode signedCommand, final Boolean ipcRedirect) throws SlCommandoBuildException { final ObjectNode redirectReqParams = mapper.getMapper().createObjectNode(); addOnlyOnceOfTwo(redirectReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND, command, signedCommand); addSingleStringElement(redirectReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL, url, false); addSingleBooleanElement(redirectReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_IPCREDIRECT, ipcRedirect, false); return redirectReqParams; } /** * Create parameters for Call command. * * @param url http URL for Call command * @param method http method used by call commando result * @param includeTransactionId TransactionId * @param reqParameters Request parameters on CALL command * @return JSON * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createCallCommandParameters(final String url, final String method, final Boolean includeTransactionId, final Map reqParameters) throws SlCommandoBuildException { final ObjectNode callReqParams = mapper.getMapper().createObjectNode(); addSingleStringElement(callReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_URL, url, true); addSingleStringElement(callReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD, method, true); addSingleBooleanElement(callReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_INCLUDETRANSACTIONID, includeTransactionId, false); addArrayOfStringElements(callReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_REQPARAMETER, reqParameters); return callReqParams; } /** * Create result for Error command. * * @param errorCode Error-Code * @param errorMsg Error-message * @return JSON * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createErrorCommandResult(final String errorCode, final String errorMsg) throws SlCommandoBuildException { final ObjectNode result = mapper.getMapper().createObjectNode(); addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, errorCode, true); addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, errorMsg, true); return result; } /** * Create parameters for qualifiedeID command. * * @param consentTemplateId Identifier of the template that is used for consent * visualization * @param consent Consent that has to be signed by user * @param dataUrl DataURL for result * @param x5cEnc Response encryption certificate * @return JSON * @throws CertificateEncodingException In case of a encryption certificate * encoding problem * @throws SlCommandoBuildException In case of a generel error */ public static ObjectNode createQualifiedeEidConsent(final String consentTemplateId, final byte[] consent, final String dataUrl, final X509Certificate x5cEnc) throws CertificateEncodingException, SlCommandoBuildException { final ObjectNode params = mapper.getMapper().createObjectNode(); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_CONSENTTEMPLATEID, consentTemplateId, true); addSingleByteElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_CONSENT, consent, true); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_DATAURL, dataUrl, true); addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_X5CENC, x5cEnc, false); return params; } /** * Create parameters for qualifiedeID command. * * @param authBlockId AuthBlock transformation Id * @param dataUrl DataURL for result * @param additionalReqParameters additional parameters * @param x5cEnc Response encryption certificate * @return JSON * @throws CertificateEncodingException In case of a encryption certificate * encoding problem * @throws SlCommandoBuildException In case of a generel error */ @Deprecated public static ObjectNode createQualifiedEidCommandParameters(final String authBlockId, final String dataUrl, final Map additionalReqParameters, final X509Certificate x5cEnc) throws CertificateEncodingException, SlCommandoBuildException { final ObjectNode params = mapper.getMapper().createObjectNode(); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_AUTHBLOCKID, authBlockId, true); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_DATAURL, dataUrl, true); addArrayOfStringElements(params, SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES, additionalReqParameters); addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_X5CENC, x5cEnc, false); return params; } /** * Create result for qualifiedeID command. * * @param idl IdentityLink * @param authBlock AuthBlock * @param ccsUrl VDA URL * @param loa LoA * @return JSON * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createQualifiedEidCommandResult(final byte[] idl, final byte[] authBlock, final String ccsUrl, final String loa) throws SlCommandoBuildException { final ObjectNode result = mapper.getMapper().createObjectNode(); addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL, idl, true); addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, authBlock, true); addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL, ccsUrl, true); addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA, loa, true); return result; } /** * Create Binding-Key command parameters. * * @param kontoId KontoId * @param subjectName SubjectName * @param keySize KeySize * @param keyAlg Key-algorithm * @param policies Key policy * @param dataUrl DataURL * @param x5cVdaTrust trusted certificate from VDA * @param reqUserPassword User passwort initialize request * @param x5cEnc Result encryption certificate * @return JSON * @throws SlCommandoBuildException in case of an errr * @throws CertificateEncodingException In case of a certificate error */ public static ObjectNode createBindingKeyCommandParams(final String kontoId, final String subjectName, final int keySize, final String keyAlg, final Map policies, final String dataUrl, final X509Certificate x5cVdaTrust, final Boolean reqUserPassword, final X509Certificate x5cEnc) throws SlCommandoBuildException, CertificateEncodingException { final ObjectNode params = mapper.getMapper().createObjectNode(); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_KONTOID, kontoId, true); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_SN, subjectName, true); addSingleNumberElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_KEYLENGTH, keySize, true); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG, keyAlg, true); addArrayOfStringElements(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES, policies); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_DATAURL, dataUrl, true); addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_X5CVDATRUST, x5cVdaTrust, false); addSingleBooleanElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_REQUESTUSERPASSWORD, reqUserPassword, false); addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_X5CENC, x5cEnc, false); return params; } /** * Create Binding-Key command result. * * @param appId AppId * @param csr CSR * @param attCert Key-Attestation certificate * @param password user's password * @return JSON * @throws SlCommandoBuildException In case of an error * @throws CertificateEncodingException In case of a certificate processing * error */ public static ObjectNode createBindingKeyCommandResult(final String appId, final byte[] csr, final X509Certificate attCert, final byte[] password) throws SlCommandoBuildException, CertificateEncodingException { final ObjectNode result = mapper.getMapper().createObjectNode(); addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_APPID, appId, true); addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_CSR, csr, true); addSingleCertificateElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_KEYATTESTATIONZERTIFICATE, attCert, false); addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_USERPASSWORD, password, false); return result; } /** * Create Store Binding-Certificate command parameters. * * @param cert Certificate * @param dataUrl DATA URL * @return JSON * @throws CertificateEncodingException In case of a certificate processing * error * @throws SlCommandoBuildException In case of a error */ public static ObjectNode createStoreBindingCertCommandParams(final X509Certificate cert, final String dataUrl) throws CertificateEncodingException, SlCommandoBuildException { final ObjectNode params = mapper.getMapper().createObjectNode(); addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_STORE_CERTIFICATE, cert, true); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_STORE_DATAURL, dataUrl, true); return params; } /** * Create Store Binding-Certificate command result. * * @return JSON * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createStoreBindingCertCommandSuccessResult() throws SlCommandoBuildException { final ObjectNode result = mapper.getMapper().createObjectNode(); addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS, SL20Constants.SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS_VALUE, true); return result; } /** * Create idAndPassword command parameters. * * @param keyAlg key algorithm * @param dataUrl DATA Url * @param x5cEnc result encryption certificate * @return JSON * @throws SlCommandoBuildException In case of an error * @throws CertificateEncodingException In case of a certificate processing * error */ public static ObjectNode createIdAndPasswordCommandParameters(final String keyAlg, final String dataUrl, final X509Certificate x5cEnc) throws SlCommandoBuildException, CertificateEncodingException { final ObjectNode params = mapper.getMapper().createObjectNode(); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG, keyAlg, true); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_DATAURL, dataUrl, true); addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_X5CENC, x5cEnc, false); return params; } /** * Create idAndPassword command result. * * @param kontoId User's Id * @param password User's password * @return JSON * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createIdAndPasswordCommandResult(final String kontoId, final byte[] password) throws SlCommandoBuildException { final ObjectNode result = mapper.getMapper().createObjectNode(); addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_KONTOID, kontoId, true); addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_USERPASSWORD, password, true); return result; } /** * Create JWS Token Authentication command. * * @param nonce nonce that should be signed * @param dataUrl Data URL * @param displayData Data that should be displayed * @param displayUrl URL to data that should be displayed * @return JSON * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createJwsTokenAuthCommandParams(final String nonce, final String dataUrl, final List displayData, final List displayUrl) throws SlCommandoBuildException { final ObjectNode params = mapper.getMapper().createObjectNode(); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_NONCE, nonce, true); addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DATAURL, dataUrl, true); addArrayOfStrings(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYDATA, displayData); addArrayOfStrings(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYURL, displayUrl); return params; } /** * Create JWS Token Authentication command result. * * @param nonce Serialzed JWS that contains the signed nonce * @return JSON * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createJwsTokenAuthCommandResult(final String nonce) throws SlCommandoBuildException { final ObjectNode result = mapper.getMapper().createObjectNode(); addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_RESULT_NONCE, nonce, true); return result; } /** * Create Generic Request Container. * * @param reqId RequestId * @param transactionId TransactionId * @param payLoad unsigned payload * @param signedPayload Signed payload * @return JSON * @throws SlCommandoBuildException In case of an error */ public static ObjectNode createGenericRequest(final String reqId, final String transactionId, final ObjectNode payLoad, final String signedPayload) throws SlCommandoBuildException { final ObjectNode req = mapper.getMapper().createObjectNode(); addSingleIntegerElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true); addSingleStringElement(req, SL20Constants.SL20_REQID, reqId, true); addSingleStringElement(req, SL20Constants.SL20_TRANSACTIONID, transactionId, false); addOnlyOnceOfTwo(req, SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD, payLoad, signedPayload); return req; } /** * Create Generic Response Container. * * @param respId Response Id * @param inResponseTo RequestId to this response * @param transactionId transactionId * @param payLoad Unsigned payload * @param signedPayload Signed payload * @return JSON * @throws SlCommandoBuildException In case of an error */ public static final ObjectNode createGenericResponse(final String respId, final String inResponseTo, final String transactionId, final ObjectNode payLoad, final String signedPayload) throws SlCommandoBuildException { final ObjectNode req = mapper.getMapper().createObjectNode(); addSingleIntegerElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true); addSingleStringElement(req, SL20Constants.SL20_RESPID, respId, true); addSingleStringElement(req, SL20Constants.SL20_INRESPTO, inResponseTo, false); addSingleStringElement(req, SL20Constants.SL20_TRANSACTIONID, transactionId, false); addOnlyOnceOfTwo(req, SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD, payLoad, signedPayload); return req; } private static void addOnlyOnceOfTwo(final ObjectNode parent, final String firstKeyId, final String secondKeyId, final ObjectNode first, final ObjectNode second) throws SlCommandoBuildException { if (first == null && second == null) { throw new SlCommandoBuildException(firstKeyId + " and " + secondKeyId + " is NULL"); } else if (first != null && second != null) { throw new SlCommandoBuildException(firstKeyId + " and " + secondKeyId + " can not SET TWICE"); } else if (first != null) { parent.set(firstKeyId, first); } else if (second != null) { parent.set(secondKeyId, second); } else { throw new SlCommandoBuildException("Internal build error"); } } /** * Add one element of two possible elements
* This method adds either the first element or the second element to parent * JSON, but never both. * * @param parent Parent JSON element * @param firstKeyId first element Id * @param secondKeyId second element Id * @param first first element * @param second second element * @throws SlCommandoBuildException In case of an error. */ public static void addOnlyOnceOfTwo(final ObjectNode parent, final String firstKeyId, final String secondKeyId, final ObjectNode first, final String second) throws SlCommandoBuildException { if (first == null && (second == null || second.isEmpty())) { throw new SlCommandoBuildException(firstKeyId + " and " + secondKeyId + " is NULL"); } else if (first != null && second != null) { throw new SlCommandoBuildException(firstKeyId + " and " + secondKeyId + " can not SET TWICE"); } else if (first != null) { parent.set(firstKeyId, first); } else if (second != null && !second.isEmpty()) { parent.put(secondKeyId, second); } else { throw new SlCommandoBuildException("Internal build error"); } } // TODO!!!! private static ObjectNode createJsonSignedHeader() throws SlCommandoBuildException { final ObjectNode header = mapper.getMapper().createObjectNode(); addSingleStringElement(header, SL20Constants.JSON_ALGORITHM, SL20Constants.JSON_ALGORITHM_SIGNING_RS256, true); addSingleStringElement(header, SL20Constants.JSON_CONTENTTYPE, SL20Constants.SL20_CONTENTTYPE_SIGNED_COMMAND, true); addArrayOfStrings(header, SL20Constants.JSON_X509_CERTIFICATE, Arrays.asList(Constants.DUMMY_SIGNING_CERT)); return header; } // TODO!!!! private static ObjectNode createJsonEncryptionHeader() throws SlCommandoBuildException { final ObjectNode header = mapper.getMapper().createObjectNode(); addSingleStringElement(header, SL20Constants.JSON_ALGORITHM, SL20Constants.JSON_ALGORITHM_ENC_KEY_RSAOAEP, true); addSingleStringElement(header, SL20Constants.JSON_ENCRYPTION_PAYLOAD, SL20Constants.JSON_ALGORITHM_ENC_PAYLOAD_A128CBCHS256, true); addSingleStringElement(header, SL20Constants.JSON_CONTENTTYPE, SL20Constants.SL20_CONTENTTYPE_ENCRYPTED_RESULT, true); addSingleStringElement(header, SL20Constants.JSON_X509_FINGERPRINT, Constants.DUMMY_SIGNING_CERT_FINGERPRINT, true); return header; } // TODO!!!! private static String createJsonSignedFooter() { return "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7\n" + " AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4\n" + " BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K\n" + " 0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv\n" + " hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB\n" + " p0igcN_IoypGlUPQGe77Rw"; } private static void addArrayOfStrings(final ObjectNode parent, final String keyId, final List values) throws SlCommandoBuildException { validateParentAndKey(parent, keyId); if (values != null) { final ArrayNode callReqParamsArray = mapper.getMapper().createArrayNode(); parent.set(keyId, callReqParamsArray); for (final String el : values) { callReqParamsArray.add(el); } } } private static void addArrayOfStringElements(final ObjectNode parent, final String keyId, final Map keyValuePairs) throws SlCommandoBuildException { validateParentAndKey(parent, keyId); if (keyValuePairs != null) { final ArrayNode callReqParamsArray = mapper.getMapper().createArrayNode(); parent.set(keyId, callReqParamsArray); for (final Entry el : keyValuePairs.entrySet()) { final ObjectNode callReqParams = mapper.getMapper().createObjectNode(); callReqParams.put(el.getKey(), el.getValue()); callReqParamsArray.add(callReqParams); } } } private static void addSingleCertificateElement(final ObjectNode parent, final String keyId, final X509Certificate cert, final boolean isRequired) throws CertificateEncodingException, SlCommandoBuildException { if (cert != null) { addSingleByteElement(parent, keyId, cert.getEncoded(), isRequired); } else if (isRequired) { throw new SlCommandoBuildException(keyId + " is marked as REQUIRED"); } } private static void addSingleByteElement(final ObjectNode parent, final String keyId, final byte[] value, final boolean isRequired) throws SlCommandoBuildException { validateParentAndKey(parent, keyId); if (isRequired && value == null) { throw new SlCommandoBuildException(keyId + " has NULL value"); } else if (value != null) { parent.put(keyId, Base64.getEncoder().encodeToString(value)); } } private static void addSingleBooleanElement(final ObjectNode parent, final String keyId, final Boolean value, final boolean isRequired) throws SlCommandoBuildException { validateParentAndKey(parent, keyId); if (isRequired && value == null) { throw new SlCommandoBuildException(keyId + " has a NULL value"); } else if (value != null) { parent.put(keyId, value); } } private static void addSingleNumberElement(final ObjectNode parent, final String keyId, final Integer value, final boolean isRequired) throws SlCommandoBuildException { validateParentAndKey(parent, keyId); if (isRequired && value == null) { throw new SlCommandoBuildException(keyId + " has a NULL value"); } else if (value != null) { parent.put(keyId, value); } } private static void addSingleStringElement(final ObjectNode parent, final String keyId, final String value, final boolean isRequired) throws SlCommandoBuildException { validateParentAndKey(parent, keyId); if (isRequired && (value == null || value.isEmpty())) { throw new SlCommandoBuildException(keyId + " has an empty value"); } else if (value != null && !value.isEmpty()) { parent.put(keyId, value); } } private static void addSingleIntegerElement(final ObjectNode parent, final String keyId, final Integer value, final boolean isRequired) throws SlCommandoBuildException { validateParentAndKey(parent, keyId); if (isRequired && value == null) { throw new SlCommandoBuildException(keyId + " has an empty value"); } else if (value != null) { parent.put(keyId, value); } } private static void addSingleJsonElement(final ObjectNode parent, final String keyId, final ObjectNode element, final boolean isRequired) throws SlCommandoBuildException { validateParentAndKey(parent, keyId); if (isRequired && element == null) { throw new SlCommandoBuildException("No commando name included"); } else if (element != null) { parent.set(keyId, element); } } private static void validateParentAndKey(final ObjectNode parent, final String keyId) throws SlCommandoBuildException { if (parent == null) { throw new SlCommandoBuildException("NO parent JSON element"); } if (keyId == null || keyId.isEmpty()) { throw new SlCommandoBuildException("NO JSON element identifier"); } } }