From fd692be28186154ec5d217dfa35dbae45e5e0166 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Thu, 25 Aug 2022 14:59:03 +0200 Subject: feat(eidas): add support for new IDA AuthBlock format The ID Austria system changes the format of technical AuthBlock with Frontend/Backend interface-specification v1.1.0 --- .../eidas/v2/service/AuthBlockSigningService.java | 210 +++++++++++++-------- 1 file changed, 130 insertions(+), 80 deletions(-) (limited to 'modules/authmodule-eIDAS-v2/src/main') diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java index 098e76ce..1998fa85 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java @@ -1,5 +1,6 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2.service; +import java.io.Serializable; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; @@ -44,7 +45,7 @@ import lombok.extern.slf4j.Slf4j; /** * Service to build and sign AuthBlock's for E-ID system. - * + * * @author tlenz * */ @@ -55,157 +56,206 @@ public class AuthBlockSigningService { private static final String KEYSTORE_FRIENDLYNAME = "AuthBlock_Signing"; private static ObjectMapper mapper = new ObjectMapper(); - + @Autowired IConfiguration basicConfig; - + @Autowired EaafKeyStoreFactory keyStoreFactory; - private Pair keyStore; - + /** - * Build and sign an AuthBlock for E-ID system. - * + * Build and sign an AuthBlock for E-ID system. + * * @param pendingReq data that should be added into AuthBlock * @return serialized JWS - * @throws JsonProcessingException In case of a AuthBlock generation error - * @throws JoseException In case of a JWS signing error - * @throws EaafException In case of a KeyStore or Key error + * @throws JsonProcessingException In case of a AuthBlock generation error + * @throws JoseException In case of a JWS signing error + * @throws EaafException In case of a KeyStore or Key error */ - public String buildSignedAuthBlock(IRequest pendingReq) + public String buildSignedAuthBlock(IRequest pendingReq) throws JsonProcessingException, EaafException, JoseException { - - //TODO: set Challenge to SAML2 requestId to create link between authentication request and authBlock - + + // TODO: set Challenge to SAML2 requestId to create link between authentication + // request and authBlock + // build AuthBlock - EidasAuchBlock authBlock = new EidasAuchBlock(); - authBlock.setChallenge(UUID.randomUUID().toString()); - authBlock.setTimestamp(LocalDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)); - authBlock.setUniqueId(pendingReq.getRawData(MsEidasNodeConstants.DATA_REQUESTERID, String.class)); - authBlock.setPiiTransactionId(pendingReq.getUniquePiiTransactionIdentifier()); - - //set Binding PublicKey if available - Object bindingPubKey = pendingReq.getRawData(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME); - if (bindingPubKey instanceof String) { - authBlock.setBindingPublicKey((String) bindingPubKey); - - } - - String jwsPayload = mapper.writeValueAsString(authBlock); + final String jwsPayload = mapper.writeValueAsString(buildAuthBlock(pendingReq)); log.debug("Building and sign authBlock with data: {}", jwsPayload); - - //sign JWS - return JoseUtils - .createSignature(keyStore, getKeyAlias(), getKeyPassword(), jwsPayload, false, - KEYSTORE_FRIENDLYNAME); + + // sign JWS + return JoseUtils.createSignature( + keyStore, getKeyAlias(), getKeyPassword(), jwsPayload, false, KEYSTORE_FRIENDLYNAME); + + } + + private Serializable buildAuthBlock(IRequest pendingReq) { + if (basicConfig.getBasicConfigurationBoolean( + MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_LEGACY_USE, false)) { + final EidasAuchBlockV1 authBlock = new EidasAuchBlockV1(); + authBlock.setChallenge(UUID.randomUUID().toString()); + authBlock.setTimestamp(LocalDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)); + authBlock.setUniqueId(pendingReq.getRawData(MsEidasNodeConstants.DATA_REQUESTERID, String.class)); + authBlock.setPiiTransactionId(pendingReq.getUniquePiiTransactionIdentifier()); + + // set Binding PublicKey if available + final Object bindingPubKey = pendingReq.getRawData(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME); + if (bindingPubKey instanceof String) { + authBlock.setBindingPublicKey((String) bindingPubKey); + + } + return authBlock; + + } else { + final EidasAuchBlockV2 authBlock = new EidasAuchBlockV2(); + authBlock.setChallenge(UUID.randomUUID().toString()); + authBlock.setTimestamp(LocalDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)); + + // set Binding PublicKey if available + final Object bindingPubKey = pendingReq.getRawData(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME); + if (bindingPubKey instanceof String) { + authBlock.setBindingPublicKey((String) bindingPubKey); + + } + return authBlock; + + } } - /** * Get the Base64 encoded PublicKey that is used to sign the AuthBlock. - * + * * @return Base64 encoded PublicKey * @throws EaafKeyAccessException In case of an unknown or invalid key */ - public String getBase64EncodedPublicKey() throws EaafKeyAccessException { - Pair keyPair = EaafKeyStoreUtils.getPrivateKeyAndCertificates( - keyStore.getFirst(), getKeyAlias(), getKeyPassword(), true, KEYSTORE_FRIENDLYNAME); + public String getBase64EncodedPublicKey() throws EaafKeyAccessException { + final Pair keyPair = EaafKeyStoreUtils.getPrivateKeyAndCertificates( + keyStore.getFirst(), getKeyAlias(), getKeyPassword(), true, KEYSTORE_FRIENDLYNAME); return Base64.getEncoder().encodeToString(keyPair.getSecond()[0].getPublicKey().getEncoded()); - + } @PostConstruct - private void initialize() throws KeyStoreException, EaafException { + private void initialize() throws KeyStoreException, EaafException { log.debug("Initializing AuthBlock signing service ... "); - // read Connector wide config data TODO connector wide! - String keyStoreName = basicConfig + // read Connector wide config data TODO connector wide! + final String keyStoreName = basicConfig .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_NAME); - String keyStorePw = basicConfig + final String keyStorePw = basicConfig .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PASSWORD); - String keyStorePath = basicConfig + final String keyStorePath = basicConfig .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PATH); - String keyStoreType = basicConfig + final String keyStoreType = basicConfig .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_TYPE); - - //build new KeyStore configuration - KeyStoreConfiguration keyStoreConfiguration = new KeyStoreConfiguration(); + // build new KeyStore configuration + final KeyStoreConfiguration keyStoreConfiguration = new KeyStoreConfiguration(); keyStoreConfiguration.setFriendlyName(KEYSTORE_FRIENDLYNAME); - + keyStoreConfiguration.setSoftKeyStoreFilePath(keyStorePath); keyStoreConfiguration.setSoftKeyStorePassword(keyStorePw); - keyStoreConfiguration.setKeyStoreType(KeyStoreConfiguration.KeyStoreType.fromString(keyStoreType)); + keyStoreConfiguration.setKeyStoreType(KeyStoreConfiguration.KeyStoreType.fromString(keyStoreType)); keyStoreConfiguration.setKeyStoreName(keyStoreName); - - //validate KeyStore configuration + + // validate KeyStore configuration keyStoreConfiguration.validate(); - - //validate key alias + + // validate key alias if (StringUtils.isEmpty(getKeyAlias())) { - throw new EaafConfigurationException("config.08", - new Object[] {MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_ALIAS}); - + throw new EaafConfigurationException("config.08", + new Object[] { MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_ALIAS }); + } - - //build new KeyStore based on configuration - keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfiguration); - - //check if Key is accessible + + // build new KeyStore based on configuration + keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfiguration); + + // check if Key is accessible EaafKeyStoreUtils.getPrivateKeyAndCertificates( keyStore.getFirst(), getKeyAlias(), getKeyPassword(), true, KEYSTORE_FRIENDLYNAME); - - log.info("AuthBlock signing-service successful initialized"); - - } - + + log.info("AuthBlock signing-service successful initialized {}", + basicConfig.getBasicConfigurationBoolean(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_LEGACY_USE, false) + ? " in legacy mode" + : ""); + + } + private char[] getKeyPassword() { - final String value = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_PASSWORD); + final String value = basicConfig.getBasicConfiguration( + MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_PASSWORD); if (value != null) { return value.trim().toCharArray(); } return null; - - } + } private String getKeyAlias() { return basicConfig .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_ALIAS); - + } - + /** * Technical AuthBlock for eIDAS Authentication. - * + * * @author tlenz * */ @Data @JsonInclude(JsonInclude.Include.NON_NULL) - private static class EidasAuchBlock { + @Deprecated + private static class EidasAuchBlockV1 implements Serializable { + + private static final long serialVersionUID = 8437172632081476257L; @JsonProperty("challenge") private String challenge; - + @JsonProperty("timestamp") @JsonSerialize(using = LocalDateTimeSerializer.class) @JsonDeserialize(using = LocalDateTimeDeserializer.class) @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC") private LocalDateTime timestamp; - + @JsonProperty("appId") private String uniqueId; - + @JsonProperty("piiTransactionId") private String piiTransactionId; - + + @JsonProperty("bindingPublicKey") + private String bindingPublicKey; + + } + + /** + * AuthBlock for Binding Authentication. + * + * @author tlenz + * + */ + @Data + @JsonInclude(JsonInclude.Include.NON_NULL) + public class EidasAuchBlockV2 implements Serializable { + + private static final long serialVersionUID = -2013435642666124497L; + + @JsonProperty("challenge") + private String challenge; + + @JsonProperty("issuedAt") + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC") + private LocalDateTime timestamp; + @JsonProperty("bindingPublicKey") private String bindingPublicKey; - + } - } -- cgit v1.2.3