diff options
Diffstat (limited to 'eaaf_modules/eaaf_module_auth_sl20')
28 files changed, 2978 insertions, 2729 deletions
diff --git a/eaaf_modules/eaaf_module_auth_sl20/pom.xml b/eaaf_modules/eaaf_module_auth_sl20/pom.xml index d3c141d3..81611aff 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/pom.xml +++ b/eaaf_modules/eaaf_module_auth_sl20/pom.xml @@ -1,14 +1,17 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>at.gv.egiz.eaaf</groupId> <artifactId>eaaf_modules</artifactId> - <version>1.0.13.2</version> + <version>1.1.0</version> </parent> <artifactId>eaaf_module_auth_sl20</artifactId> <name>Generic SL2.0 authentication</name> - - <licenses> + + <licenses> <license> <name>European Union Public License, version 1.2 (EUPL-1.2)</name> <url>https://opensource.org/licenses/EUPL-1.2</url> @@ -24,37 +27,37 @@ <organizationUrl>https://www.egiz.gv.at</organizationUrl> </developer> </developers> - + <dependencies> - <dependency> - <groupId>at.gv.egiz.eaaf</groupId> - <artifactId>eaaf-core</artifactId> - <version>${egiz.eaaf.version}</version> - </dependency> - <dependency> - <groupId>org.bitbucket.b_c</groupId> - <artifactId>jose4j</artifactId> - </dependency> - <dependency> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-databind</artifactId> - </dependency> - - <dependency> - <groupId>javax.servlet</groupId> - <artifactId>javax.servlet-api</artifactId> - <scope>provided</scope> - </dependency> + <dependency> + <groupId>at.gv.egiz.eaaf</groupId> + <artifactId>eaaf-core</artifactId> + <version>${egiz.eaaf.version}</version> + </dependency> + <dependency> + <groupId>org.bitbucket.b_c</groupId> + <artifactId>jose4j</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <scope>provided</scope> + </dependency> </dependencies> - + <build> - <resources> - <resource> - <directory>src/main/resources</directory> - </resource> - </resources> - - <plugins> + <resources> + <resource> + <directory>src/main/resources</directory> + </resource> + </resources> + + <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> @@ -70,13 +73,13 @@ <artifactId>maven-jar-plugin</artifactId> <version>3.1.1</version> <configuration> - <archive> - <manifest> - <addClasspath>true</addClasspath> - <addDefaultImplementationEntries>true</addDefaultImplementationEntries> - <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> - </manifest> - </archive> + <archive> + <manifest> + <addClasspath>true</addClasspath> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> + </manifest> + </archive> </configuration> </plugin> @@ -92,23 +95,23 @@ </filesets> </configuration> </plugin> - + <!-- enable co-existence of testng and junit --> - <plugin> - <artifactId>maven-surefire-plugin</artifactId> - <version>${surefire.version}</version> - <configuration> - <threadCount>1</threadCount> - </configuration> - <dependencies> - <dependency> - <groupId>org.apache.maven.surefire</groupId> - <artifactId>surefire-junit47</artifactId> - <version>${surefire.version}</version> - </dependency> - </dependencies> - </plugin> - </plugins> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>${surefire.version}</version> + <configuration> + <threadCount>1</threadCount> + </configuration> + <dependencies> + <dependency> + <groupId>org.apache.maven.surefire</groupId> + <artifactId>surefire-junit47</artifactId> + <version>${surefire.version}</version> + </dependency> + </dependencies> + </plugin> + </plugins> </build> - + </project>
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/AbstractSL20AuthenticationModulImpl.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/AbstractSL20AuthenticationModulImpl.java index 7e306f25..e9932ae8 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/AbstractSL20AuthenticationModulImpl.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/AbstractSL20AuthenticationModulImpl.java @@ -12,119 +12,130 @@ import org.springframework.beans.factory.annotation.Autowired; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.api.idp.auth.modules.AuthModule; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.impl.idp.auth.AbstractAuthenticationManager; import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants; - /** + * AuthModule to select a Securtiy-Layer 2.0 based authentication process. + * * @author tlenz * */ -public abstract class AbstractSL20AuthenticationModulImpl implements AuthModule { - private static final Logger log = LoggerFactory.getLogger(AbstractSL20AuthenticationModulImpl.class); - - private int priority = 3; - public static final List<String> VDA_TYPE_IDS = Arrays.asList("1", "2", "3", "4"); - - @Autowired(required=true) protected IConfiguration authConfig; - @Autowired(required=true) private AbstractAuthenticationManager authManager; - - @Override - public int getPriority() { - return priority; - } - - /** - * Sets the priority of this module. Default value is {@code 0}. - * @param priority The priority. - */ - public void setPriority(int priority) { - this.priority = priority; - } - - @PostConstruct - protected void initalSL20Authentication() { - //parameter to whiteList - authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE); - authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE); - - } - - - /* (non-Javadoc) - * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#selectProcess(at.gv.egovernment.moa.id.process.api.ExecutionContext) - */ - @Override - public String selectProcess(ExecutionContext context, IRequest pendingReq) { - final ISPConfiguration spConfig = pendingReq.getServiceProviderConfiguration(); - - if (spConfig == null) { - log.error("Suspect state. NO SP CONFIGURATION IN CONTEXT!"); - throw new RuntimeException("Suspect state. NO SP CONFIGURATION IN CONTEXT!"); - - } - - final String sl20ClientTypeHeader = (String) context.get(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE.toLowerCase()); - final String sl20VDATypeHeader = (String) context.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase()); - - if (authConfig.getBasicConfigurationBoolean(getGeneralConfigPropertyNameEnableModule(), getGeneralConfigPropertyNameEnableModuleDefault())) { - if (spConfig != null && - StringUtils.isNotEmpty(spConfig.getConfigurationValue(getSPConfigPropertyNameEnableModule())) && - Boolean.valueOf(spConfig.getConfigurationValue(getSPConfigPropertyNameEnableModule()))) { - log.debug("SL2.0 is enabled for " + spConfig.getUniqueIdentifier()); - log.trace(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + ": " + sl20ClientTypeHeader); - log.trace(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE + ": " + sl20VDATypeHeader); - return getProcessName(); - - } else { - log.trace("SL2.0 is NOT enabled for " + spConfig.getUniqueIdentifier()); - return null; - - } - - } else { - log.trace("SL2.0 is NOT enabled with property: {}", getGeneralConfigPropertyNameEnableModule()); - return null; - - } - - } - - /** - * Get the general configuration-key that holds the enabled key for this authentication module - * - * @return - */ - public abstract String getGeneralConfigPropertyNameEnableModule(); - - /** - * Get the default value of the general configuration-key that holds the enabled key for this authentication module - * - * @return - */ - public abstract boolean getGeneralConfigPropertyNameEnableModuleDefault(); - - /** - * Get the SP specific configuration-key that holds the enabled key for this authentication module - * - * @return configuration key for SP configuration - */ - public abstract String getSPConfigPropertyNameEnableModule(); - - /** - * Get the name of this specific SL2.0 process - * - * @return - */ - public abstract String getProcessName(); - - /* (non-Javadoc) - * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#getProcessDefinitions() - */ - @Override - public abstract String[] getProcessDefinitions(); +public abstract class AbstractSL20AuthenticationModulImpl implements AuthModule { + private static final Logger log = LoggerFactory.getLogger(AbstractSL20AuthenticationModulImpl.class); + + private int priority = 3; + public static final List<String> VDA_TYPE_IDS = Arrays.asList("1", "2", "3", "4"); + + @Autowired(required = true) + protected IConfiguration authConfig; + @Autowired(required = true) + private AbstractAuthenticationManager authManager; + + @Override + public int getPriority() { + return priority; + } + + /** + * Sets the priority of this module. Default value is {@code 0}. + * + * @param priority The priority. + */ + public void setPriority(final int priority) { + this.priority = priority; + } + + @PostConstruct + protected void initalSL20Authentication() { + // parameter to whiteList + authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE); + authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE); + + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#selectProcess(at.gv. + * egovernment.moa.id.process .api.ExecutionContext) + */ + @Override + public String selectProcess(final ExecutionContext context, final IRequest pendingReq) { + final ISpConfiguration spConfig = pendingReq.getServiceProviderConfiguration(); + + if (spConfig == null) { + log.error("Suspect state. NO SP CONFIGURATION IN CONTEXT!"); + throw new RuntimeException("Suspect state. NO SP CONFIGURATION IN CONTEXT!"); + + } + + final String sl20ClientTypeHeader = (String) context.get(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE.toLowerCase()); + final String sl20VdaTypeHeader = (String) context.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase()); + + if (authConfig.getBasicConfigurationBoolean(getGeneralConfigPropertyNameEnableModule(), + getGeneralConfigPropertyNameEnableModuleDefault())) { + if (StringUtils.isNotEmpty(spConfig.getConfigurationValue(getSpConfigPropertyNameEnableModule())) + && Boolean.valueOf(spConfig.getConfigurationValue(getSpConfigPropertyNameEnableModule()))) { + log.debug("SL2.0 is enabled for " + spConfig.getUniqueIdentifier()); + log.trace(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + ": " + sl20ClientTypeHeader); + log.trace(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE + ": " + sl20VdaTypeHeader); + return getProcessName(); + + } else { + log.trace("SL2.0 is NOT enabled for " + spConfig.getUniqueIdentifier()); + return null; + + } + + } else { + log.trace("SL2.0 is NOT enabled with property: {}", getGeneralConfigPropertyNameEnableModule()); + return null; + + } + + } + + /** + * Get the general configuration-key that holds the enabled key for this + * authentication module. + * + * @return + */ + public abstract String getGeneralConfigPropertyNameEnableModule(); + + /** + * Get the default value of the general configuration-key that holds the enabled + * key for this authentication module. + * + * @return + */ + public abstract boolean getGeneralConfigPropertyNameEnableModuleDefault(); + + /** + * Get the SP specific configuration-key that holds the enabled key for this + * authentication module. + * + * @return configuration key for SP configuration + */ + public abstract String getSpConfigPropertyNameEnableModule(); + + /** + * Get the name of this specific SL2.0 process. + * + * @return + */ + public abstract String getProcessName(); + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#getProcessDefinitions() + */ + @Override + public abstract String[] getProcessDefinitions(); } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java index a1490d2b..11fd41fb 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java @@ -1,58 +1,87 @@ package at.gv.egiz.eaaf.modules.auth.sl20; public class Constants { - - public static final String CONFIG_PROP_PREFIX = "modules.sl20"; - public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID = CONFIG_PROP_PREFIX + ".vda.urls.qualeID."; - - public static final String CONFIG_PROP_VDA_AUTHBLOCK_TRANSFORMATION_ID = CONFIG_PROP_PREFIX + ".vda.authblock.transformation.id"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_PATH = CONFIG_PROP_PREFIX + ".security.keystore.path"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD = CONFIG_PROP_PREFIX + ".security.keystore.password"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS = CONFIG_PROP_PREFIX + ".security.sign.alias"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD = CONFIG_PROP_PREFIX + ".security.sign.password"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS = CONFIG_PROP_PREFIX + ".security.encryption.alias";; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD = CONFIG_PROP_PREFIX + ".security.encryption.password"; - - public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT = "default"; - public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT = CONFIG_PROP_VDA_ENDPOINT_QUALeID + CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT; - public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST = CONFIG_PROP_VDA_ENDPOINT_QUALeID + "list"; - public static final String CONFIG_PROP_SP_LIST = CONFIG_PROP_PREFIX + ".sp.entityIds."; - - public static final String CONFIG_PROP_DISABLE_EID_VALIDATION = CONFIG_PROP_PREFIX + ".security.eID.validation.disable"; - public static final String CONFIG_PROP_ENABLE_EID_ENCRYPTION = CONFIG_PROP_PREFIX + ".security.eID.encryption.enabled"; - public static final String CONFIG_PROP_FORCE_EID_ENCRYPTION = CONFIG_PROP_PREFIX + ".security.eID.encryption.required"; - public static final String CONFIG_PROP_FORCE_EID_SIGNED_RESULT = CONFIG_PROP_PREFIX + ".security.eID.signed.result.required"; - - public static final String CONFIG_PROP_IPC_RETURN_URL = CONFIG_PROP_PREFIX + ".testing.ipc.return.url"; - public static final String CONFIG_PROP_HTTP_REDIRECT_CODE = CONFIG_PROP_PREFIX + ".testing.redirect.http.code"; - public static final String CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE = "303"; - - public static final String CONFIG_PROP_SP_ENABLE_SL20_AUTHENTICATION = "auth.sl20.enabled"; - public static final String CONFIG_PROP_SP_SL20_ENDPOINT_LIST = "auth.sl20.endpoints"; - - public static final String PENDING_REQ_STORAGE_PREFIX = "SL20_AUTH_"; - - /** - * Only dummy data for development!!!!!! - */ - public static final String DUMMY_SIGNING_CERT = - "MIIC9zCCAd8CBFretWcwDQYJKoZIhvcNAQEOBQAwQDELMAkGA1UEBhMCQVQxDTAL\n" + - "BgNVBAoMBEVHSVoxIjAgBgNVBAMMGW93biBkdW1teSBtZXRhZGF0YSBzaWduZXIw\n" + - "HhcNMTgwNDI0MDQ0MTExWhcNMjEwMTE3MDQ0MTExWjBAMQswCQYDVQQGEwJBVDEN\n" + - "MAsGA1UECgwERUdJWjEiMCAGA1UEAwwZb3duIGR1bW15IG1ldGFkYXRhIHNpZ25l\n" + - "cjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJvN3l1pjzlnmoW5trHH\n" + - "Rb1s60QtGNp2v1nfMg1R6h7SzygtmO869v5bqrVBBVGmujslr7W8cZ2DLmJoQx1N\n" + - "WwhccjXTHpNPw0B70qHGch2uRNkqkizSOlwth0Ll2DJtzxTolbajYdg+xppXScUq\n" + - "WNlNZndauPSnB2CESgNkaUou4x4YVSDInugAtLvdLx8rf2YcuidI6UIXxeSZr3VO\n" + - "Z12YtddzcJ+lwh7OX8B0UvLsdYjKjefjEudyuNBmVwLv4K2LsFhSqgE1CAzk3oCb\n" + - "V2A84klaWVPiXoBiOucyouvX781WVp1aCBp0QA8gpJH7/2wRsdPQ90tjMzM7dcgY\n" + - "LDkCAwEAATANBgkqhkiG9w0BAQ4FAAOCAQEAQuYRQcCNLDYU1ItliYz9f28+KDyU\n" + - "8WjF3NDZrlJbGSKQ4n7wkBfxdK3zprmpHadWDB+aZaPt/+voE2FduzPiLUDlpazN\n" + - "60JJ5/YHZ3q9MZvdoNg6rjkpioWatoj/smUkT6oUWL/gp8tH12fOd2oJygBqXMve\n" + - "3y3qVCghnjRaMYuXcScTZcjH9yebkTLygirtw34oGVb7t+HwbtcN65fUIBly6Rcl\n" + - "8NV3pwOKhXFKDAqXUpvhebL4+tWOqPdqfIfGaE6rELfTf3icGY3CQCzDz5Gp0Ptc\n" + - "TfQqm64xnhtAruXNJXWg2ptg+GuQgWnJUgQ8wLNMxw9XdeEwlQo5dL6xmg=="; - - public static final String DUMMY_SIGNING_CERT_FINGERPRINT = "IwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJvN3l1pjzlnmoW"; + + public static final String CONFIG_PROP_PREFIX = "modules.sl20"; + public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID = CONFIG_PROP_PREFIX + ".vda.urls.qualeID."; + + public static final String CONFIG_PROP_VDA_AUTHBLOCK_TRANSFORMATION_ID = CONFIG_PROP_PREFIX + + ".vda.authblock.transformation.id"; + + //KeyStore configuration + public static final String CONFIG_PROP_SECURITY_KEYSTORE_TYPE = + CONFIG_PROP_PREFIX + ".security.keystore.type"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_NAME = + CONFIG_PROP_PREFIX + ".security.keystore.name"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_PATH = + CONFIG_PROP_PREFIX + ".security.keystore.path"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD = + CONFIG_PROP_PREFIX + ".security.keystore.password"; + + public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS = + CONFIG_PROP_PREFIX + ".security.sign.alias"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD = + CONFIG_PROP_PREFIX + ".security.sign.password"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS = + CONFIG_PROP_PREFIX + ".security.encryption.alias"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD = + CONFIG_PROP_PREFIX + ".security.encryption.password"; + + //TrustStore configuration + public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE = + CONFIG_PROP_PREFIX + ".security.truststore.type"; + public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_NAME = + CONFIG_PROP_PREFIX + ".security.truststore.name"; + public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PATH = + CONFIG_PROP_PREFIX + ".security.truststore.path"; + public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PASSWORD = + CONFIG_PROP_PREFIX + ".security.truststore.password"; + + + public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT = "default"; + public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT = CONFIG_PROP_VDA_ENDPOINT_QUALeID + + CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT; + public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST = CONFIG_PROP_VDA_ENDPOINT_QUALeID + "list"; + public static final String CONFIG_PROP_SP_LIST = CONFIG_PROP_PREFIX + ".sp.entityIds."; + + public static final String CONFIG_PROP_DISABLE_EID_VALIDATION = CONFIG_PROP_PREFIX + + ".security.eID.validation.disable"; + public static final String CONFIG_PROP_ENABLE_EID_ENCRYPTION = CONFIG_PROP_PREFIX + + ".security.eID.encryption.enabled"; + public static final String CONFIG_PROP_FORCE_EID_ENCRYPTION = CONFIG_PROP_PREFIX + + ".security.eID.encryption.required"; + public static final String CONFIG_PROP_FORCE_EID_SIGNED_RESULT = CONFIG_PROP_PREFIX + + ".security.eID.signed.result.required"; + + public static final String CONFIG_PROP_IPC_RETURN_URL = CONFIG_PROP_PREFIX + ".testing.ipc.return.url"; + public static final String CONFIG_PROP_HTTP_REDIRECT_CODE = CONFIG_PROP_PREFIX + ".testing.redirect.http.code"; + public static final String CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE = "303"; + + public static final String CONFIG_PROP_SP_ENABLE_SL20_AUTHENTICATION = "auth.sl20.enabled"; + public static final String CONFIG_PROP_SP_SL20_ENDPOINT_LIST = "auth.sl20.endpoints"; + + public static final String PENDING_REQ_STORAGE_PREFIX = "SL20_AUTH_"; + + /** + * Only dummy data for development!!!!!!. + */ + public static final String DUMMY_SIGNING_CERT = "MIIC9zCCAd8CBFretWcwDQYJKoZIhvcNAQEOBQAwQDELMAkGA1UEBhMCQVQxDTAL\n" + + "BgNVBAoMBEVHSVoxIjAgBgNVBAMMGW93biBkdW1teSBtZXRhZGF0YSBzaWduZXIw\n" + + "HhcNMTgwNDI0MDQ0MTExWhcNMjEwMTE3MDQ0MTExWjBAMQswCQYDVQQGEwJBVDEN\n" + + "MAsGA1UECgwERUdJWjEiMCAGA1UEAwwZb3duIGR1bW15IG1ldGFkYXRhIHNpZ25l\n" + + "cjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJvN3l1pjzlnmoW5trHH\n" + + "Rb1s60QtGNp2v1nfMg1R6h7SzygtmO869v5bqrVBBVGmujslr7W8cZ2DLmJoQx1N\n" + + "WwhccjXTHpNPw0B70qHGch2uRNkqkizSOlwth0Ll2DJtzxTolbajYdg+xppXScUq\n" + + "WNlNZndauPSnB2CESgNkaUou4x4YVSDInugAtLvdLx8rf2YcuidI6UIXxeSZr3VO\n" + + "Z12YtddzcJ+lwh7OX8B0UvLsdYjKjefjEudyuNBmVwLv4K2LsFhSqgE1CAzk3oCb\n" + + "V2A84klaWVPiXoBiOucyouvX781WVp1aCBp0QA8gpJH7/2wRsdPQ90tjMzM7dcgY\n" + + "LDkCAwEAATANBgkqhkiG9w0BAQ4FAAOCAQEAQuYRQcCNLDYU1ItliYz9f28+KDyU\n" + + "8WjF3NDZrlJbGSKQ4n7wkBfxdK3zprmpHadWDB+aZaPt/+voE2FduzPiLUDlpazN\n" + + "60JJ5/YHZ3q9MZvdoNg6rjkpioWatoj/smUkT6oUWL/gp8tH12fOd2oJygBqXMve\n" + + "3y3qVCghnjRaMYuXcScTZcjH9yebkTLygirtw34oGVb7t+HwbtcN65fUIBly6Rcl\n" + + "8NV3pwOKhXFKDAqXUpvhebL4+tWOqPdqfIfGaE6rELfTf3icGY3CQCzDz5Gp0Ptc\n" + + "TfQqm64xnhtAruXNJXWg2ptg+GuQgWnJUgQ8wLNMxw9XdeEwlQo5dL6xmg=="; + + public static final String DUMMY_SIGNING_CERT_FINGERPRINT = "IwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJvN3l1pjzlnmoW"; } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/EventCodes.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/EventCodes.java index e19ef5fc..af155206 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/EventCodes.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/EventCodes.java @@ -1,16 +1,16 @@ package at.gv.egiz.eaaf.modules.auth.sl20; /** - * Set of event codes uses in Auth-Handler implementation - * + * Set of event codes uses in Auth-Handler implementation. + * * @author tlenz * */ public class EventCodes { - public static final int AUTHPROCESS_SL20_SELECTED = 4111; - public static final int AUTHPROCESS_SL20_ENDPOINT_URL = 4112; - public static final int AUTHPROCESS_SL20_DATAURL_IP = 4113; - - public static final int AUTHPROCESS_SL20_CONSENT_VALID = 4113; + public static final int AUTHPROCESS_SL20_SELECTED = 4111; + public static final int AUTHPROCESS_SL20_ENDPOINT_URL = 4112; + public static final int AUTHPROCESS_SL20_DATAURL_IP = 4113; + + public static final int AUTHPROCESS_SL20_CONSENT_VALID = 4113; } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/data/VerificationResult.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/data/VerificationResult.java index 0c625a9b..bb0c41d7 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/data/VerificationResult.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/data/VerificationResult.java @@ -7,33 +7,39 @@ import com.fasterxml.jackson.databind.JsonNode; public class VerificationResult { - private Boolean validSigned = null; - private List<X509Certificate> certs = null; - private JsonNode payload = null; - - public VerificationResult(JsonNode payload) { - this.payload = payload; - - } - - public VerificationResult(JsonNode string, List<X509Certificate> certs, boolean wasValidSigned) { - this.payload = string; - this.certs = certs; - this.validSigned = wasValidSigned; - - } - - public Boolean isValidSigned() { - return validSigned; - } - public List<X509Certificate> getCertChain() { - return certs; - } - public JsonNode getPayload() { - return payload; - } - - - - + private Boolean validSigned = null; + private List<X509Certificate> certs = null; + private JsonNode payload = null; + + public VerificationResult(final JsonNode payload) { + this.payload = payload; + + } + + /** + * JWS signature verification-result container. + * + * @param payload JWS payload + * @param certs JWS signercertificate + * @param wasValidSigned true if signature was valid + */ + public VerificationResult(final JsonNode payload, final List<X509Certificate> certs, final boolean wasValidSigned) { + this.payload = payload; + this.certs = certs; + this.validSigned = wasValidSigned; + + } + + public Boolean isValidSigned() { + return validSigned; + } + + public List<X509Certificate> getCertChain() { + return certs; + } + + public JsonNode getPayload() { + return payload; + } + } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20EidDataValidationException.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20EidDataValidationException.java new file mode 100644 index 00000000..a14fbe9e --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20EidDataValidationException.java @@ -0,0 +1,16 @@ +package at.gv.egiz.eaaf.modules.auth.sl20.exceptions; + +public class SL20EidDataValidationException extends SL20Exception { + private static final long serialVersionUID = 1L; + + public SL20EidDataValidationException(final Object[] parameters) { + super("sl20.07", parameters); + + } + + public SL20EidDataValidationException(final Object[] parameters, final Throwable e) { + super("sl20.07", parameters, e); + + } + +} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20Exception.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20Exception.java index b23b5ca3..12921ad6 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20Exception.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20Exception.java @@ -1,19 +1,19 @@ package at.gv.egiz.eaaf.modules.auth.sl20.exceptions; -import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException; +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; -public class SL20Exception extends EAAFAuthenticationException { +public class SL20Exception extends EaafAuthenticationException { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - public SL20Exception(String messageId, Object[] parameters) { - super(messageId, parameters); + public SL20Exception(final String messageId, final Object[] parameters) { + super(messageId, parameters); - } - - public SL20Exception(String messageId, Object[] parameters, Throwable wrapped) { - super(messageId, parameters, wrapped); + } - } + public SL20Exception(final String messageId, final Object[] parameters, final Throwable wrapped) { + super(messageId, parameters, wrapped); + + } } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20SecurityException.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20SecurityException.java index eaf55ba3..62abdeb8 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20SecurityException.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20SecurityException.java @@ -2,19 +2,19 @@ package at.gv.egiz.eaaf.modules.auth.sl20.exceptions; public class SL20SecurityException extends SL20Exception { - private static final long serialVersionUID = 3281385988027147449L; + private static final long serialVersionUID = 3281385988027147449L; - public SL20SecurityException(Object[] parameters) { - super("sl20.05", parameters); - } - - public SL20SecurityException(String parameter) { - super("sl20.05", new Object[] {parameter}); - } - - public SL20SecurityException(Object[] parameters, Throwable wrapped) { - super("sl20.05", parameters, wrapped); + public SL20SecurityException(final Object[] parameters) { + super("sl20.05", parameters); + } - } + public SL20SecurityException(final String parameter) { + super("sl20.05", new Object[] { parameter }); + } + + public SL20SecurityException(final Object[] parameters, final Throwable wrapped) { + super("sl20.05", parameters, wrapped); + + } } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20eIDDataValidationException.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20eIDDataValidationException.java deleted file mode 100644 index 24df735a..00000000 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20eIDDataValidationException.java +++ /dev/null @@ -1,16 +0,0 @@ -package at.gv.egiz.eaaf.modules.auth.sl20.exceptions; - -public class SL20eIDDataValidationException extends SL20Exception { - private static final long serialVersionUID = 1L; - - public SL20eIDDataValidationException(Object[] parameters) { - super("sl20.07", parameters); - - } - - public SL20eIDDataValidationException(Object[] parameters, Throwable e) { - super("sl20.07", parameters, e); - - } - -} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SLCommandoBuildException.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SLCommandoBuildException.java deleted file mode 100644 index 1f521ebc..00000000 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SLCommandoBuildException.java +++ /dev/null @@ -1,17 +0,0 @@ -package at.gv.egiz.eaaf.modules.auth.sl20.exceptions; - -public class SLCommandoBuildException extends SL20Exception { - - private static final long serialVersionUID = 1L; - - - public SLCommandoBuildException(String msg) { - super("sl20.01", new Object[]{msg}); - - } - - public SLCommandoBuildException(String msg, Throwable e) { - super("sl20.01", new Object[]{msg}, e); - - } -} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SLCommandoParserException.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SLCommandoParserException.java deleted file mode 100644 index 60993e69..00000000 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SLCommandoParserException.java +++ /dev/null @@ -1,17 +0,0 @@ -package at.gv.egiz.eaaf.modules.auth.sl20.exceptions; - -public class SLCommandoParserException extends SL20Exception { - - private static final long serialVersionUID = 1L; - - - public SLCommandoParserException(String msg) { - super("sl20.02", new Object[]{msg}); - - } - - public SLCommandoParserException(String msg, Throwable e) { - super("sl20.02", new Object[]{msg}, e); - - } -} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SlCommandoBuildException.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SlCommandoBuildException.java new file mode 100644 index 00000000..361f57b7 --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SlCommandoBuildException.java @@ -0,0 +1,16 @@ +package at.gv.egiz.eaaf.modules.auth.sl20.exceptions; + +public class SlCommandoBuildException extends SL20Exception { + + private static final long serialVersionUID = 1L; + + public SlCommandoBuildException(final String msg) { + super("sl20.01", new Object[] { msg }); + + } + + public SlCommandoBuildException(final String msg, final Throwable e) { + super("sl20.01", new Object[] { msg }, e); + + } +} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SlCommandoParserException.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SlCommandoParserException.java new file mode 100644 index 00000000..4993796a --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SlCommandoParserException.java @@ -0,0 +1,16 @@ +package at.gv.egiz.eaaf.modules.auth.sl20.exceptions; + +public class SlCommandoParserException extends SL20Exception { + + private static final long serialVersionUID = 1L; + + public SlCommandoParserException(final String msg) { + super("sl20.02", new Object[] { msg }); + + } + + public SlCommandoParserException(final String msg, final Throwable e) { + super("sl20.02", new Object[] { msg }, e); + + } +} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java new file mode 100644 index 00000000..d1887d5c --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java @@ -0,0 +1,241 @@ +package at.gv.egiz.eaaf.modules.auth.sl20.tasks; + +import java.security.cert.CertificateEncodingException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.message.BasicNameValuePair; +import org.jose4j.base64url.Base64Url; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; +import at.gv.egiz.eaaf.core.impl.utils.IHttpClientFactory; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; +import at.gv.egiz.eaaf.modules.auth.sl20.Constants; +import at.gv.egiz.eaaf.modules.auth.sl20.EventCodes; +import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20HttpBindingUtils; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonBuilderUtils; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonExtractorUtils; + +public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServletTask { + private static final Logger log = LoggerFactory.getLogger(AbstractCreateQualEidRequestTask.class); + + @Autowired(required = true) + private IHttpClientFactory httpClientFactory; + @Autowired(required = true) + protected IConfigurationWithSP authConfigWithSp; + + @Override + public void execute(final ExecutionContext executionContext, final HttpServletRequest request, + final HttpServletResponse response) throws TaskExecutionException { + + log.debug("Starting SL2.0 authentication process .... "); + + revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_SELECTED, "sl20auth"); + + try { + // get service-provider configuration + final ISpConfiguration oaConfig = pendingReq.getServiceProviderConfiguration(); + + if (oaConfig == null) { + log.warn("No SP configuration in pendingReq!"); + throw new RuntimeException("Suspect state. NO SP CONFIGURATION IN PendingRequest!"); + + } + + // get basic configuration parameters + final String vdaQualEidDUrl = extractVdaUrlForSpecificOa(oaConfig, executionContext); + if (StringUtils.isEmpty(vdaQualEidDUrl)) { + log.error("NO VDA URL for qualified eID (" + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT + ")"); + throw new SL20Exception("sl20.03", new Object[] { "NO VDA URL for qualified eID" }); + + } + + log.debug("Use {} as VDA end-point", vdaQualEidDUrl); + pendingReq.setRawDataToTransaction( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL, vdaQualEidDUrl); + revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_ENDPOINT_URL, vdaQualEidDUrl); + + // create SL2.0 command for qualified eID + final String signedQualEidCommand = buildSignedQualifiedEidCommand(); + + // build request container + final String qualEidReqId = Random.nextProcessReferenceValue(); + final ObjectNode sl20Req = SL20JsonBuilderUtils.createGenericRequest(qualEidReqId, null, null, + signedQualEidCommand); + + // build http POST request + final HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualEidDUrl).build()); + final List<NameValuePair> parameters = new ArrayList<>(); + parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, + Base64Url.encode(sl20Req.toString().getBytes("UTF-8")))); + httpReq.setEntity(new UrlEncodedFormEntity(parameters)); + + // build http GET request + // URIBuilder sl20ReqUri = new URIBuilder(vdaQualeIDUrl); + // sl20ReqUri.addParameter(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, + // Base64Url.encode(sl20Req.toString().getBytes())); + // HttpGet httpReq = new HttpGet(sl20ReqUri.build()); + + // set native client header + httpReq.addHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE, SL20Constants.HTTP_HEADER_VALUE_NATIVE); + + log.trace("Request VDA via SL20 with: " + Base64Url.encode(sl20Req.toString().getBytes("UTF-8"))); + + // request VDA + final HttpResponse httpResp = httpClientFactory.getHttpClient(false).execute(httpReq); + + // parse response + log.info("Receive response from VDA ... "); + final JsonNode sl20Resp = SL20JsonExtractorUtils.getSL20ContainerFromResponse(httpResp); + final VerificationResult respPayloadContainer = SL20JsonExtractorUtils.extractSL20PayLoad(sl20Resp, null, false); + + if (respPayloadContainer.isValidSigned() == null) { + log.debug("Receive unsigned payLoad from VDA"); + + } + + final JsonNode respPayload = respPayloadContainer.getPayload(); + if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText() + .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT)) { + log.debug("Find 'redirect' command in VDA response ... "); + final JsonNode params = SL20JsonExtractorUtils.getJsonObjectValue(respPayload, + SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, true); + final String redirectUrl = SL20JsonExtractorUtils.getStringValue(params, + SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL, true); + final JsonNode command = SL20JsonExtractorUtils.getJsonObjectValue(params, + SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND, false); + final String signedCommand = SL20JsonExtractorUtils.getStringValue(params, + SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND, false); + + // create forward SL2.0 command + final ObjectNode sl20Forward = sl20Resp.deepCopy(); + SL20JsonBuilderUtils.addOnlyOnceOfTwo(sl20Forward, SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD, + command.deepCopy(), signedCommand); + + // store pending request + pendingReq.setRawDataToTransaction(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, + qualEidReqId); + requestStoreage.storePendingRequest(pendingReq); + + // forward SL2.0 command + // TODO: maybe add SL2ClientType Header from execution context + SL20HttpBindingUtils.writeIntoResponse(request, response, sl20Forward, redirectUrl, + Integer.parseInt(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_HTTP_REDIRECT_CODE, + Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE))); + + } else if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText() + .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) { + JsonNode result = SL20JsonExtractorUtils.getJsonObjectValue(respPayload, + SL20Constants.SL20_COMMAND_CONTAINER_RESULT, false); + if (result == null) { + result = SL20JsonExtractorUtils.getJsonObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, + false); + } + + final String errorCode = SL20JsonExtractorUtils.getStringValue(result, + SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true); + final String errorMsg = SL20JsonExtractorUtils.getStringValue(result, + SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, true); + + log.info("Receive SL2.0 error. Code:" + errorCode + " Msg:" + errorMsg); + throw new SL20Exception("sl20.08", new Object[] { errorCode, errorMsg }); + + } else { + // TODO: update to add error handling + log.warn( + "Received an unrecognized command: " + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText()); + throw new SlCommandoParserException("Received an unrecognized command: " + + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).toString()); + } + + } catch (final EaafAuthenticationException e) { + throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e); + + } catch (final Exception e) { + log.warn("SL2.0 Authentication FAILED with a generic error.", e); + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } finally { + TransactionIdUtils.removeTransactionId(); + TransactionIdUtils.removeSessionId(); + + } + + } + + /** + * Create a implementation specific qualified eID SL2.0 command + * + * @param oaConfig + * + * @return signed JWT token as serialized {@link String} + * @throws CertificateEncodingException In case of certificate parsing error + * @throws SL20Exception In case of a SL2.0 error + */ + protected abstract String buildSignedQualifiedEidCommand() throws CertificateEncodingException, SL20Exception; + + private String extractVdaUrlForSpecificOa(final ISpConfiguration oaConfig, final ExecutionContext executionContext) { + + // load SP specific config for development and testing purposes + final String spSpecificVdaEndpoints = oaConfig.getConfigurationValue(Constants.CONFIG_PROP_SP_SL20_ENDPOINT_LIST); + + // load general configuration + final Map<String, String> endPointMap = authConfigWithSp + .getBasicConfigurationWithPrefix(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST); + endPointMap.put(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT, + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT)); + if (StringUtils.isNotEmpty(spSpecificVdaEndpoints)) { + endPointMap.putAll(KeyValueUtils.convertListToMap( + KeyValueUtils.getListOfCsvValues(KeyValueUtils.normalizeCsvValueString(spSpecificVdaEndpoints)))); + log.debug("Find OA specific SL2.0 endpoints. Updating endPoint list ... "); + + } + + log.trace("Find #" + endPointMap.size() + " SL2.0 endpoints ... "); + + // selection based on request Header + final String sl20VdaTypeHeader = (String) executionContext + .get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase()); + if (StringUtils.isNotEmpty(sl20VdaTypeHeader)) { + final String vdaUrl = endPointMap.get(sl20VdaTypeHeader); + if (StringUtils.isNotEmpty(vdaUrl)) { + return vdaUrl.trim(); + } else { + log.info("Can NOT find VDA with Id: " + sl20VdaTypeHeader + ". Use default VDA"); + } + + } + + log.info("NO specific VDA endpoint requested or found. Use default VDA"); + return endPointMap.get(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT); + + } + +} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java deleted file mode 100644 index 85302d83..00000000 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java +++ /dev/null @@ -1,227 +0,0 @@ -package at.gv.egiz.eaaf.modules.auth.sl20.tasks; - -import java.security.cert.CertificateEncodingException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.message.BasicNameValuePair; -import org.jose4j.base64url.Base64Url; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; -import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; -import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; -import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException; -import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; -import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; -import at.gv.egiz.eaaf.core.impl.utils.IHttpClientFactory; -import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; -import at.gv.egiz.eaaf.core.impl.utils.Random; -import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils; -import at.gv.egiz.eaaf.modules.auth.sl20.Constants; -import at.gv.egiz.eaaf.modules.auth.sl20.EventCodes; -import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SLCommandoBuildException; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SLCommandoParserException; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20HttpBindingUtils; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JSONBuilderUtils; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JSONExtractorUtils; - -public abstract class AbstractCreateQualeIDRequestTask extends AbstractAuthServletTask { - private static final Logger log = LoggerFactory.getLogger(AbstractCreateQualeIDRequestTask.class); - - @Autowired(required=true) private IHttpClientFactory httpClientFactory; - @Autowired(required=true) protected IConfigurationWithSP authConfigWithSp; - - @Override - public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) - throws TaskExecutionException { - - log.debug("Starting SL2.0 authentication process .... "); - - revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_SELECTED, "sl20auth"); - - try { - //get service-provider configuration - final ISPConfiguration oaConfig = pendingReq.getServiceProviderConfiguration(); - - if (oaConfig == null) { - log.warn("No SP configuration in pendingReq!"); - throw new RuntimeException("Suspect state. NO SP CONFIGURATION IN PendingRequest!"); - - } - - //get basic configuration parameters - final String vdaQualeIDUrl = extractVDAURLForSpecificOA(oaConfig, executionContext); - if (StringUtils.isEmpty(vdaQualeIDUrl)) { - log.error("NO VDA URL for qualified eID (" + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT + ")"); - throw new SL20Exception("sl20.03", new Object[]{"NO VDA URL for qualified eID"}); - - } - - log.debug("Use {} as VDA end-point", vdaQualeIDUrl) ; - pendingReq.setRawDataToTransaction( - Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL, - vdaQualeIDUrl); - revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_ENDPOINT_URL, vdaQualeIDUrl); - - //create SL2.0 command for qualified eID - final String signedQualeIDCommand = buildSignedQualifiedEIDCommand(); - - //build request container - final String qualeIDReqId = Random.nextProcessReferenceValue(); - final ObjectNode sl20Req = SL20JSONBuilderUtils.createGenericRequest(qualeIDReqId, null, null, signedQualeIDCommand); - - //build http POST request - final HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualeIDUrl).build()); - final List<NameValuePair> parameters = new ArrayList<NameValuePair>();; - parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes()))); - httpReq.setEntity(new UrlEncodedFormEntity(parameters )); - - //build http GET request -// URIBuilder sl20ReqUri = new URIBuilder(vdaQualeIDUrl); -// sl20ReqUri.addParameter(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes())); -// HttpGet httpReq = new HttpGet(sl20ReqUri.build()); - - //set native client header - httpReq.addHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE, SL20Constants.HTTP_HEADER_VALUE_NATIVE); - - log.trace("Request VDA via SL20 with: " + Base64Url.encode(sl20Req.toString().getBytes())); - - //request VDA - final HttpResponse httpResp = httpClientFactory.getHttpClient(false).execute(httpReq); - - //parse response - log.info("Receive response from VDA ... "); - final JsonNode sl20Resp = SL20JSONExtractorUtils.getSL20ContainerFromResponse(httpResp); - final VerificationResult respPayloadContainer = SL20JSONExtractorUtils.extractSL20PayLoad(sl20Resp, null, false); - - if (respPayloadContainer.isValidSigned() == null) { - log.debug("Receive unsigned payLoad from VDA"); - - } - - final JsonNode respPayload = respPayloadContainer.getPayload(); - if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText() - .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT)) { - log.debug("Find 'redirect' command in VDA response ... "); - final JsonNode params = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, true); - final String redirectURL = SL20JSONExtractorUtils.getStringValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL, true); - final JsonNode command = SL20JSONExtractorUtils.getJSONObjectValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND, false); - final String signedCommand = SL20JSONExtractorUtils.getStringValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND, false); - - //create forward SL2.0 command - final ObjectNode sl20Forward = sl20Resp.deepCopy(); - SL20JSONBuilderUtils.addOnlyOnceOfTwo(sl20Forward, - SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD, - command.deepCopy(), signedCommand); - - //store pending request - pendingReq.setRawDataToTransaction(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, - qualeIDReqId); - requestStoreage.storePendingRequest(pendingReq); - - //forward SL2.0 command - //TODO: maybe add SL2ClientType Header from execution context - SL20HttpBindingUtils.writeIntoResponse(request, response, sl20Forward, redirectURL, - Integer.parseInt(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_HTTP_REDIRECT_CODE, Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE))); - - } else if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText() - .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) { - JsonNode result = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_RESULT, false); - if (result == null) - result = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, false); - - final String errorCode = SL20JSONExtractorUtils.getStringValue(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true); - final String errorMsg = SL20JSONExtractorUtils.getStringValue(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, true); - - log.info("Receive SL2.0 error. Code:" + errorCode + " Msg:" + errorMsg); - throw new SL20Exception("sl20.08", new Object[]{errorCode, errorMsg}); - - } else { - //TODO: update to add error handling - log.warn("Received an unrecognized command: " + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText()); - throw new SLCommandoParserException("Received an unrecognized command: \" + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString()"); - } - - - } catch (final EAAFAuthenticationException e) { - throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e); - - } catch (final Exception e) { - log.warn("SL2.0 Authentication FAILED with a generic error.", e); - throw new TaskExecutionException(pendingReq, e.getMessage(), e); - - } finally { - TransactionIDUtils.removeTransactionId(); - TransactionIDUtils.removeSessionId(); - - } - - } - - /** - * Create a implementation specific qualified eID SL2.0 command - * @param oaConfig - * - * @return signed JWT token as serialized {@link String} - * @throws CertificateEncodingException - * @throws SLCommandoBuildException - * @throws SL20Exception - */ - protected abstract String buildSignedQualifiedEIDCommand() throws CertificateEncodingException, SL20Exception; - - - private String extractVDAURLForSpecificOA(ISPConfiguration oaConfig, ExecutionContext executionContext) { - - //load SP specific config for development and testing purposes - final String spSpecificVDAEndpoints = oaConfig.getConfigurationValue(Constants.CONFIG_PROP_SP_SL20_ENDPOINT_LIST); - - //load general configuration - final Map<String, String> endPointMap = authConfigWithSp.getBasicConfigurationWithPrefix(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST); - endPointMap.put(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT, authConfig.getBasicConfiguration(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT)); - if (StringUtils.isNotEmpty(spSpecificVDAEndpoints)) { - endPointMap.putAll(KeyValueUtils.convertListToMap( - KeyValueUtils.getListOfCSVValues( - KeyValueUtils.normalizeCSVValueString(spSpecificVDAEndpoints)))); - log.debug("Find OA specific SL2.0 endpoints. Updating endPoint list ... "); - - } - - log.trace("Find #" + endPointMap.size() + " SL2.0 endpoints ... "); - - //selection based on request Header - final String sl20VDATypeHeader = (String) executionContext.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase()); - if (StringUtils.isNotEmpty(sl20VDATypeHeader)) { - final String vdaURL = endPointMap.get(sl20VDATypeHeader); - if (StringUtils.isNotEmpty(vdaURL)) - return vdaURL.trim(); - else - log.info("Can NOT find VDA with Id: " + sl20VDATypeHeader + ". Use default VDA"); - - } - - - log.info("NO specific VDA endpoint requested or found. Use default VDA"); - return endPointMap.get(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT); - - } - -} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java new file mode 100644 index 00000000..655cc2c6 --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java @@ -0,0 +1,211 @@ +package at.gv.egiz.eaaf.modules.auth.sl20.tasks; + +import java.io.IOException; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; +import at.gv.egiz.eaaf.core.impl.utils.DataUrlBuilder; +import at.gv.egiz.eaaf.core.impl.utils.StreamUtils; +import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; +import at.gv.egiz.eaaf.modules.auth.sl20.Constants; +import at.gv.egiz.eaaf.modules.auth.sl20.EventCodes; +import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20SecurityException; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.IJoseTools; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.JsonMapper; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonExtractorUtils; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20ResponseUtils; + +import org.apache.commons.lang3.StringUtils; +import org.jose4j.base64url.Base64Url; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; + +public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask { + private static final Logger log = LoggerFactory.getLogger(AbstractReceiveQualEidTask.class); + + @Autowired(required = true) + private IJoseTools joseTools; + + @Override + public void execute(final ExecutionContext executionContext, final HttpServletRequest request, + final HttpServletResponse response) throws TaskExecutionException { + String sl20Result = null; + + try { + log.debug("Receiving SL2.0 response process .... "); + JsonNode sl20ReqObj = null; + + // A-Trust does not SET http-header 'SL2ClientType' with value 'native' + // If A-trust sends an error, its maybe FrontChannel on DataURL + // boolean aTrustErrorWorkAround = false; + + try { + // get SL2.0 command or result from HTTP request + final Map<String, String> reqParams = getParameters(request); + sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM); + + if (StringUtils.isEmpty(sl20Result)) { + // Workaround for SIC Handy-Signature, because it sends result in InputStream + final String isReqInput = StreamUtils.readStream(request.getInputStream(), "UTF-8"); + if (StringUtils.isNotEmpty(isReqInput)) { + log.info("Use SIC Handy-Signature work-around!"); + sl20Result = isReqInput.substring("slcommand=".length()); + + } else { + log.info("NO SL2.0 commando or result FOUND."); + throw new SL20Exception("sl20.04", null); + } + + } + + log.trace("Received SL2.0 result: " + sl20Result); + revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_DATAURL_IP, request.getRemoteAddr()); + + // parse SL2.0 command/result into JSON + try { + sl20ReqObj = new JsonMapper().getMapper().readTree(Base64Url.decodeToUtf8String(sl20Result)); + + } catch (final JsonParseException e) { + log.warn("SL2.0 command or result is NOT valid JSON.", e); + log.debug("SL2.0 msg: " + sl20Result); + throw new SL20Exception("sl20.02", new Object[] { "SL2.0 command or result is NOT valid JSON." }, e); + + } + + // check on errorMessage + final VerificationResult payLoadContainerErrorCheck = SL20JsonExtractorUtils.extractSL20PayLoad(sl20ReqObj, + joseTools, false); + if (SL20JsonExtractorUtils + .getStringValue(payLoadContainerErrorCheck.getPayload(), SL20Constants.SL20_COMMAND_CONTAINER_NAME, true) + .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) { + log.debug("Find " + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR + " result .... "); + final JsonNode errorResult = SL20JsonExtractorUtils.extractSL20Result(payLoadContainerErrorCheck.getPayload(), + joseTools, false); + final String errorCode = SL20JsonExtractorUtils.getStringValue(errorResult, + SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true); + final String errorMsg = SL20JsonExtractorUtils.getStringValue(errorResult, + SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, false); + + log.info("Receiving errorcode: {} with msg: {} from VDA! Stopping auth-process ... ", errorCode, errorMsg); + // aTrustErrorWorkAround = true; + throw new SL20Exception("sl20.08", new Object[] { errorCode, errorMsg }); + + } else { + // Receive no error - To request validation + + // validate reqId with inResponseTo + final String sl20ReqId = pendingReq + .getRawData(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, String.class); + final String inRespTo = SL20JsonExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_INRESPTO, true); + if (sl20ReqId == null || !sl20ReqId.equals(inRespTo)) { + log.info("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo); + throw new SL20SecurityException( + "SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo); + } + + // validate signature + final VerificationResult payLoadContainer = SL20JsonExtractorUtils.extractSL20PayLoad(sl20ReqObj, joseTools, + authConfig.getBasicConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true)); + + if (payLoadContainer.isValidSigned() == null || !payLoadContainer.isValidSigned()) { + if (authConfig.getBasicConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true)) { + log.info("SL20 result from VDA was not valid signed"); + throw new SL20SecurityException(new Object[] { "Signature on SL20 result NOT valid." }); + + } else { + log.warn("SL20 result from VDA is NOT valid signed, but signatures-verification " + + "is DISABLED by configuration!"); + + } + } + + // extract payloaf + final JsonNode payLoad = payLoadContainer.getPayload(); + + // handle SL2.0 response payLoad + handleResponsePayLoad(payLoad); + + } + + } catch (final EaafAuthenticationException e) { + log.warn("SL2.0 processing error:", e); + if (sl20Result != null) { + log.debug("Received SL2.0 result: " + sl20Result); + } + pendingReq.setRawDataToTransaction( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, + new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e)); + + } catch (final Exception e) { + log.warn("ERROR:", e); + log.warn("SL2.0 Authentication FAILED with a generic error.", e); + if (sl20Result != null) { + log.debug("Received SL2.0 result: " + sl20Result); + } + pendingReq.setRawDataToTransaction( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, + new TaskExecutionException(pendingReq, e.getMessage(), e)); + + } finally { + // store pending request + requestStoreage.storePendingRequest(pendingReq); + + // write SL2.0 response + if (sl20ReqObj != null) { + final String resumeEndpoint = new DataUrlBuilder().buildDataUrl(pendingReq.getAuthUrl(), + getResumeEndPoint(), pendingReq.getPendingRequestId()); + SL20ResponseUtils.buildResponse(request, response, pendingReq, resumeEndpoint, + SL20JsonExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false), + authConfig); + + } else { + SL20ResponseUtils.buildErrorResponse(response, "2000", "General transport Binding error"); + } + + } + + } catch (final Exception e) { + // write internal server errror 500 according to SL2.0 specification, chapter + // https transport + // binding + log.warn("Can NOT build SL2.0 response. Reason: " + e.getMessage(), e); + if (sl20Result != null) { + log.debug("Received SL2.0 result: " + sl20Result); + } + try { + response.sendError(500, "Internal Server Error."); + + } catch (final IOException e1) { + log.error("Can NOT send error message. SOMETHING IS REALY WRONG!", e); + + } + + } finally { + TransactionIdUtils.removeTransactionId(); + TransactionIdUtils.removeSessionId(); + + } + } + + protected abstract void handleResponsePayLoad(JsonNode payLoad) + throws SlCommandoParserException, SL20Exception, EaafStorageException; + + protected abstract String getResumeEndPoint(); + + +} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualeIDTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualeIDTask.java deleted file mode 100644 index b4039cf9..00000000 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualeIDTask.java +++ /dev/null @@ -1,321 +0,0 @@ -package at.gv.egiz.eaaf.modules.auth.sl20.tasks; - -import java.io.IOException; -import java.io.StringWriter; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.entity.ContentType; -import org.jose4j.base64url.Base64Url; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import at.gv.egiz.eaaf.core.api.data.EAAFConstants; -import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; -import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException; -import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException; -import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; -import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; -import at.gv.egiz.eaaf.core.impl.utils.DataURLBuilder; -import at.gv.egiz.eaaf.core.impl.utils.StreamUtils; -import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils; -import at.gv.egiz.eaaf.modules.auth.sl20.Constants; -import at.gv.egiz.eaaf.modules.auth.sl20.EventCodes; -import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20SecurityException; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SLCommandoParserException; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.IJOSETools; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.JsonMapper; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JSONBuilderUtils; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JSONExtractorUtils; - - -public abstract class AbstractReceiveQualeIDTask extends AbstractAuthServletTask { - private static final Logger log = LoggerFactory.getLogger(AbstractReceiveQualeIDTask.class); - - @Autowired(required=true) private IJOSETools joseTools; - - @Override - public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) - throws TaskExecutionException { - String sl20Result = null; - - try { - log.debug("Receiving SL2.0 response process .... "); - JsonNode sl20ReqObj = null; - - //A-Trust does not SET http-header 'SL2ClientType' with value 'native' - //If A-trust sends an error, its maybe FrontChannel on DataURL - //boolean aTrustErrorWorkAround = false; - - try { - //get SL2.0 command or result from HTTP request - final Map<String, String> reqParams = getParameters(request); - sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM); - - if (StringUtils.isEmpty(sl20Result)) { - //Workaround for SIC Handy-Signature, because it sends result in InputStream - final String isReqInput = StreamUtils.readStream(request.getInputStream(), "UTF-8"); - if (StringUtils.isNotEmpty(isReqInput)) { - log.info("Use SIC Handy-Signature work-around!"); - sl20Result = isReqInput.substring("slcommand=".length()); - - } else { - log.info("NO SL2.0 commando or result FOUND."); - throw new SL20Exception("sl20.04", null); - } - - } - - log.trace("Received SL2.0 result: " + sl20Result); - revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_DATAURL_IP, request.getRemoteAddr()); - - //parse SL2.0 command/result into JSON - try { - sl20ReqObj = new JsonMapper().getMapper().readTree(Base64Url.decodeToUtf8String(sl20Result)); - - } catch (final JsonParseException e) { - log.warn("SL2.0 command or result is NOT valid JSON.", e); - log.debug("SL2.0 msg: " + sl20Result); - throw new SL20Exception("sl20.02", new Object[]{"SL2.0 command or result is NOT valid JSON."}, e); - - } - - //check on errorMessage - final VerificationResult payLoadContainerErrorCheck = SL20JSONExtractorUtils.extractSL20PayLoad(sl20ReqObj, joseTools, false); - if (SL20JSONExtractorUtils.getStringValue( - payLoadContainerErrorCheck.getPayload(), SL20Constants.SL20_COMMAND_CONTAINER_NAME, true) - .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) { - log.debug("Find " + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR + " result .... "); - final JsonNode errorResult = SL20JSONExtractorUtils.extractSL20Result(payLoadContainerErrorCheck.getPayload(), joseTools, false); - final String errorCode = SL20JSONExtractorUtils.getStringValue(errorResult, - SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true); - final String errorMsg = SL20JSONExtractorUtils.getStringValue(errorResult, - SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, false); - - log.info("Receiving errorcode: {} with msg: {} from VDA! Stopping auth-process ... ", errorCode, errorMsg); - //aTrustErrorWorkAround = true; - throw new SL20Exception("sl20.08", new Object[] {errorCode, errorMsg}); - - } else { - //Receive no error - To request validation - - //validate reqId with inResponseTo - final String sl20ReqId = pendingReq.getRawData(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, String.class); - final String inRespTo = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_INRESPTO, true); - if (sl20ReqId == null || !sl20ReqId.equals(inRespTo)) { - log.info("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo); - throw new SL20SecurityException("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo); - } - - - //validate signature - final VerificationResult payLoadContainer = SL20JSONExtractorUtils.extractSL20PayLoad( - sl20ReqObj, joseTools, - authConfig.getBasicConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true)); - - if ( (payLoadContainer.isValidSigned() == null || !payLoadContainer.isValidSigned())) { - if (authConfig.getBasicConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true)) { - log.info("SL20 result from VDA was not valid signed"); - throw new SL20SecurityException(new Object[]{"Signature on SL20 result NOT valid."}); - - } else { - log.warn("SL20 result from VDA is NOT valid signed, but signatures-verification is DISABLED by configuration!"); - - } - } - - payLoadContainer.getCertChain(); - - - //extract payloaf - final JsonNode payLoad = payLoadContainer.getPayload(); - - - //handle SL2.0 response payLoad - handleResponsePayLoad(payLoad); - - } - - } catch (final EAAFAuthenticationException e) { - log.warn("SL2.0 processing error:", e); - if (sl20Result != null) - log.debug("Received SL2.0 result: " + sl20Result); - pendingReq.setRawDataToTransaction( - Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, - new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e)); - - } catch (final Exception e) { - log.warn("ERROR:", e); - log.warn("SL2.0 Authentication FAILED with a generic error.", e); - if (sl20Result != null) - log.debug("Received SL2.0 result: " + sl20Result); - pendingReq.setRawDataToTransaction( - Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, - new TaskExecutionException(pendingReq, e.getMessage(), e)); - - } finally { - //store pending request - requestStoreage.storePendingRequest(pendingReq); - - //write SL2.0 response - if (sl20ReqObj != null) - //buildResponse(request, response, sl20ReqObj, aTrustErrorWorkAround); - buildResponse(request, response, sl20ReqObj); - else - buildErrorResponse(request, response, "2000", "General transport Binding error"); - - } - - } catch (final Exception e) { - //write internal server errror 500 according to SL2.0 specification, chapter https transport binding - log.warn("Can NOT build SL2.0 response. Reason: " + e.getMessage(), e); - if (sl20Result != null) - log.debug("Received SL2.0 result: " + sl20Result); - try { - response.sendError(500, "Internal Server Error."); - - } catch (final IOException e1) { - log.error("Can NOT send error message. SOMETHING IS REALY WRONG!", e); - - } - - } finally { - TransactionIDUtils.removeTransactionId(); - TransactionIDUtils.removeSessionId(); - - } - } - - protected abstract void handleResponsePayLoad(JsonNode payLoad) throws SLCommandoParserException, SL20Exception, EAAFStorageException; - - protected abstract String getResumeEndPoint(); - - private void buildErrorResponse(HttpServletRequest request, HttpServletResponse response, String errorCode, String errorMsg) throws Exception { - final ObjectNode error = SL20JSONBuilderUtils.createErrorCommandResult(errorCode, errorMsg); - final ObjectNode errorCommand = SL20JSONBuilderUtils.createCommandResponse(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, error, null); - - - final ObjectNode respContainer = SL20JSONBuilderUtils.createGenericResponse( - UUID.randomUUID().toString(), - null, - null, - errorCommand , - null); - - log.trace("SL20 response to VDA: " + respContainer); - final StringWriter writer = new StringWriter(); - writer.write(respContainer.toString()); - final byte[] content = writer.toString().getBytes("UTF-8"); - response.setStatus(HttpServletResponse.SC_OK); - response.setContentLength(content.length); - response.setContentType(ContentType.APPLICATION_JSON.toString()); - response.getOutputStream().write(content); - - } - - private void buildResponse(HttpServletRequest request, HttpServletResponse response, JsonNode sl20ReqObj) throws IOException, SL20Exception, URISyntaxException { - //create response - final Map<String, String> reqParameters = new HashMap<String, String>(); - reqParameters.put(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReq.getPendingRequestId()); - final ObjectNode callReqParams = SL20JSONBuilderUtils.createCallCommandParameters( - new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), getResumeEndPoint(), null), - SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET, - false, - reqParameters); - final ObjectNode callCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, callReqParams); - - //build first redirect command for app - final ObjectNode redirectOneParams = SL20JSONBuilderUtils.createRedirectCommandParameters( - generateICPRedirectURLForDebugging(), - callCommand, null, true); - final ObjectNode redirectOneCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams); - - //build second redirect command for IDP - final ObjectNode redirectTwoParams = SL20JSONBuilderUtils.createRedirectCommandParameters( - new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), getResumeEndPoint(), pendingReq.getPendingRequestId()), - redirectOneCommand, null, false); - final ObjectNode redirectTwoCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectTwoParams); - - //build generic SL2.0 response container - final String transactionId = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false); - final ObjectNode respContainer = SL20JSONBuilderUtils.createGenericRequest( - UUID.randomUUID().toString(), - transactionId, - redirectTwoCommand, - null); - - if (request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null && - request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) { - log.debug("Client request containts 'native client' header ... "); - log.trace("SL20 response to VDA: " + respContainer); - final StringWriter writer = new StringWriter(); - writer.write(respContainer.toString()); - final byte[] content = writer.toString().getBytes("UTF-8"); - response.setStatus(HttpServletResponse.SC_OK); - response.setContentLength(content.length); - response.setContentType(ContentType.APPLICATION_JSON.toString()); - response.getOutputStream().write(content); - - - } else { - log.info("SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"); - - log.debug("Client request containts is no native client ... "); - final URIBuilder clientRedirectURI = new URIBuilder( - new DataURLBuilder().buildDataURL( - pendingReq.getAuthURL(), getResumeEndPoint(), pendingReq.getPendingRequestId())); - response.setStatus(Integer.parseInt( - authConfig.getBasicConfiguration( - Constants.CONFIG_PROP_HTTP_REDIRECT_CODE, - Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE))); - response.setHeader("Location", clientRedirectURI.build().toString()); - - -// throw new SL20Exception("sl20.06", -// new Object[] {"SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"}); - - } - } - - /** - * Generates a IPC redirect URL that is configured on IDP side - * - * @return IPC ReturnURL, or null if no URL is configured - */ - private String generateICPRedirectURLForDebugging() { - final String PATTERN_PENDING_REQ_ID = "#PENDINGREQID#"; - - String ipcRedirectURLConfig = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_IPC_RETURN_URL); - if (StringUtils.isNotEmpty(ipcRedirectURLConfig)) { - if (ipcRedirectURLConfig.contains(PATTERN_PENDING_REQ_ID)) { - log.trace("Find 'pendingReqId' pattern in IPC redirect URL. Update url ... "); - ipcRedirectURLConfig = ipcRedirectURLConfig.replaceAll( - "#PENDINGREQID#", - EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID + "=" + pendingReq.getPendingRequestId()); - - } - - return ipcRedirectURLConfig; - } - - return null; - - } - - -} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJOSETools.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJOSETools.java deleted file mode 100644 index b124ada7..00000000 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJOSETools.java +++ /dev/null @@ -1,87 +0,0 @@ -package at.gv.egiz.eaaf.modules.auth.sl20.utils; - -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.cert.X509Certificate; -import java.util.List; - -import javax.annotation.Nonnull; - -import org.jose4j.jwa.AlgorithmConstraints; -import org.jose4j.lang.JoseException; - -import com.fasterxml.jackson.databind.JsonNode; - -import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SLCommandoBuildException; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SLCommandoParserException; - -public interface IJOSETools { - - /** - * Create a JWS signature - * - * @param payLoad Payload to sign - * @throws SLCommandoBuildException - */ - public String createSignature(String payLoad) throws SLCommandoBuildException; - - /** - * Validates a signed SL2.0 message - * - * @param serializedContent - * @return - * @throws SLCommandoParserException - * @throws SL20Exception - */ - @Nonnull - public VerificationResult validateSignature(@Nonnull String serializedContent) throws SL20Exception; - - /** - * Validate a JWS signature - * - * @param serializedContent JWS in serialized form - * @param trustedCerts trusted X509 certificates - * @param constraints signature verification constraints - * @return Signature-verification result - * @throws JoseException - * @throws IOException - */ - @Nonnull - public VerificationResult validateSignature(@Nonnull String serializedContent, @Nonnull List<X509Certificate> trustedCerts, - @Nonnull AlgorithmConstraints constraints) throws JoseException, IOException; - - /** - * Validate a JWS signature - * - * @param serializedContent JWS in serialized form - * @param trustStore with trusted X509 certificates - * @param algconstraints signature verification constraints - * @return Signature-verification result - * @throws JoseException - * @throws IOException - * @throws KeyStoreException - */ - @Nonnull - public VerificationResult validateSignature(@Nonnull String serializedContent, @Nonnull KeyStore trustStore, - @Nonnull AlgorithmConstraints algconstraints) throws JoseException, IOException, KeyStoreException; - - /** - * Get the encryption certificate for SL2.0 End-to-End encryption - * - * @return - */ - public X509Certificate getEncryptionCertificate(); - - /** - * Decrypt a serialized JWE token - * - * @param compactSerialization Serialized JWE token - * @return decrypted payload - * @throws SL20Exception - */ - public JsonNode decryptPayload(String compactSerialization) throws SL20Exception; - -} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJoseTools.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJoseTools.java new file mode 100644 index 00000000..f04555dc --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJoseTools.java @@ -0,0 +1,98 @@ +package at.gv.egiz.eaaf.modules.auth.sl20.utils; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.X509Certificate; +import java.util.List; + +import javax.annotation.Nonnull; + +import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoBuildException; + +import org.jose4j.jwa.AlgorithmConstraints; +import org.jose4j.lang.JoseException; + +import com.fasterxml.jackson.databind.JsonNode; + +public interface IJoseTools { + + /** + * Create a JWS signature. + * + *<p>This method adds the certificate chain into JOSE header.</p> + * + * @param payLoad Payload to sign + * @throws SlCommandoBuildException In case of a signature creation error + */ + String createSignature(String payLoad) throws SlCommandoBuildException; + + /** + * Create a JWS signature. + * + * @param payLoad Payload to sign + * @param addFullCertChain If <code>true</code> the full certificate chain will be added, + * otherwise only the X509CertSha256Fingerprint is added into JOSE header + * @return Signed PayLoad in serialized form + * @throws SlCommandoBuildException SlCommandoBuildException In case of a signature creation error + */ + String createSignature(String payLoad, boolean addFullCertChain) throws SlCommandoBuildException; + + /** + * Validates a signed SL2.0 message. + * + * @param serializedContent Serialized JWS signature + * @return Verification-result DAO + * @throws SL20Exception In case of a signature validation error + */ + @Nonnull + VerificationResult validateSignature(@Nonnull String serializedContent) throws SL20Exception; + + /** + * Validate a JWS signature. + * + * @param serializedContent JWS in serialized form + * @param trustedCerts trusted X509 certificates + * @param constraints signature verification constraints + * @return Signature-verification result + * @throws JoseException In case of a signature verification error + * @throws IOException In case of a general IO error + */ + @Nonnull + VerificationResult validateSignature(@Nonnull String serializedContent, @Nonnull List<X509Certificate> trustedCerts, + @Nonnull AlgorithmConstraints constraints) throws JoseException, IOException; + + /** + * Validate a JWS signature. + * + * @param serializedContent JWS in serialized form + * @param trustStore with trusted X509 certificates + * @param algconstraints signature verification constraints + * @return Signature-verification result + * @throws JoseException In case of a signature verification error + * @throws IOException In case of a general IO error + * @throws KeyStoreException In case of TrustStore error + */ + @Nonnull + VerificationResult validateSignature(@Nonnull String serializedContent, @Nonnull KeyStore trustStore, + @Nonnull AlgorithmConstraints algconstraints) throws JoseException, IOException, KeyStoreException; + + /** + * Get the encryption certificate for SL2.0 End-to-End encryption. + * + * @return + */ + X509Certificate getEncryptionCertificate(); + + /** + * Decrypt a serialized JWE token. + * + * @param compactSerialization Serialized JWE token + * @return decrypted payload + * @throws SL20Exception In case of a decryption error + */ + JsonNode decryptPayload(String compactSerialization) throws SL20Exception; + +} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonMapper.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonMapper.java index b33649e1..2387a9f2 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonMapper.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonMapper.java @@ -18,114 +18,122 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.type.TypeFactory; import at.gv.egiz.eaaf.core.api.utils.IJsonMapper; -import at.gv.egiz.eaaf.core.exceptions.EAAFJsonMapperException; +import at.gv.egiz.eaaf.core.exceptions.EaafJsonMapperException; public class JsonMapper implements IJsonMapper { - private static final Logger log = LoggerFactory.getLogger(JsonMapper.class); - - private final ObjectMapper mapper = new ObjectMapper(); - - /** - * The default constructor where the default pretty printer is disabled. - */ - public JsonMapper() { - this(false); - - } - - /** - * The constructor. - * @param prettyPrint enables or disables the default pretty printer - */ - public JsonMapper(@NonNull boolean prettyPrint) { - log.trace("Initializing JSON object-mapper ... "); - mapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true); - mapper.configure(DeserializationFeature.FAIL_ON_TRAILING_TOKENS, true); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES , true); - mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE); - mapper.setVisibility(PropertyAccessor.GETTER, Visibility.PUBLIC_ONLY); - mapper.setVisibility(PropertyAccessor.IS_GETTER, Visibility.PUBLIC_ONLY); - if (prettyPrint) { - mapper.enable(SerializationFeature.INDENT_OUTPUT); - } - - log.debug("JSON object-mapper initialized"); - - } - - - /* (non-Javadoc) - * @at.gv.egiz.eaaf.core.api.utils.IJsonMapper#getMapper() - */ - public ObjectMapper getMapper() { - return mapper; - - } - - - /* (non-Javadoc) - * @see at.gv.egiz.eaaf.core.api.utils.IJsonMapper#serialize(java.lang.Object) - */ - @Override - public String serialize(Object value) throws EAAFJsonMapperException { - try { - return mapper.writeValueAsString(value); - - } catch (final JsonProcessingException e) { - log.warn("JSON mapping FAILED with error: {}", e.getMessage()); - throw new EAAFJsonMapperException(e.getMessage(), e); - - } - - } - - /* (non-Javadoc) - * @see at.gv.egiz.eaaf.core.api.utils.IJsonMapper#deserialize(java.lang.String, java.lang.Class) - */ - @Override - public <T> Object deserialize(String value, Class<T> clazz) throws EAAFJsonMapperException { - try { - if (clazz != null) { - if (clazz.isAssignableFrom(TypeReference.class)) - return mapper.readValue(value, clazz); - else { - final JavaType javaType = TypeFactory.defaultInstance().constructType(clazz); - return mapper.readValue(value, javaType); - - } - - } else - return mapper.readValue(value, Object.class); - - } catch (final IOException e) { - log.warn("JSON mapping FAILED with error: {}", e.getMessage()); - throw new EAAFJsonMapperException(e.getMessage(), e); - - } - - } - - @Override - public <T> Object deserialize(InputStream is, Class<T> clazz) throws EAAFJsonMapperException { - try { - if (clazz != null) { - if (clazz.isAssignableFrom(TypeReference.class)) - return mapper.readValue(is, clazz); - else { - final JavaType javaType = TypeFactory.defaultInstance().constructType(clazz); - return mapper.readValue(is, javaType); - - } - - } else - return mapper.readValue(is, Object.class); - - } catch (final IOException e) { - log.warn("JSON mapping FAILED with error: {}", e.getMessage()); - throw new EAAFJsonMapperException(e.getMessage(), e); - - } - - } - + private static final Logger log = LoggerFactory.getLogger(JsonMapper.class); + + private final ObjectMapper mapper = new ObjectMapper(); + + /** + * The default constructor where the default pretty printer is disabled. + */ + public JsonMapper() { + this(false); + + } + + /** + * The constructor. + * + * @param prettyPrint enables or disables the default pretty printer + */ + public JsonMapper(@NonNull final boolean prettyPrint) { + log.trace("Initializing JSON object-mapper ... "); + mapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true); + mapper.configure(DeserializationFeature.FAIL_ON_TRAILING_TOKENS, true); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); + mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE); + mapper.setVisibility(PropertyAccessor.GETTER, Visibility.PUBLIC_ONLY); + mapper.setVisibility(PropertyAccessor.IS_GETTER, Visibility.PUBLIC_ONLY); + if (prettyPrint) { + mapper.enable(SerializationFeature.INDENT_OUTPUT); + } + + log.debug("JSON object-mapper initialized"); + + } + + /* + * (non-Javadoc) + * + * @at.gv.egiz.eaaf.core.api.utils.IJsonMapper#getMapper() + */ + public ObjectMapper getMapper() { + return mapper; + + } + + /* + * (non-Javadoc) + * + * @see at.gv.egiz.eaaf.core.api.utils.IJsonMapper#serialize(java.lang.Object) + */ + @Override + public String serialize(final Object value) throws EaafJsonMapperException { + try { + return mapper.writeValueAsString(value); + + } catch (final JsonProcessingException e) { + log.warn("JSON mapping FAILED with error: {}", e.getMessage()); + throw new EaafJsonMapperException(e.getMessage(), e); + + } + + } + + /* + * (non-Javadoc) + * + * @see at.gv.egiz.eaaf.core.api.utils.IJsonMapper#deserialize(java.lang.String, + * java.lang.Class) + */ + @Override + public <T> Object deserialize(final String value, final Class<T> clazz) throws EaafJsonMapperException { + try { + if (clazz != null) { + if (clazz.isAssignableFrom(TypeReference.class)) { + return mapper.readValue(value, clazz); + } else { + final JavaType javaType = TypeFactory.defaultInstance().constructType(clazz); + return mapper.readValue(value, javaType); + + } + + } else { + return mapper.readValue(value, Object.class); + } + + } catch (final IOException e) { + log.warn("JSON mapping FAILED with error: {}", e.getMessage()); + throw new EaafJsonMapperException(e.getMessage(), e); + + } + + } + + @Override + public <T> Object deserialize(final InputStream is, final Class<T> clazz) throws EaafJsonMapperException { + try { + if (clazz != null) { + if (clazz.isAssignableFrom(TypeReference.class)) { + return mapper.readValue(is, clazz); + } else { + final JavaType javaType = TypeFactory.defaultInstance().constructType(clazz); + return mapper.readValue(is, javaType); + + } + + } else { + return mapper.readValue(is, Object.class); + } + + } catch (final IOException e) { + log.warn("JSON mapping FAILED with error: {}", e.getMessage()); + throw new EaafJsonMapperException(e.getMessage(), e); + + } + + } + } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java index c07c6081..1b1f090f 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java @@ -1,23 +1,36 @@ package at.gv.egiz.eaaf.modules.auth.sl20.utils; import java.io.IOException; -import java.net.MalformedURLException; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; -import java.security.PrivateKey; -import java.security.cert.Certificate; +import java.security.Provider; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; -import java.util.ArrayList; import java.util.Collections; -import java.util.Enumeration; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.PostConstruct; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exception.EaafKeyAccessException; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.utils.X509Utils; +import at.gv.egiz.eaaf.modules.auth.sl20.Constants; +import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20SecurityException; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoBuildException; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException; + import org.apache.commons.lang3.StringUtils; +import org.jose4j.jca.ProviderContext; import org.jose4j.jwa.AlgorithmConstraints; import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; import org.jose4j.jwe.JsonWebEncryption; @@ -37,384 +50,403 @@ import org.springframework.util.Base64Utils; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonNode; -import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException; -import at.gv.egiz.eaaf.core.impl.utils.FileUtils; -import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; -import at.gv.egiz.eaaf.core.impl.utils.X509Utils; -import at.gv.egiz.eaaf.modules.auth.sl20.Constants; -import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20SecurityException; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SLCommandoBuildException; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SLCommandoParserException; - @Service -public class JsonSecurityUtils implements IJOSETools{ - private static final Logger log = LoggerFactory.getLogger(JsonSecurityUtils.class); - - @Autowired(required=true) IConfiguration authConfig; - private Key signPrivKey = null; - private X509Certificate[] signCertChain = null; - - private Key encPrivKey = null; - private X509Certificate[] encCertChain = null; - - private List<X509Certificate> trustedCerts = new ArrayList<X509Certificate>(); - - private static JsonMapper mapper = new JsonMapper(); - - @PostConstruct - protected void initalize() { - log.info("Initialize SL2.0 authentication security constrains ... "); - try { - if (getKeyStoreFilePath() != null) { - final KeyStore keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(), - getKeyStorePassword()); - - //load signing key - signPrivKey = keyStore.getKey(getSigningKeyAlias(), getSigningKeyPassword().toCharArray()); - final Certificate[] certChainSigning = keyStore.getCertificateChain(getSigningKeyAlias()); - signCertChain = new X509Certificate[certChainSigning.length]; - for (int i=0; i<certChainSigning.length; i++) { - if (certChainSigning[i] instanceof X509Certificate) { - signCertChain[i] = (X509Certificate)certChainSigning[i]; - } else - log.warn("NO X509 certificate for signing: " + certChainSigning[i].getType()); - - } - - //load encryption key - try { - encPrivKey = keyStore.getKey(getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray()); - if (encPrivKey != null) { - final Certificate[] certChainEncryption = keyStore.getCertificateChain(getEncryptionKeyAlias()); - encCertChain = new X509Certificate[certChainEncryption.length]; - for (int i=0; i<certChainEncryption.length; i++) { - if (certChainEncryption[i] instanceof X509Certificate) { - encCertChain[i] = (X509Certificate)certChainEncryption[i]; - } else - log.warn("NO X509 certificate for encryption: " + certChainEncryption[i].getType()); - } - } else - log.info("No encryption key for SL2.0 found. End-to-End encryption is not used."); - - } catch (final Exception e) { - log.warn("No encryption key for SL2.0 found. End-to-End encryption is not used. Reason: " + e.getMessage(), e); - - } - - //load trusted certificates - trustedCerts = readCertsFromKeyStore(keyStore); - - //some short validation - if (signPrivKey == null || !(signPrivKey instanceof PrivateKey)) { - log.info("Can NOT open privateKey for SL2.0 signing. KeyStore=" + getKeyStoreFilePath()); - throw new SL20Exception("sl20.03", new Object[]{"Can NOT open private key for signing"}); - - } - - if (signCertChain == null || signCertChain.length == 0) { - log.info("NO certificate for SL2.0 signing. KeyStore=" + getKeyStoreFilePath()); - throw new SL20Exception("sl20.03", new Object[]{"NO certificate for SL2.0 signing"}); - - } - - log.info("SL2.0 authentication security constrains initialized."); - - } else - log.info("NO SL2.0 authentication security configuration. Initialization was skipped"); - - } catch ( final Exception e) { - log.error("SL2.0 security constrains initialization FAILED.", e); - - } - - } - - @Override - public String createSignature(String payLoad) throws SLCommandoBuildException { - try { - final JsonWebSignature jws = new JsonWebSignature(); - - //set payload - jws.setPayload(payLoad); - - //set basic header - jws.setContentTypeHeaderValue(SL20Constants.SL20_CONTENTTYPE_SIGNED_COMMAND); - - //set signing information - jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); - jws.setKey(signPrivKey); - - //TODO: - jws.setCertificateChainHeaderValue(signCertChain); - jws.setX509CertSha256ThumbprintHeaderValue(signCertChain[0]); - - return jws.getCompactSerialization(); - - } catch (final JoseException e) { - log.warn("Can NOT sign SL2.0 command.", e); - throw new SLCommandoBuildException("Can NOT sign SL2.0 command.", e); - - } - - } - - @Override - public VerificationResult validateSignature(String serializedContent, KeyStore trustStore, - AlgorithmConstraints algconstraints) throws JoseException, IOException, KeyStoreException { - final List<X509Certificate> trustedCertificates = readCertsFromKeyStore(trustStore); - return validateSignature(serializedContent, trustedCertificates , algconstraints); - - } - - @Override - @NonNull - public VerificationResult validateSignature(@Nonnull String serializedContent, @Nonnull List<X509Certificate> trustedCerts, @Nonnull AlgorithmConstraints constraints) throws JoseException, IOException { - final JsonWebSignature jws = new JsonWebSignature(); - //set payload - jws.setCompactSerialization(serializedContent); - - //set security constrains - jws.setAlgorithmConstraints(constraints); - - //load signinc certs - Key selectedKey = null; - final List<X509Certificate> x5cCerts = jws.getCertificateChainHeaderValue(); - final String x5t256 = jws.getX509CertSha256ThumbprintHeaderValue(); - if (x5cCerts != null) { - log.debug("Found x509 certificate in JOSE header ... "); - log.trace("Sorting received X509 certificates ... "); - final List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts); - - if (trustedCerts.contains(sortedX5cCerts.get(0))) { - selectedKey = sortedX5cCerts.get(0).getPublicKey(); - - } else { - log.info("Can NOT find JOSE certificate in truststore."); - try { - log.debug("Cert: " + Base64Utils.encodeToString(sortedX5cCerts.get(0).getEncoded())); - - } catch (final CertificateEncodingException e) { - e.printStackTrace(); - - } - - } - - } else if (StringUtils.isNotEmpty(x5t256)) { - log.debug("Found x5t256 fingerprint in JOSE header .... "); - final X509VerificationKeyResolver x509VerificationKeyResolver = new X509VerificationKeyResolver(trustedCerts); - selectedKey = x509VerificationKeyResolver.resolveKey(jws, Collections.<JsonWebStructure>emptyList()); - - } else { - throw new JoseException("JWS contains NO signature certificate or NO certificate fingerprint"); - - } - - if (selectedKey == null) { - throw new JoseException("Can NOT select verification key for JWS. Signature verification FAILED"); - - } - - //set verification key - jws.setKey(selectedKey); - - //load payLoad - return new VerificationResult(mapper.getMapper().readTree(jws.getPayload()), null, jws.verifySignature()) ; - - - } - - @Override - @Nonnull - public VerificationResult validateSignature(@Nonnull String serializedContent) throws SL20Exception { - try { - final AlgorithmConstraints algConstraints = new AlgorithmConstraints(ConstraintType.WHITELIST, - SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()])); - - final VerificationResult result = validateSignature(serializedContent, trustedCerts, algConstraints); - - if (!result.isValidSigned()) { - log.info("JWS signature invalide. Stopping authentication process ..."); - log.debug("Received JWS msg: " + serializedContent); - throw new SL20SecurityException("JWS signature invalide."); - - } - - log.debug("SL2.0 commando signature validation sucessfull"); - return result; - - } catch (JoseException | JsonParseException e) { - log.warn("SL2.0 commando signature validation FAILED", e); - throw new SL20SecurityException(new Object[]{e.getMessage()}, e); - - } catch (final IOException e) { - log.warn("Decrypted SL2.0 result can not be parsed.", e); - throw new SLCommandoParserException("Decrypted SL2.0 result can not be parsed", e); - - } - - } - - - @Override - public JsonNode decryptPayload(String compactSerialization) throws SL20Exception { - try { - final JsonWebEncryption receiverJwe = new JsonWebEncryption(); - - //set security constrains - receiverJwe.setAlgorithmConstraints( - new AlgorithmConstraints(ConstraintType.WHITELIST, - SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION.size()]))); - receiverJwe.setContentEncryptionAlgorithmConstraints( - new AlgorithmConstraints(ConstraintType.WHITELIST, - SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION.size()]))); - - //set payload - receiverJwe.setCompactSerialization(compactSerialization); - - - //validate key from header against key from config - final List<X509Certificate> x5cCerts = receiverJwe.getCertificateChainHeaderValue(); - final String x5t256 = receiverJwe.getX509CertSha256ThumbprintHeaderValue(); - if (x5cCerts != null) { - log.debug("Found x509 certificate in JOSE header ... "); - log.trace("Sorting received X509 certificates ... "); - final List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts); - - if (!sortedX5cCerts.get(0).equals(encCertChain[0])) { - log.info("Certificate from JOSE header does NOT match encryption certificate"); - log.debug("JOSE certificate: " + sortedX5cCerts.get(0).toString()); - - try { - log.debug("Cert: " + Base64Utils.encode(sortedX5cCerts.get(0).getEncoded())); - } catch (final CertificateEncodingException e) { - e.printStackTrace(); - } - throw new SL20Exception("sl20.05", new Object[]{"Certificate from JOSE header does NOT match encryption certificate"}); - } - - } else if (StringUtils.isNotEmpty(x5t256)) { - log.debug("Found x5t256 fingerprint in JOSE header .... "); - final String certFingerPrint = X509Util.x5tS256(encCertChain[0]); - if (!certFingerPrint.equals(x5t256)) { - log.info("X5t256 from JOSE header does NOT match encryption certificate"); - log.debug("X5t256 from JOSE header: " + x5t256 + " Encrytption cert: " + certFingerPrint); - throw new SL20Exception("sl20.05", new Object[]{"X5t256 from JOSE header does NOT match encryption certificate"}); - - } - - } else { - log.info("Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint"); - throw new SLCommandoParserException("Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint"); - - } - - //set key - receiverJwe.setKey(encPrivKey); - - - //decrypt payload - return mapper.getMapper().readTree(receiverJwe.getPlaintextString()); - - } catch (final JoseException e) { - log.warn("SL2.0 result decryption FAILED", e); - throw new SL20SecurityException(new Object[]{e.getMessage()}, e); - - } catch ( final JsonParseException e) { - log.warn("Decrypted SL2.0 result is NOT a valid JSON.", e); - throw new SLCommandoParserException("Decrypted SL2.0 result is NOT a valid JSON.", e); - - } catch (final IOException e) { - log.warn("Decrypted SL2.0 result can not be parsed.", e); - throw new SLCommandoParserException("Decrypted SL2.0 result can not be parsed", e); - } - - } - - - - @Override - public X509Certificate getEncryptionCertificate() { - //TODO: maybe update after SL2.0 update on encryption certificate parts - if (encCertChain !=null && encCertChain.length > 0) - return encCertChain[0]; - else - return null; - } - - private String getKeyStoreFilePath() throws EAAFConfigurationException, MalformedURLException { - return FileUtils.makeAbsoluteURL( - authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PATH), - authConfig.getConfigurationRootDirectory()); - } - - private String getKeyStorePassword() { - String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD); - if (value != null) - value = value.trim(); - - return value; - - } - - private String getSigningKeyAlias() { - String value = authConfig.getBasicConfiguration( - Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS).trim(); - if (value != null) - value = value.trim(); - - return value; - } - - private String getSigningKeyPassword() { - String value = authConfig.getBasicConfiguration( - Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD).trim(); - if (value != null) - value = value.trim(); - - return value; - } - - private String getEncryptionKeyAlias() { - String value = authConfig.getBasicConfiguration( - Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS).trim(); - if (value != null) - value = value.trim(); - - return value; - } - - private String getEncryptionKeyPassword() { - String value = authConfig.getBasicConfiguration( - Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD).trim(); - if (value != null) - value = value.trim(); - - return value; - } - - @Nonnull - private List<X509Certificate> readCertsFromKeyStore(@Nonnull KeyStore keyStore) throws KeyStoreException { - final List<X509Certificate> result = new ArrayList<>(); - - final Enumeration<String> aliases = keyStore.aliases(); - while(aliases.hasMoreElements()) { - final String el = aliases.nextElement(); - log.trace("Process TrustStoreEntry: " + el); - if (keyStore.isCertificateEntry(el)) { - final Certificate cert = keyStore.getCertificate(el); - if (cert != null && cert instanceof X509Certificate) - result.add((X509Certificate) cert); - else - log.info("Can not process entry: " + el + ". Reason: " + cert.toString()); - - } - } - - return Collections.unmodifiableList(result); - } - +public class JsonSecurityUtils implements IJoseTools { + private static final Logger log = LoggerFactory.getLogger(JsonSecurityUtils.class); + + private static final String FRIENDLYNAME_KEYSTORE = "SL2.0 KeyStore"; + private static final String FRIENDLYNAME_TRUSTSTORE = "SL2.0 TrustStore"; + + @Autowired(required = true) + IConfiguration authConfig; + @Autowired(required = true) + EaafKeyStoreFactory keystoreFactory; + + private Pair<KeyStore, Provider> keyStore; + private Pair<KeyStore, Provider> trustStore; + + private static JsonMapper mapper = new JsonMapper(); + + @PostConstruct + protected void initalize() throws SL20Exception { + log.info("Initialize SL2.0 authentication security constrains ... "); + try { + // load KeyStore + final KeyStoreConfiguration keyStoreConfig = buildKeyStoreConfiguration(); + keyStore = keystoreFactory.buildNewKeyStore(keyStoreConfig); + + // load TrustStore + final KeyStoreConfiguration trustStoreConfig = buildTrustStoreConfiguration(); + trustStore = keystoreFactory.buildNewKeyStore(trustStoreConfig); + + // validate KeyStore entries + EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore.getFirst(), getSigningKeyAlias(), + getSigningKeyPassword(), true, FRIENDLYNAME_KEYSTORE); + final Pair<Key, X509Certificate[]> encCredentials = + EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore.getFirst(), getEncryptionKeyAlias(), + getEncryptionKeyPassword(), false, FRIENDLYNAME_TRUSTSTORE); + if (encCredentials == null) { + log.info("No encryption key for SL2.0 found. End-to-End encryption is not used."); + + } + + // validate TrustStore + final List<X509Certificate> trustedCerts = EaafKeyStoreUtils.readCertsFromKeyStore(trustStore + .getFirst()); + if (trustedCerts.isEmpty()) { + log.info("No certificates in TrustStore: {}. Signature validation will FAIL!", + FRIENDLYNAME_TRUSTSTORE); + + } else { + log.info("Find #{} certificates in TrustStore: {}", + trustedCerts.size(), FRIENDLYNAME_TRUSTSTORE); + + } + + log.info("SL2.0 authentication security constrains initialized."); + + } catch (final RuntimeException e) { + throw e; + + } catch (final Exception e) { + log.error("SL2.0 security constrains initialization FAILED."); + throw new SL20Exception("sl20.11", new Object[] { e.getMessage() }, e); + + } + + } + + @Override + public String createSignature(final String payLoad) throws SlCommandoBuildException { + return createSignature(payLoad, true); + + } + + @Override + public String createSignature(final String payLoad, boolean addFullCertChain) throws SlCommandoBuildException { + try { + final JsonWebSignature jws = new JsonWebSignature(); + + // set payload + jws.setPayload(payLoad); + + // set basic header + jws.setContentTypeHeaderValue(SL20Constants.SL20_CONTENTTYPE_SIGNED_COMMAND); + + // set signing information + jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); + final Pair<Key, X509Certificate[]> signingCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates( + keyStore.getFirst(), getSigningKeyAlias(), getSigningKeyPassword(), true, FRIENDLYNAME_KEYSTORE); + jws.setKey(signingCred.getFirst()); + + // set special provider if required + if (keyStore.getSecond() != null) { + log.trace("Injecting special Java Security Provider: {}", keyStore.getSecond().getName()); + final ProviderContext providerCtx = new ProviderContext(); + providerCtx.getSuppliedKeyProviderContext().setSignatureProvider( + keyStore.getSecond().getName()); + jws.setProviderContext(providerCtx); + + } + + if (addFullCertChain) { + jws.setCertificateChainHeaderValue(signingCred.getSecond()); + + } + + jws.setX509CertSha256ThumbprintHeaderValue(signingCred.getSecond()[0]); + + return jws.getCompactSerialization(); + + } catch (final JoseException | EaafKeyAccessException e) { + log.warn("Can NOT sign SL2.0 command.", e); + throw new SlCommandoBuildException("Can NOT sign SL2.0 command.", e); + + } + + } + + @Override + public VerificationResult validateSignature(final String serializedContent, final KeyStore trustStore, + final AlgorithmConstraints algconstraints) throws JoseException, IOException, KeyStoreException { + final List<X509Certificate> trustedCertificates = EaafKeyStoreUtils.readCertsFromKeyStore(trustStore); + return validateSignature(serializedContent, trustedCertificates, algconstraints); + + } + + @Override + @NonNull + public VerificationResult validateSignature(@Nonnull final String serializedContent, + @Nonnull final List<X509Certificate> trustedCerts, @Nonnull final AlgorithmConstraints constraints) + throws JoseException, IOException { + final JsonWebSignature jws = new JsonWebSignature(); + // set payload + jws.setCompactSerialization(serializedContent); + + // set security constrains + jws.setAlgorithmConstraints(constraints); + + // load signinc certs + Key selectedKey = null; + final List<X509Certificate> x5cCerts = jws.getCertificateChainHeaderValue(); + final String x5t256 = jws.getX509CertSha256ThumbprintHeaderValue(); + if (x5cCerts != null) { + log.debug("Found x509 certificate in JOSE header ... "); + log.trace("Sorting received X509 certificates ... "); + final List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts); + + if (trustedCerts.contains(sortedX5cCerts.get(0))) { + selectedKey = sortedX5cCerts.get(0).getPublicKey(); + + } else { + log.info("Can NOT find JOSE certificate in truststore."); + try { + log.debug("Cert: " + Base64Utils.encodeToString(sortedX5cCerts.get(0).getEncoded())); + + } catch (final CertificateEncodingException e) { + e.printStackTrace(); + + } + + } + + } else if (StringUtils.isNotEmpty(x5t256)) { + log.debug("Found x5t256 fingerprint in JOSE header .... "); + final X509VerificationKeyResolver x509VerificationKeyResolver = new X509VerificationKeyResolver( + trustedCerts); + selectedKey = x509VerificationKeyResolver.resolveKey(jws, Collections.<JsonWebStructure>emptyList()); + + } else { + throw new JoseException("JWS contains NO signature certificate or NO certificate fingerprint"); + + } + + if (selectedKey == null) { + throw new JoseException("Can NOT select verification key for JWS. Signature verification FAILED"); + + } + + // set verification key + jws.setKey(selectedKey); + + // load payLoad + return new VerificationResult(mapper.getMapper().readTree(jws.getPayload()), null, jws.verifySignature()); + + } + + @Override + @Nonnull + public VerificationResult validateSignature(@Nonnull final String serializedContent) throws SL20Exception { + try { + final AlgorithmConstraints algConstraints = new AlgorithmConstraints(ConstraintType.WHITELIST, + SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING + .toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()])); + + final VerificationResult result = + validateSignature(serializedContent, EaafKeyStoreUtils.readCertsFromKeyStore(trustStore.getFirst()), + algConstraints); + + if (!result.isValidSigned()) { + log.info("JWS signature invalide. Stopping authentication process ..."); + log.debug("Received JWS msg: " + serializedContent); + throw new SL20SecurityException("JWS signature invalide."); + + } + + log.debug("SL2.0 commando signature validation sucessfull"); + return result; + + } catch (JoseException | JsonParseException | KeyStoreException e) { + log.warn("SL2.0 commando signature validation FAILED", e); + throw new SL20SecurityException(new Object[] { e.getMessage() }, e); + + } catch (final IOException e) { + log.warn("Decrypted SL2.0 result can not be parsed.", e); + throw new SlCommandoParserException("Decrypted SL2.0 result can not be parsed", e); + + } + + } + + @Override + public JsonNode decryptPayload(final String compactSerialization) throws SL20Exception { + try { + final JsonWebEncryption receiverJwe = new JsonWebEncryption(); + + // set security constrains + receiverJwe.setAlgorithmConstraints( + new AlgorithmConstraints(ConstraintType.WHITELIST, + SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION + .toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION.size()]))); + receiverJwe.setContentEncryptionAlgorithmConstraints( + new AlgorithmConstraints(ConstraintType.WHITELIST, SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION + .toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION.size()]))); + + // set payload + receiverJwe.setCompactSerialization(compactSerialization); + + final Pair<Key, X509Certificate[]> encryptionCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates( + keyStore.getFirst(), getEncryptionKeyAlias(), getEncryptionKeyPassword(), true, + FRIENDLYNAME_KEYSTORE); + + // validate key from header against key from config + final List<X509Certificate> x5cCerts = receiverJwe.getCertificateChainHeaderValue(); + final String x5t256 = receiverJwe.getX509CertSha256ThumbprintHeaderValue(); + if (x5cCerts != null) { + log.debug("Found x509 certificate in JOSE header ... "); + log.trace("Sorting received X509 certificates ... "); + final List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts); + + if (!sortedX5cCerts.get(0).equals(encryptionCred.getSecond()[0])) { + log.info("Certificate from JOSE header does NOT match encryption certificate"); + + try { + + log.debug("JOSE certificate: {}", Base64Utils.encode(sortedX5cCerts.get(0).getEncoded())); + } catch (final CertificateEncodingException e) { + e.printStackTrace(); + } + throw new SL20Exception("sl20.05", + new Object[] { "Certificate from JOSE header does NOT match encryption certificate" }); + } + + } else if (StringUtils.isNotEmpty(x5t256)) { + log.debug("Found x5t256 fingerprint in JOSE header .... "); + final String certFingerPrint = X509Util.x5tS256(encryptionCred.getSecond()[0]); + if (!certFingerPrint.equals(x5t256)) { + log.info("X5t256 from JOSE header does NOT match encryption certificate"); + log.debug("X5t256 from JOSE header: " + x5t256 + " Encrytption cert: " + certFingerPrint); + throw new SL20Exception("sl20.05", + new Object[] { "X5t256 from JOSE header does NOT match encryption certificate" }); + + } + + } else { + log.info("Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint"); + throw new SlCommandoParserException( + "Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint"); + + } + + // set key + receiverJwe.setKey(encryptionCred.getFirst()); + + // decrypt payload + return mapper.getMapper().readTree(receiverJwe.getPlaintextString()); + + } catch (final JoseException | EaafKeyAccessException e) { + log.warn("SL2.0 result decryption FAILED", e); + throw new SL20SecurityException(new Object[] { e.getMessage() }, e); + + } catch (final JsonParseException e) { + log.warn("Decrypted SL2.0 result is NOT a valid JSON.", e); + throw new SlCommandoParserException("Decrypted SL2.0 result is NOT a valid JSON.", e); + + } catch (final IOException e) { + log.warn("Decrypted SL2.0 result can not be parsed.", e); + throw new SlCommandoParserException("Decrypted SL2.0 result can not be parsed", e); + + } + } + + @Override + public X509Certificate getEncryptionCertificate() { + Pair<Key, X509Certificate[]> encryptionCred; + try { + encryptionCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore.getFirst(), + getEncryptionKeyAlias(), getEncryptionKeyPassword(), false, FRIENDLYNAME_KEYSTORE); + if (encryptionCred != null && encryptionCred.getSecond().length > 0) { + return encryptionCred.getSecond()[0]; + + } + + } catch (final EaafKeyAccessException e) { + log.trace("Exception is skipped because Encryption is not mandatory on this level", e); + + } + + return null; + + } + + private KeyStoreConfiguration buildKeyStoreConfiguration() throws EaafConfigurationException { + final KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName(FRIENDLYNAME_KEYSTORE); + + config.setKeyStoreType(authConfig.getBasicConfiguration( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_TYPE), + KeyStoreType.JKS.getKeyStoreType())); + config.setKeyStoreName( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_NAME)); + config.setSoftKeyStoreFilePath( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PATH)); + config.setSoftKeyStorePassword( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD)); + + // validate configuration state + config.validate(); + + return config; + + } + + private KeyStoreConfiguration buildTrustStoreConfiguration() throws EaafConfigurationException { + final KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName(FRIENDLYNAME_TRUSTSTORE); + + config.setKeyStoreType(authConfig.getBasicConfiguration( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE), + KeyStoreType.JKS.getKeyStoreType())); + config.setKeyStoreName( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_NAME)); + config.setSoftKeyStoreFilePath( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_PATH)); + config.setSoftKeyStorePassword( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_PASSWORD)); + + // validate configuration state + config.validate(); + + return config; + } + + private String getSigningKeyAlias() { + String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS); + if (value != null) { + value = value.trim(); + } + + return value; + } + + private char[] getSigningKeyPassword() { + final String value = authConfig.getBasicConfiguration( + Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD); + if (value != null) { + return value.trim().toCharArray(); + } + + return null; + } + + private String getEncryptionKeyAlias() { + String value = authConfig.getBasicConfiguration( + Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS); + if (value != null) { + value = value.trim(); + } + + return value; + } + + private char[] getEncryptionKeyPassword() { + final String value = authConfig.getBasicConfiguration( + Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD); + if (value != null) { + return value.trim().toCharArray(); + } + + return null; + } + } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20Constants.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20Constants.java index 06c36cff..01316b9b 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20Constants.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20Constants.java @@ -1,6 +1,7 @@ package at.gv.egiz.eaaf.modules.auth.sl20.utils; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers; @@ -8,234 +9,255 @@ import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers; import org.jose4j.jws.AlgorithmIdentifiers; public class SL20Constants { - public static final int CURRENT_SL20_VERSION = 10; - - //http binding parameters - public static final String PARAM_SL20_REQ_COMMAND_PARAM = "slcommand"; - public static final String PARAM_SL20_REQ_COMMAND_PARAM_OLD = "sl2command"; - - public static final String PARAM_SL20_REQ_ICP_RETURN_URL_PARAM = "slIPCReturnUrl"; - public static final String PARAM_SL20_REQ_TRANSACTIONID = "slTransactionID"; - - public static final String HTTP_HEADER_SL20_CLIENT_TYPE = "SL2ClientType"; - public static final String HTTP_HEADER_SL20_VDA_TYPE = "X-MOA-VDA"; - public static final String HTTP_HEADER_VALUE_NATIVE = "nativeApp"; - - public static final String HTTP_HEADER_SL20_RESP = "X-SL20Operation"; - - - //******************************************************************************************* - //JSON signing and encryption headers - public static final String JSON_ALGORITHM = "alg"; - public static final String JSON_CONTENTTYPE = "cty"; - public static final String JSON_X509_CERTIFICATE = "x5c"; - public static final String JSON_X509_FINGERPRINT = "x5t#S256"; - public static final String JSON_ENCRYPTION_PAYLOAD = "enc"; - - public static final String JSON_ALGORITHM_SIGNING_RS256 = AlgorithmIdentifiers.RSA_USING_SHA256; - public static final String JSON_ALGORITHM_SIGNING_RS512 = AlgorithmIdentifiers.RSA_USING_SHA512; - public static final String JSON_ALGORITHM_SIGNING_ES256 = AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256; - public static final String JSON_ALGORITHM_SIGNING_ES512 = AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512; - public static final String JSON_ALGORITHM_SIGNING_PS256 = AlgorithmIdentifiers.RSA_PSS_USING_SHA256; - public static final String JSON_ALGORITHM_SIGNING_PS512 = AlgorithmIdentifiers.RSA_PSS_USING_SHA512; - - public static final List<String> SL20_ALGORITHM_WHITELIST_SIGNING = Arrays.asList( - JSON_ALGORITHM_SIGNING_RS256, - JSON_ALGORITHM_SIGNING_RS512, - JSON_ALGORITHM_SIGNING_ES256, - JSON_ALGORITHM_SIGNING_ES512, - JSON_ALGORITHM_SIGNING_PS256, - JSON_ALGORITHM_SIGNING_PS512 - ); - - public static final String JSON_ALGORITHM_ENC_KEY_RSAOAEP = KeyManagementAlgorithmIdentifiers.RSA_OAEP; - public static final String JSON_ALGORITHM_ENC_KEY_RSAOAEP256 = KeyManagementAlgorithmIdentifiers.RSA_OAEP_256; - - public static final List<String> SL20_ALGORITHM_WHITELIST_KEYENCRYPTION = Arrays.asList( - JSON_ALGORITHM_ENC_KEY_RSAOAEP, - JSON_ALGORITHM_ENC_KEY_RSAOAEP256 - ); - - public static final String JSON_ALGORITHM_ENC_PAYLOAD_A128CBCHS256 = ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256; - public static final String JSON_ALGORITHM_ENC_PAYLOAD_A256CBCHS512 = ContentEncryptionAlgorithmIdentifiers.AES_256_CBC_HMAC_SHA_512; - public static final String JSON_ALGORITHM_ENC_PAYLOAD_A128GCM = ContentEncryptionAlgorithmIdentifiers.AES_128_GCM; - public static final String JSON_ALGORITHM_ENC_PAYLOAD_A256GCM = ContentEncryptionAlgorithmIdentifiers.AES_256_GCM; - - public static final List<String> SL20_ALGORITHM_WHITELIST_ENCRYPTION = Arrays.asList( - JSON_ALGORITHM_ENC_PAYLOAD_A128CBCHS256, - JSON_ALGORITHM_ENC_PAYLOAD_A256CBCHS512, - JSON_ALGORITHM_ENC_PAYLOAD_A128GCM, - JSON_ALGORITHM_ENC_PAYLOAD_A256GCM - ); - - - //********************************************************************************************* - //Object identifier for generic transport container - public static final String SL20_CONTENTTYPE_SIGNED_COMMAND ="application/sl2.0;command"; - public static final String SL20_CONTENTTYPE_ENCRYPTED_RESULT ="application/sl2.0;result"; - - public static final String SL20_VERSION = "v"; - public static final String SL20_REQID = "reqID"; - public static final String SL20_RESPID = "respID"; - public static final String SL20_INRESPTO = "inResponseTo"; - public static final String SL20_TRANSACTIONID = "transactionID"; - public static final String SL20_PAYLOAD = "payload"; - public static final String SL20_SIGNEDPAYLOAD = "signedPayload"; - - //Generic Object identifier for commands - public static final String SL20_COMMAND_CONTAINER_NAME = "name"; - public static final String SL20_COMMAND_CONTAINER_PARAMS = "params"; - public static final String SL20_COMMAND_CONTAINER_RESULT = "result"; - public static final String SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT = "encryptedResult"; - - //COMMAND Object identifier - public static final String SL20_COMMAND_IDENTIFIER_REDIRECT = "redirect"; - public static final String SL20_COMMAND_IDENTIFIER_CALL = "call"; - public static final String SL20_COMMAND_IDENTIFIER_ERROR = "error"; - @Deprecated public static final String SL20_COMMAND_IDENTIFIER_QUALIFIEDEID = "qualifiedeID"; - public static final String SL20_COMMAND_IDENTIFIER_QUALIFIEDEIDCONSENT = "qualifiedEIDConsent"; - //public static final String SL20_COMMAND_IDENTIFIER_QUALIFIEDSIG = "qualifiedSig"; - - public static final String SL20_COMMAND_IDENTIFIER_GETCERTIFICATE = "getCertificate"; - public static final String SL20_COMMAND_IDENTIFIER_CREATE_SIG_CADES = "createCAdES"; - - - public static final String SL20_COMMAND_IDENTIFIER_BINDING_CREATE_KEY = "createBindingKey"; - public static final String SL20_COMMAND_IDENTIFIER_BINDING_STORE_CERT = "storeBindingCert"; - - public static final String SL20_COMMAND_IDENTIFIER_AUTH_IDANDPASSWORD = "idAndPassword"; - public static final String SL20_COMMAND_IDENTIFIER_AUTH_JWSTOKENFACTOR = "jwsTokenAuth"; - public static final String SL20_COMMAND_IDENTIFIER_AUTH_QRCODEFACTOR = "qrCodeFactor"; - - //*****COMMAND parameter identifier****** - //general Identifier - public static final String SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_VALUE = "value"; - public static final String SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_KEY = "key"; - public static final String SL20_COMMAND_PARAM_GENERAL_DATAURL = "dataUrl"; - public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE = "x5cEnc"; - public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK = "jwkEnc"; - - //Redirect command - public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL = "url"; - public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND = "command"; - public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND = "signedCommand"; - public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_IPCREDIRECT = "IPCRedirect"; - - //Call command - public static final String SL20_COMMAND_PARAM_GENERAL_CALL_URL = SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL; - public static final String SL20_COMMAND_PARAM_GENERAL_CALL_METHOD = "method"; - public static final String SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET = "get"; - public static final String SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_POST = "post"; - public static final String SL20_COMMAND_PARAM_GENERAL_CALL_INCLUDETRANSACTIONID = "includeTransactionID"; - public static final String SL20_COMMAND_PARAM_GENERAL_CALL_REQPARAMETER = "reqParams"; - - //error command - public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE = "errorCode"; - public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE = "errorMessage"; - - //qualified eID command - @Deprecated public static final String SL20_COMMAND_PARAM_EID_AUTHBLOCKID = "authBlockTemplateID"; - public static final String SL20_COMMAND_PARAM_EID_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; - @Deprecated public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES = "attributes"; - @Deprecated public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_MANDATEREFVALUE = "MANDATE-REFERENCE-VALUE"; - @Deprecated public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID = "SP-UNIQUEID"; - @Deprecated public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME = "SP-FRIENDLYNAME"; - @Deprecated public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPCOUNTRYCODE = "SP-COUNTRYCODE"; - public static final String SL20_COMMAND_PARAM_EID_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; - public static final String SL20_COMMAND_PARAM_EID_JWKCENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK; - @Deprecated public static final String SL20_COMMAND_PARAM_EID_RESULT_IDL = "EID-IDENTITY-LINK"; - @Deprecated public static final String SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK = "EID-AUTH-BLOCK"; - public static final String SL20_COMMAND_PARAM_EID_RESULT_CCSURL = "EID-CCS-URL"; - @Deprecated public static final String SL20_COMMAND_PARAM_EID_RESULT_LOA = "EID-CITIZEN-QAA-LEVEL"; - - public static final String SL20_COMMAND_PARAM_EID_CONSENTTEMPLATEID = "consentTemplateID"; - public static final String SL20_COMMAND_PARAM_EID_CONSENT = "consent"; - public static final String SL20_COMMAND_PARAM_EID_CONSENT_RESULT_MDS = "MDS"; - public static final String SL20_COMMAND_PARAM_EID_CONSENT_RESULT_VSZ = "vSZ"; - public static final String SL20_COMMAND_PARAM_EID_CONSENT_RESULT_SIGNEDCONSENT = "signedConsent"; - - //qualified Signature comamnd -// public static final String SL20_COMMAND_PARAM_QUALSIG_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; -// public static final String SL20_COMMAND_PARAM_QUALSIG_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; - - - //getCertificate - public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_KEYID = "keyId"; - public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; - public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; - public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_JWKCENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK; - public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_RESULT_CERTIFICATE = "x5c"; - - //createCAdES Signture - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_KEYID = "keyId"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CONTENT = "content"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_MIMETYPE = "mimeType"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_PADES_COMBATIBILTY = "padesComatibility"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_EXCLUDEBYTERANGE = "excludedByteRange"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL = "cadesLevel"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_JWKCENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_RESULT_SIGNATURE = "signature"; - - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_BASIC = "cAdES"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_T = "cAdES-T"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_C = "cAdES-C"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_X = "cAdES-X"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_XL = "cAdES-X-L"; - public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_A = "cAdES-A"; - - - - //create binding key command - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KONTOID = "kontoID"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_SN = "SN"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYLENGTH = "keyLength"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG = "keyAlg"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES = "policies"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_X5CVDATRUST = "x5cVdaTrust"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_REQUESTUSERPASSWORD = "reqUserPassword"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; - - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG_RSA = "RSA"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG_SECPR256R1 = "secp256r1"; - - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_LIFETIME = "lifeTime"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_USESECUREELEMENT = "useSecureElement"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_KEYTIMEOUT = "keyTimeout"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_NEEDUSERAUTH = "needUserAuth"; - - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_APPID = "appID"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_CSR = "csr"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_KEYATTESTATIONZERTIFICATE = "attCert"; - public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_USERPASSWORD = "encodedPass"; - - - //store binding certificate command - public static final String SL20_COMMAND_PARAM_BINDING_STORE_CERTIFICATE = "x5c"; - public static final String SL20_COMMAND_PARAM_BINDING_STORE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; - public static final String SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS = "success"; - public static final String SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS_VALUE = "OK"; - - // Username and password authentication - public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG = "keyAlg"; - public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG_VALUE_PLAIN = "plain"; - public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG_VALUE_PBKDF2 = "PBKDF2"; - public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; - public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; - public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_KONTOID = SL20_COMMAND_PARAM_BINDING_CREATE_KONTOID; - public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_USERPASSWORD = SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_USERPASSWORD; - - //JWS Token authentication - public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_NONCE = "nonce"; - public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYDATA = "displayData"; - public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYURL = "displayUrl"; - public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; - public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_RESULT_NONCE = SL20_COMMAND_PARAM_AUTH_JWSTOKEN_NONCE; - - //QR-Code authentication - public static final String SL20_COMMAND_PARAM_AUTH_QRCODE_QRCODE = "qrCode"; - public static final String SL20_COMMAND_PARAM_AUTH_QRCODE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; - + public static final int CURRENT_SL20_VERSION = 10; + + // http binding parameters + public static final String PARAM_SL20_REQ_COMMAND_PARAM = "slcommand"; + public static final String PARAM_SL20_REQ_COMMAND_PARAM_OLD = "sl2command"; + + public static final String PARAM_SL20_REQ_ICP_RETURN_URL_PARAM = "slIPCReturnUrl"; + public static final String PARAM_SL20_REQ_TRANSACTIONID = "slTransactionID"; + + public static final String HTTP_HEADER_SL20_CLIENT_TYPE = "SL2ClientType"; + public static final String HTTP_HEADER_SL20_VDA_TYPE = "X-MOA-VDA"; + public static final String HTTP_HEADER_VALUE_NATIVE = "nativeApp"; + + public static final String HTTP_HEADER_SL20_RESP = "X-SL20Operation"; + + // ******************************************************************************************* + // JSON signing and encryption headers + public static final String JSON_ALGORITHM = "alg"; + public static final String JSON_CONTENTTYPE = "cty"; + public static final String JSON_X509_CERTIFICATE = "x5c"; + public static final String JSON_X509_FINGERPRINT = "x5t#S256"; + public static final String JSON_ENCRYPTION_PAYLOAD = "enc"; + + public static final String JSON_ALGORITHM_SIGNING_RS256 = AlgorithmIdentifiers.RSA_USING_SHA256; + public static final String JSON_ALGORITHM_SIGNING_RS512 = AlgorithmIdentifiers.RSA_USING_SHA512; + public static final String JSON_ALGORITHM_SIGNING_ES256 = + AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256; + public static final String JSON_ALGORITHM_SIGNING_ES512 = + AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512; + public static final String JSON_ALGORITHM_SIGNING_PS256 = AlgorithmIdentifiers.RSA_PSS_USING_SHA256; + public static final String JSON_ALGORITHM_SIGNING_PS512 = AlgorithmIdentifiers.RSA_PSS_USING_SHA512; + + public static final List<String> SL20_ALGORITHM_WHITELIST_SIGNING = Collections.unmodifiableList( + Arrays.asList(JSON_ALGORITHM_SIGNING_RS256, JSON_ALGORITHM_SIGNING_RS512, JSON_ALGORITHM_SIGNING_ES256, + JSON_ALGORITHM_SIGNING_ES512, JSON_ALGORITHM_SIGNING_PS256, JSON_ALGORITHM_SIGNING_PS512)); + + public static final String JSON_ALGORITHM_ENC_KEY_RSAOAEP = KeyManagementAlgorithmIdentifiers.RSA_OAEP; + public static final String JSON_ALGORITHM_ENC_KEY_RSAOAEP256 = + KeyManagementAlgorithmIdentifiers.RSA_OAEP_256; + + public static final List<String> SL20_ALGORITHM_WHITELIST_KEYENCRYPTION = Collections + .unmodifiableList(Arrays.asList(JSON_ALGORITHM_ENC_KEY_RSAOAEP, JSON_ALGORITHM_ENC_KEY_RSAOAEP256)); + + public static final String JSON_ALGORITHM_ENC_PAYLOAD_A128CBCHS256 = + ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256; + public static final String JSON_ALGORITHM_ENC_PAYLOAD_A256CBCHS512 = + ContentEncryptionAlgorithmIdentifiers.AES_256_CBC_HMAC_SHA_512; + public static final String JSON_ALGORITHM_ENC_PAYLOAD_A128GCM = + ContentEncryptionAlgorithmIdentifiers.AES_128_GCM; + public static final String JSON_ALGORITHM_ENC_PAYLOAD_A256GCM = + ContentEncryptionAlgorithmIdentifiers.AES_256_GCM; + + public static final List<String> SL20_ALGORITHM_WHITELIST_ENCRYPTION = Collections + .unmodifiableList(Arrays.asList(JSON_ALGORITHM_ENC_PAYLOAD_A128CBCHS256, + JSON_ALGORITHM_ENC_PAYLOAD_A256CBCHS512, + JSON_ALGORITHM_ENC_PAYLOAD_A128GCM, JSON_ALGORITHM_ENC_PAYLOAD_A256GCM)); + + // ********************************************************************************************* + // Object identifier for generic transport container + public static final String SL20_CONTENTTYPE_SIGNED_COMMAND = "application/sl2.0;command"; + public static final String SL20_CONTENTTYPE_ENCRYPTED_RESULT = "application/sl2.0;result"; + + public static final String SL20_VERSION = "v"; + public static final String SL20_REQID = "reqID"; + public static final String SL20_RESPID = "respID"; + public static final String SL20_INRESPTO = "inResponseTo"; + public static final String SL20_TRANSACTIONID = "transactionID"; + public static final String SL20_PAYLOAD = "payload"; + public static final String SL20_SIGNEDPAYLOAD = "signedPayload"; + + // Generic Object identifier for commands + public static final String SL20_COMMAND_CONTAINER_NAME = "name"; + public static final String SL20_COMMAND_CONTAINER_PARAMS = "params"; + public static final String SL20_COMMAND_CONTAINER_RESULT = "result"; + public static final String SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT = "encryptedResult"; + + // COMMAND Object identifier + public static final String SL20_COMMAND_IDENTIFIER_REDIRECT = "redirect"; + public static final String SL20_COMMAND_IDENTIFIER_CALL = "call"; + public static final String SL20_COMMAND_IDENTIFIER_ERROR = "error"; + @Deprecated + public static final String SL20_COMMAND_IDENTIFIER_QUALIFIEDEID = "qualifiedeID"; + public static final String SL20_COMMAND_IDENTIFIER_QUALIFIEDEIDCONSENT = "qualifiedEIDConsent"; + // public static final String SL20_COMMAND_IDENTIFIER_QUALIFIEDSIG = + // "qualifiedSig"; + + public static final String SL20_COMMAND_IDENTIFIER_GETCERTIFICATE = "getCertificate"; + public static final String SL20_COMMAND_IDENTIFIER_CREATE_SIG_CADES = "createCAdES"; + + public static final String SL20_COMMAND_IDENTIFIER_BINDING_CREATE_KEY = "createBindingKey"; + public static final String SL20_COMMAND_IDENTIFIER_BINDING_STORE_CERT = "storeBindingCert"; + + public static final String SL20_COMMAND_IDENTIFIER_AUTH_IDANDPASSWORD = "idAndPassword"; + public static final String SL20_COMMAND_IDENTIFIER_AUTH_JWSTOKENFACTOR = "jwsTokenAuth"; + public static final String SL20_COMMAND_IDENTIFIER_AUTH_QRCODEFACTOR = "qrCodeFactor"; + + // *****COMMAND parameter identifier****** + // general Identifier + public static final String SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_VALUE = "value"; + public static final String SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_KEY = "key"; + public static final String SL20_COMMAND_PARAM_GENERAL_DATAURL = "dataUrl"; + public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE = "x5cEnc"; + public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK = "jwkEnc"; + + // Redirect command + public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL = "url"; + public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND = "command"; + public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND = "signedCommand"; + public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_IPCREDIRECT = "IPCRedirect"; + + // Call command + public static final String SL20_COMMAND_PARAM_GENERAL_CALL_URL = SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL; + public static final String SL20_COMMAND_PARAM_GENERAL_CALL_METHOD = "method"; + public static final String SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET = "get"; + public static final String SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_POST = "post"; + public static final String SL20_COMMAND_PARAM_GENERAL_CALL_INCLUDETRANSACTIONID = "includeTransactionID"; + public static final String SL20_COMMAND_PARAM_GENERAL_CALL_REQPARAMETER = "reqParams"; + + // error command + public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE = "errorCode"; + public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE = "errorMessage"; + + // qualified eID command + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_AUTHBLOCKID = "authBlockTemplateID"; + public static final String SL20_COMMAND_PARAM_EID_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES = "attributes"; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_MANDATEREFVALUE = "MANDATE-REFERENCE-VALUE"; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID = "SP-UNIQUEID"; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME = "SP-FRIENDLYNAME"; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPCOUNTRYCODE = "SP-COUNTRYCODE"; + public static final String SL20_COMMAND_PARAM_EID_X5CENC = + SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; + public static final String SL20_COMMAND_PARAM_EID_JWKCENC = + SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_RESULT_IDL = "EID-IDENTITY-LINK"; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK = "EID-AUTH-BLOCK"; + public static final String SL20_COMMAND_PARAM_EID_RESULT_CCSURL = "EID-CCS-URL"; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_RESULT_LOA = "EID-CITIZEN-QAA-LEVEL"; + + public static final String SL20_COMMAND_PARAM_EID_CONSENTTEMPLATEID = "consentTemplateID"; + public static final String SL20_COMMAND_PARAM_EID_CONSENT = "consent"; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_CONSENT_RESULT_MDS = "MDS"; + @Deprecated + public static final String SL20_COMMAND_PARAM_EID_CONSENT_RESULT_VSZ = "vSZ"; + public static final String SL20_COMMAND_PARAM_EID_CONSENT_RESULT_SIGNEDCONSENT = "signedConsent"; + public static final String SL20_COMMAND_PARAM_EID_CONSENT_RESULT_QCBIND = "qcBind"; + + // qualified Signature comamnd + // public static final String SL20_COMMAND_PARAM_QUALSIG_DATAURL = + // SL20_COMMAND_PARAM_GENERAL_DATAURL; + // public static final String SL20_COMMAND_PARAM_QUALSIG_X5CENC = + // SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; + + // getCertificate + public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_KEYID = "keyId"; + public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; + public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_X5CENC = + SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; + public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_JWKCENC = + SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK; + public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_RESULT_CERTIFICATE = "x5c"; + + // createCAdES Signture + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_KEYID = "keyId"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CONTENT = "content"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_MIMETYPE = "mimeType"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_PADES_COMBATIBILTY = "padesComatibility"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_EXCLUDEBYTERANGE = "excludedByteRange"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL = "cadesLevel"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_X5CENC = + SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_JWKCENC = + SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_RESULT_SIGNATURE = "signature"; + + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_BASIC = "cAdES"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_T = "cAdES-T"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_C = "cAdES-C"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_X = "cAdES-X"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_XL = "cAdES-X-L"; + public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_A = "cAdES-A"; + + // create binding key command + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KONTOID = "kontoID"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_SN = "SN"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYLENGTH = "keyLength"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG = "keyAlg"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES = "policies"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_X5CVDATRUST = "x5cVdaTrust"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_REQUESTUSERPASSWORD = "reqUserPassword"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_X5CENC = + SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; + + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG_RSA = "RSA"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG_SECPR256R1 = "secp256r1"; + + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_LIFETIME = "lifeTime"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_USESECUREELEMENT = "useSecureElement"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_KEYTIMEOUT = "keyTimeout"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_NEEDUSERAUTH = "needUserAuth"; + + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_APPID = "appID"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_CSR = "csr"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_KEYATTESTATIONZERTIFICATE = "attCert"; + public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_USERPASSWORD = "encodedPass"; + + // store binding certificate command + public static final String SL20_COMMAND_PARAM_BINDING_STORE_CERTIFICATE = "x5c"; + public static final String SL20_COMMAND_PARAM_BINDING_STORE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; + public static final String SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS = "success"; + public static final String SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS_VALUE = "OK"; + + // Username and password authentication + public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG = "keyAlg"; + public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG_VALUE_PLAIN = "plain"; + public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG_VALUE_PBKDF2 = "PBKDF2"; + public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_DATAURL = + SL20_COMMAND_PARAM_GENERAL_DATAURL; + public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_X5CENC = + SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; + public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_KONTOID = + SL20_COMMAND_PARAM_BINDING_CREATE_KONTOID; + public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_USERPASSWORD = + SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_USERPASSWORD; + + // JWS Token authentication + public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_NONCE = "nonce"; + public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYDATA = "displayData"; + public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYURL = "displayUrl"; + public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; + public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_RESULT_NONCE = + SL20_COMMAND_PARAM_AUTH_JWSTOKEN_NONCE; + + // QR-Code authentication + public static final String SL20_COMMAND_PARAM_AUTH_QRCODE_QRCODE = "qrCode"; + public static final String SL20_COMMAND_PARAM_AUTH_QRCODE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; + + + } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java index 4d8cabb7..1d7c9646 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java @@ -18,46 +18,47 @@ import org.springframework.http.MediaType; import com.fasterxml.jackson.databind.JsonNode; public class SL20HttpBindingUtils { - private static final Logger log = LoggerFactory.getLogger(SL20HttpBindingUtils.class); - - /** - * Write SL2.0 response into http-response object - * - * @param httpReq Current http request - * @param httpResp Current http response - * @param sl20Forward SL2.0 command that should be written to response - * @param redirectURL SL2.0 redirect URL in case of SL2.0 redirect command and no native client (see SL2.0 specification) - * @param httpCodeRedirect http redirect-code in case of SL2.0 redirect command and no native client (see SL2.0 specification) - * @throws IOException - * @throws URISyntaxException - */ - public static void writeIntoResponse(@Nonnull HttpServletRequest httpReq, @Nonnull HttpServletResponse httpResp, - @Nonnull JsonNode sl20Forward, @Nullable String redirectURL, - @Nonnull int httpCodeRedirect) throws IOException, URISyntaxException { - //forward SL2.0 command - httpResp.addIntHeader(SL20Constants.HTTP_HEADER_SL20_RESP, SL20Constants.CURRENT_SL20_VERSION); - - if (httpReq.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null && - httpReq.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) { - log.debug("Client request containts 'native client' header ... "); - final StringWriter writer = new StringWriter(); - writer.write(sl20Forward.toString()); - final byte[] content = writer.toString().getBytes("UTF-8"); - httpResp.setStatus(HttpServletResponse.SC_OK); - httpResp.setContentLength(content.length); - httpResp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); - httpResp.getOutputStream().write(content); - - } else { - log.debug("Client request containts is no native client ... "); - final URIBuilder clientRedirectURI = new URIBuilder(redirectURL); - clientRedirectURI.addParameter( - SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, - Base64Url.encode(sl20Forward.toString().getBytes())); - httpResp.setStatus(httpCodeRedirect); - httpResp.setHeader("Location", clientRedirectURI.build().toString()); - - } - - } + private static final Logger log = LoggerFactory.getLogger(SL20HttpBindingUtils.class); + + /** + * Write SL2.0 response into http-response object + * + * @param httpReq Current http request + * @param httpResp Current http response + * @param sl20Forward SL2.0 command that should be written to response + * @param redirectUrl SL2.0 redirect URL in case of SL2.0 redirect command + * and no native client (see SL2.0 specification) + * @param httpCodeRedirect http redirect-code in case of SL2.0 redirect command + * and no native client (see SL2.0 specification) + * @throws IOException In case of an IO error + * @throws URISyntaxException In case of a wrong URL + */ + public static void writeIntoResponse(@Nonnull final HttpServletRequest httpReq, + @Nonnull final HttpServletResponse httpResp, @Nonnull final JsonNode sl20Forward, + @Nullable final String redirectUrl, @Nonnull final int httpCodeRedirect) throws IOException, URISyntaxException { + // forward SL2.0 command + httpResp.addIntHeader(SL20Constants.HTTP_HEADER_SL20_RESP, SL20Constants.CURRENT_SL20_VERSION); + + if (httpReq.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null && httpReq + .getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) { + log.debug("Client request containts 'native client' header ... "); + final StringWriter writer = new StringWriter(); + writer.write(sl20Forward.toString()); + final byte[] content = writer.toString().getBytes("UTF-8"); + httpResp.setStatus(HttpServletResponse.SC_OK); + httpResp.setContentLength(content.length); + httpResp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + httpResp.getOutputStream().write(content); + + } else { + log.debug("Client request containts is no native client ... "); + final URIBuilder clientRedirectUri = new URIBuilder(redirectUrl); + clientRedirectUri.addParameter(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, + Base64Url.encode(sl20Forward.toString().getBytes("UTF-8"))); + httpResp.setStatus(httpCodeRedirect); + httpResp.setHeader("Location", clientRedirectUri.build().toString()); + + } + + } } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JSONBuilderUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JSONBuilderUtils.java deleted file mode 100644 index ba069ac7..00000000 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JSONBuilderUtils.java +++ /dev/null @@ -1,640 +0,0 @@ -package at.gv.egiz.eaaf.modules.auth.sl20.utils; - -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 - * @param params - * @throws SLCommandoBuildException - * @return - */ - public static ObjectNode createCommand(String name, 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 - * @param params - * @param signer - * @return - * @throws SLCommandoBuildException - */ - public static String createSignedCommand(String name, ObjectNode params, 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 - * @param encrypter - * @return - * @throws SLCommandoBuildException - */ - public static String createEncryptedCommandoResult(ObjectNode result, JsonSecurityUtils encrypter) throws SLCommandoBuildException { - //TODO: add real implementation - //create header and footer - final String dummyHeader = createJsonEncryptionHeader(encrypter).toString(); - final String payLoad = result.toString(); - final String dummyFooter = createJsonSignedFooter(encrypter); - - return Base64.getUrlEncoder().encodeToString(dummyHeader.getBytes()) + "." - + Base64.getUrlEncoder().encodeToString(payLoad.getBytes()) + "." - + Base64.getUrlEncoder().encodeToString(dummyFooter.getBytes()); - - } - - - /** - * Create command result - * - * @param name - * @param result - * @param encryptedResult - * @throws SLCommandoBuildException - * @return - */ - public static ObjectNode createCommandResponse(String name, ObjectNode result, 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 command result - * - * @param name - * @param result - * @param encryptedResult - * @throws SLCommandoBuildException - * @return - */ - public static String createSignedCommandResponse(String name, ObjectNode result, String encryptedResult, 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(signer).toString(); - final String dummyFooter = createJsonSignedFooter(signer); - - return Base64.getUrlEncoder().encodeToString(dummyHeader.getBytes()) + "." - + Base64.getUrlEncoder().encodeToString(encodedCommand.getBytes()) + "." - + Base64.getUrlEncoder().encodeToString(dummyFooter.getBytes()); - - } - - /** - * Create parameters for Redirect command - * - * @param url - * @param command - * @param signedCommand - * @param ipcRedirect - * @return - * @throws SLCommandoBuildException - */ - public static ObjectNode createRedirectCommandParameters(String url, ObjectNode command, ObjectNode signedCommand, 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 - * @param method - * @param includeTransactionId - * @param reqParameters - * @return - * @throws SLCommandoBuildException - */ - public static ObjectNode createCallCommandParameters(String url, String method, Boolean includeTransactionId, Map<String, String> 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 - * @param errorMsg - * @return - * @throws SLCommandoBuildException - */ - public static ObjectNode createErrorCommandResult(String errorCode, 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 - * @param additionalReqParameters - * @param x5cEnc - * @return - * @throws CertificateEncodingException - * @throws SLCommandoBuildException - */ - public static ObjectNode createQualifiedeEIDConsent(String consentTemplateId, byte[] consent, String dataUrl, - 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 - * @param dataUrl - * @param additionalReqParameters - * @param x5cEnc - * @return - * @throws CertificateEncodingException - * @throws SLCommandoBuildException - */ - @Deprecated - public static ObjectNode createQualifiedeIDCommandParameters(String authBlockId, String dataUrl, - Map<String, String> additionalReqParameters, 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 - * @param authBlock - * @param ccsURL - * @param LoA - * @return - * @throws SLCommandoBuildException - */ - public static ObjectNode createQualifiedeIDCommandResult(byte[] idl, byte[] authBlock, String ccsURL, 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 - * @param subjectName - * @param keySize - * @param keyAlg - * @param policies - * @param dataUrl - * @param x5cVdaTrust - * @param reqUserPassword - * @param x5cEnc - * @return - * @throws SLCommandoBuildException - * @throws CertificateEncodingException - */ - public static ObjectNode createBindingKeyCommandParams(String kontoId, String subjectName, int keySize, String keyAlg, - Map<String, String> policies, String dataUrl, X509Certificate x5cVdaTrust, Boolean reqUserPassword, 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 - * @param csr - * @param attCert - * @param password - * @return - * @throws SLCommandoBuildException - * @throws CertificateEncodingException - */ - public static ObjectNode createBindingKeyCommandResult(String appId, byte[] csr, X509Certificate attCert, 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 - * @param dataUrl - * @return - * @throws CertificateEncodingException - * @throws SLCommandoBuildException - */ - public static ObjectNode createStoreBindingCertCommandParams(X509Certificate cert, 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 - * @throws SLCommandoBuildException - */ - 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 - * @param dataUrl - * @param x5cEnc - * @return - * @throws SLCommandoBuildException - * @throws CertificateEncodingException - */ - public static ObjectNode createIdAndPasswordCommandParameters(String keyAlg, String dataUrl, 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 - * @param password - * @return - * @throws SLCommandoBuildException - */ - public static ObjectNode createIdAndPasswordCommandResult(String kontoId, 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 - * @param dataUrl - * @param displayData - * @param displayUrl - * @return - * @throws SLCommandoBuildException - */ - public static ObjectNode createJwsTokenAuthCommandParams(String nonce, String dataUrl, List<String> displayData, List<String> 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 - * @return - * @throws SLCommandoBuildException - */ - public static ObjectNode createJwsTokenAuthCommandResult(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 - * @param transactionId - * @param payLoad - * @param signedPayload - * @return - * @throws SLCommandoBuildException - */ - public static ObjectNode createGenericRequest(String reqId, String transactionId, ObjectNode payLoad, 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 - * @param inResponseTo - * @param transactionId - * @param payLoad - * @param signedPayload - * @return - * @throws SLCommandoBuildException - */ - public static final ObjectNode createGenericResponse(String respId, String inResponseTo, String transactionId, - ObjectNode payLoad, 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; - - } - - /** - * Add one element of two possible elements <br> - * 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 - */ - public static void addOnlyOnceOfTwo(ObjectNode parent, String firstKeyId, String secondKeyId, ObjectNode first, 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(JsonSecurityUtils signer) 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(JsonSecurityUtils signer) 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(JsonSecurityUtils signer) { - 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(ObjectNode parent, String keyId, List<String> 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(ObjectNode parent, String keyId, Map<String, String> keyValuePairs) throws SLCommandoBuildException { - validateParentAndKey(parent, keyId); - if (keyValuePairs != null) { - final ArrayNode callReqParamsArray = mapper.getMapper().createArrayNode(); - parent.set(keyId, callReqParamsArray); - - for(final Entry<String, String> el : keyValuePairs.entrySet()) { - final ObjectNode callReqParams = mapper.getMapper().createObjectNode(); - callReqParams.put(el.getKey(), el.getValue()); - callReqParamsArray.add(callReqParams); - - } - } - } - - private static void addSingleCertificateElement(ObjectNode parent, String keyId, X509Certificate cert, 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(ObjectNode parent, String keyId, byte[] value, 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(ObjectNode parent, String keyId, Boolean value, 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(ObjectNode parent, String keyId, Integer value, 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(ObjectNode parent, String keyId, String value, 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(ObjectNode parent, String keyId, Integer value, 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(ObjectNode parent, String keyId, ObjectNode element, 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 addOnlyOnceOfTwo(ObjectNode parent, String firstKeyId, String secondKeyId, ObjectNode first, 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"); - } - - private static void validateParentAndKey(ObjectNode parent, 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"); - } -} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JSONExtractorUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JSONExtractorUtils.java deleted file mode 100644 index 314dde17..00000000 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JSONExtractorUtils.java +++ /dev/null @@ -1,368 +0,0 @@ -package at.gv.egiz.eaaf.modules.auth.sl20.utils; - -import java.util.ArrayList; -import java.util.Base64; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.util.EntityUtils; -import org.jose4j.base64url.Base64Url; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SLCommandoParserException; - -public class SL20JSONExtractorUtils { - private static final Logger log = LoggerFactory.getLogger(SL20JSONExtractorUtils.class); - private static JsonMapper mapper = new JsonMapper(); - - - /** - * Extract String value from JSON - * - * @param input - * @param keyID - * @param isRequired - * @return - * @throws SLCommandoParserException - */ - public static String getStringValue(JsonNode input, String keyID, boolean isRequired) throws SLCommandoParserException { - try { - final JsonNode internal = getAndCheck(input, keyID, isRequired); - - if (internal != null) - return internal.asText(); - else - return null; - - } catch (final SLCommandoParserException e) { - throw e; - - } catch (final Exception e) { - throw new SLCommandoParserException("Can not extract String value with keyId: " + keyID, e); - - } - } - - /** - * Extract Boolean value from JSON - * - * @param input - * @param keyID - * @param isRequired - * @return - * @throws SLCommandoParserException - */ - public static boolean getBooleanValue(ObjectNode input, String keyID, boolean isRequired, boolean defaultValue) throws SLCommandoParserException { - try { - final JsonNode internal = getAndCheck(input, keyID, isRequired); - - if (internal != null) - return internal.asBoolean(); - else - return defaultValue; - - } catch (final SLCommandoParserException e) { - throw e; - - } catch (final Exception e) { - throw new SLCommandoParserException("Can not extract Boolean value with keyId: " + keyID, e); - - } - } - - /** - * Extract JSONObject value from JSON - * - * @param input - * @param keyID - * @param isRequired - * @return - * @throws SLCommandoParserException - */ - public static JsonNode getJSONObjectValue(JsonNode input, String keyID, boolean isRequired) throws SLCommandoParserException { - try { - final JsonNode internal = getAndCheck(input, keyID, isRequired); - - if (internal != null) - return internal; - else - return null; - - } catch (final SLCommandoParserException e) { - throw e; - - } catch (final Exception e) { - throw new SLCommandoParserException("Can not extract Boolean value with keyId: " + keyID, e); - - } - } - - /** - * Extract a List of String elements from a JSON element - * - * @param input - * @return - * @throws SLCommandoParserException - */ - public static List<String> getListOfStringElements(JsonNode input) throws SLCommandoParserException { - final List<String> result = new ArrayList<String>(); - if (input != null) { - if (input.isArray()) { - final Iterator<JsonNode> arrayIterator = input.iterator(); - while(arrayIterator.hasNext()) { - final JsonNode next = arrayIterator.next(); - if (next.isTextual()) - result.add(next.asText()); - } - - } else if (input.isTextual()) { - result.add(input.asText()); - - } else { - log.warn("JSON Element IS NOT a JSON array or a JSON Primitive"); - throw new SLCommandoParserException("JSON Element IS NOT a JSON array or a JSON Primitive"); - - } - } - - return result; - } - - /** - * Extract Map of Key/Value pairs from a JSON Element - * - * @param input parent JSON object - * @param keyID KeyId of the child that should be parsed - * @param isRequired - * @return - * @throws SLCommandoParserException - */ - public static Map<String, String> getMapOfStringElements(JsonNode input, String keyID, boolean isRequired) throws SLCommandoParserException { - final JsonNode internal = getAndCheck(input, keyID, isRequired); - return getMapOfStringElements(internal); - - } - - /** - * Extract Map of Key/Value pairs from a JSON Element - * - * @param input - * @return - * @throws SLCommandoParserException - */ - public static Map<String, String> getMapOfStringElements(JsonNode input) throws SLCommandoParserException { - final Map<String, String> result = new HashMap<String, String>(); - - if (input != null) { - if (input.isArray()) { - final Iterator<JsonNode> arrayIterator = input.iterator(); - while(arrayIterator.hasNext()) { - final JsonNode next = arrayIterator.next(); - final Iterator<Entry<String, JsonNode>> entry = next.fields(); - entitySetToMap(result, entry); - - } - - } else if (input.isObject()) { - final Iterator<Entry<String, JsonNode>> objectKeys = input.fields(); - entitySetToMap(result, objectKeys); - - } else - throw new SLCommandoParserException("JSON Element IS NOT a JSON array or a JSON object"); - - } - - return result; - } - - private static void entitySetToMap(Map<String, String> result, Iterator<Entry<String, JsonNode>> entry) { - while (entry.hasNext()) { - final Entry<String, JsonNode> el = entry.next(); - if (result.containsKey(el.getKey())) - log.info("Attr. Map already contains Element with Key: " + el.getKey() + ". Overwrite element ... "); - - result.put(el.getKey(), el.getValue().asText()); - - } - - } - - - public static JsonNode extractSL20Result(JsonNode command, IJOSETools decrypter, boolean mustBeEncrypted) throws SL20Exception { - final JsonNode result = command.get(SL20Constants.SL20_COMMAND_CONTAINER_RESULT); - final JsonNode encryptedResult = command.get(SL20Constants.SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT); - - if (result == null && encryptedResult == null) - throw new SLCommandoParserException("NO result OR encryptedResult FOUND."); - - else if (encryptedResult == null && mustBeEncrypted) - throw new SLCommandoParserException("result MUST be encrypted."); - - else if (encryptedResult != null && encryptedResult.isTextual()) { - try { - return decrypter.decryptPayload(encryptedResult.asText()); - - } catch (final Exception e) { - log.info("Can NOT decrypt SL20 result. Reason:" + e.getMessage()); - if (!mustBeEncrypted) { - log.warn("Decrypted results are disabled by configuration. Parse result in plain if it is possible"); - - //dummy code - try { - final String[] signedPayload = encryptedResult.toString().split("\\."); - final JsonNode payLoad = mapper.getMapper().readTree(new String(Base64.getUrlDecoder().decode(signedPayload[1]))); - return payLoad; - - } catch (final Exception e1) { - log.debug("DummyCode FAILED, Reason: " + e1.getMessage() + " Ignore it ..."); - throw new SL20Exception(e.getMessage(), null, e); - - } - - } else - throw e; - - } - - } else if (result != null) { - return result; - - } else - throw new SLCommandoParserException("Internal build error"); - - - } - - /** - * Extract payLoad from generic transport container - * - * @param container - * @param joseTools - * @return - * @throws SLCommandoParserException - */ - public static VerificationResult extractSL20PayLoad(JsonNode container, IJOSETools joseTools, boolean mustBeSigned) throws SL20Exception { - - final JsonNode sl20Payload = container.get(SL20Constants.SL20_PAYLOAD); - final JsonNode sl20SignedPayload = container.get(SL20Constants.SL20_SIGNEDPAYLOAD); - - if (mustBeSigned && joseTools == null) - throw new SLCommandoParserException("'joseTools' MUST be set if 'mustBeSigned' is 'true'"); - - if (sl20Payload == null && sl20SignedPayload == null) - throw new SLCommandoParserException("NO payLoad OR signedPayload FOUND."); - - else if (sl20SignedPayload == null && mustBeSigned) - throw new SLCommandoParserException("payLoad MUST be signed."); - - else if (joseTools != null && sl20SignedPayload != null && sl20SignedPayload.isTextual()) { - return joseTools.validateSignature(sl20SignedPayload.asText()); - - } else if (sl20Payload != null) - return new VerificationResult(sl20Payload); - - else - throw new SLCommandoParserException("Internal build error"); - - - } - - - /** - * Extract generic transport container from httpResponse - * - * @param httpResp - * @return - * @throws SLCommandoParserException - */ - public static JsonNode getSL20ContainerFromResponse(HttpResponse httpResp) throws SLCommandoParserException { - try { - JsonNode sl20Resp = null; - if (httpResp.getStatusLine().getStatusCode() == 303 || httpResp.getStatusLine().getStatusCode() == 307) { - final Header[] locationHeader = httpResp.getHeaders("Location"); - if (locationHeader == null) - throw new SLCommandoParserException("Find Redirect statuscode but not Location header"); - - final String sl20RespString = new URIBuilder(locationHeader[0].getValue()).getQueryParams().get(0).getValue(); - sl20Resp = mapper.getMapper().readTree(Base64Url.decode(sl20RespString)); - - } else if (httpResp.getStatusLine().getStatusCode() == 200) { - if (httpResp.getEntity().getContentType() == null) - throw new SLCommandoParserException("SL20 response contains NO ContentType"); - - if (!httpResp.getEntity().getContentType().getValue().startsWith("application/json")) - throw new SLCommandoParserException("SL20 response with a wrong ContentType: " + httpResp.getEntity().getContentType().getValue()); - sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity()); - - } else if ( (httpResp.getStatusLine().getStatusCode() == 500) || - (httpResp.getStatusLine().getStatusCode() == 401) || - (httpResp.getStatusLine().getStatusCode() == 400) ) { - log.info("SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode() - + ". Search for error message"); - - try { - sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity()); - - } catch (final Exception e) { - log.warn("SL20 response contains no valid JSON", e); - throw new SLCommandoParserException("SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode() - + " AND NO valid JSON errormsg", e); - - } - - - - } else - throw new SLCommandoParserException("SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode()); - - log.info("Find JSON object in http response"); - return sl20Resp; - - } catch (final Exception e) { - throw new SLCommandoParserException("SL20 response parsing FAILED! Reason: " + e.getMessage(), e); - - } - } - - private static JsonNode parseSL20ResultFromResponse(HttpEntity resp) throws Exception { - if (resp != null && resp.getContent() != null) { - final String rawSL20Resp = EntityUtils.toString(resp); - final JsonNode sl20Resp = mapper.getMapper().readTree(rawSL20Resp); - - //TODO: check sl20Resp type like && sl20Resp.isJsonObject() - if (sl20Resp != null) { - return sl20Resp; - - } else - throw new SLCommandoParserException("SL2.0 can NOT parse to a JSON object"); - - - } else - throw new SLCommandoParserException("Can NOT find content in http response"); - - } - - - private static JsonNode getAndCheck(JsonNode input, String keyID, boolean isRequired) throws SLCommandoParserException { - final JsonNode internal = input.get(keyID); - - if (internal == null && isRequired) - throw new SLCommandoParserException("REQUIRED Element with keyId: " + keyID + " does not exist"); - - return internal; - - } -} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonBuilderUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonBuilderUtils.java new file mode 100644 index 00000000..eb17781b --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonBuilderUtils.java @@ -0,0 +1,677 @@ +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<String, String> 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<String, String> 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<String, String> 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<String> displayData, final List<String> 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 <br> + * 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<String> 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<String, String> keyValuePairs) throws SlCommandoBuildException { + validateParentAndKey(parent, keyId); + if (keyValuePairs != null) { + final ArrayNode callReqParamsArray = mapper.getMapper().createArrayNode(); + parent.set(keyId, callReqParamsArray); + + for (final Entry<String, String> 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"); + } + } +} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java new file mode 100644 index 00000000..eb6de461 --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java @@ -0,0 +1,389 @@ +package at.gv.egiz.eaaf.modules.auth.sl20.utils; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.util.EntityUtils; +import org.jose4j.base64url.Base64Url; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException; + +public class SL20JsonExtractorUtils { + private static final Logger log = LoggerFactory.getLogger(SL20JsonExtractorUtils.class); + private static JsonMapper mapper = new JsonMapper(); + + /** + * Extract String value from JSON. + * + * @param input JSON + * @param keyID Element identifier + * @param isRequired true, if the element must not null + * @return Value of this element + * @throws SlCommandoParserException In case an error + */ + public static String getStringValue(final JsonNode input, final String keyID, final boolean isRequired) + throws SlCommandoParserException { + try { + final JsonNode internal = getAndCheck(input, keyID, isRequired); + + if (internal != null) { + return internal.asText(); + } else { + return null; + } + + } catch (final SlCommandoParserException e) { + throw e; + + } catch (final Exception e) { + throw new SlCommandoParserException("Can not extract String value with keyId: " + keyID, e); + + } + } + + /** + * Extract Boolean value from JSON. + * + * @param input JSON + * @param keyID Element identifier + * @param isRequired true, if the element must not null + * @return Boolean + * @throws SlCommandoParserException In case of an error + */ + public static boolean getBooleanValue(final ObjectNode input, final String keyID, final boolean isRequired, + final boolean defaultValue) throws SlCommandoParserException { + try { + final JsonNode internal = getAndCheck(input, keyID, isRequired); + + if (internal != null) { + return internal.asBoolean(); + } else { + return defaultValue; + } + + } catch (final SlCommandoParserException e) { + throw e; + + } catch (final Exception e) { + throw new SlCommandoParserException("Can not extract Boolean value with keyId: " + keyID, e); + + } + } + + /** + * Extract JSONObject value from JSON. + * + * @param input JSON + * @param keyID Element identifier + * @param isRequired true, if the element must not null + * @return JSON node + * @throws SlCommandoParserException In case of an error + */ + public static JsonNode getJsonObjectValue(final JsonNode input, final String keyID, final boolean isRequired) + throws SlCommandoParserException { + try { + final JsonNode internal = getAndCheck(input, keyID, isRequired); + + if (internal != null) { + return internal; + } else { + return null; + } + + } catch (final SlCommandoParserException e) { + throw e; + + } catch (final Exception e) { + throw new SlCommandoParserException("Can not extract Boolean value with keyId: " + keyID, e); + + } + } + + /** + * Extract a List of String elements from a JSON element. + * + * @param input JSON + * @return List of Elements in this node + * @throws SlCommandoParserException In case of an error + */ + public static List<String> getListOfStringElements(final JsonNode input) throws SlCommandoParserException { + final List<String> result = new ArrayList<>(); + if (input != null) { + if (input.isArray()) { + final Iterator<JsonNode> arrayIterator = input.iterator(); + while (arrayIterator.hasNext()) { + final JsonNode next = arrayIterator.next(); + if (next.isTextual()) { + result.add(next.asText()); + } + } + + } else if (input.isTextual()) { + result.add(input.asText()); + + } else { + log.warn("JSON Element IS NOT a JSON array or a JSON Primitive"); + throw new SlCommandoParserException("JSON Element IS NOT a JSON array or a JSON Primitive"); + + } + } + + return result; + } + + /** + * Extract Map of Key/Value pairs from a JSON Element. + * + * @param input parent JSON object + * @param keyID KeyId of the child that should be parsed + * @param isRequired true, if the element must not null + * @return Map of element pairs + * @throws SlCommandoParserException In case of an error + */ + public static Map<String, String> getMapOfStringElements(final JsonNode input, final String keyID, + final boolean isRequired) throws SlCommandoParserException { + final JsonNode internal = getAndCheck(input, keyID, isRequired); + return getMapOfStringElements(internal); + + } + + /** + * Extract Map of Key/Value pairs from a JSON Element. + * + * @param input JSON + * @return Map of element pairs + * @throws SlCommandoParserException in case of an error + */ + public static Map<String, String> getMapOfStringElements(final JsonNode input) throws SlCommandoParserException { + final Map<String, String> result = new HashMap<>(); + + if (input != null) { + if (input.isArray()) { + final Iterator<JsonNode> arrayIterator = input.iterator(); + while (arrayIterator.hasNext()) { + final JsonNode next = arrayIterator.next(); + final Iterator<Entry<String, JsonNode>> entry = next.fields(); + entitySetToMap(result, entry); + + } + + } else if (input.isObject()) { + final Iterator<Entry<String, JsonNode>> objectKeys = input.fields(); + entitySetToMap(result, objectKeys); + + } else { + throw new SlCommandoParserException("JSON Element IS NOT a JSON array or a JSON object"); + } + + } + + return result; + } + + private static void entitySetToMap(final Map<String, String> result, final Iterator<Entry<String, JsonNode>> entry) { + while (entry.hasNext()) { + final Entry<String, JsonNode> el = entry.next(); + if (result.containsKey(el.getKey())) { + log.info("Attr. Map already contains Element with Key: " + el.getKey() + ". Overwrite element ... "); + } + + result.put(el.getKey(), el.getValue().asText()); + + } + + } + + /** + * Extract Security-Layer 2.0 result from response object. + * + * @param command SL2.0 command + * @param decrypter JWS decrypter implementation + * @param mustBeEncrypted if <code>true</code>, the result must be encrypted + * @return decrypted JSON + * @throws SL20Exception In case of an error + */ + public static JsonNode extractSL20Result(final JsonNode command, final IJoseTools decrypter, + final boolean mustBeEncrypted) throws SL20Exception { + final JsonNode result = command.get(SL20Constants.SL20_COMMAND_CONTAINER_RESULT); + final JsonNode encryptedResult = command.get(SL20Constants.SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT); + + if (result == null && encryptedResult == null) { + throw new SlCommandoParserException("NO result OR encryptedResult FOUND."); + } else if (encryptedResult == null && mustBeEncrypted) { + throw new SlCommandoParserException("result MUST be encrypted."); + } else if (encryptedResult != null && encryptedResult.isTextual()) { + try { + return decrypter.decryptPayload(encryptedResult.asText()); + + } catch (final Exception e) { + log.info("Can NOT decrypt SL20 result. Reason:" + e.getMessage()); + if (!mustBeEncrypted) { + log.warn("Decrypted results are disabled by configuration. Parse result in plain if it is possible"); + + // dummy code + try { + final String[] signedPayload = encryptedResult.toString().split("\\."); + final JsonNode payLoad = mapper.getMapper() + .readTree(new String(Base64.getUrlDecoder().decode(signedPayload[1]), "UTF-8")); + return payLoad; + + } catch (final Exception e1) { + log.debug("DummyCode FAILED, Reason: " + e1.getMessage() + " Ignore it ..."); + throw new SL20Exception(e.getMessage(), null, e); + + } + + } else { + throw e; + } + + } + + } else if (result != null) { + return result; + + } else { + throw new SlCommandoParserException("Internal build error"); + } + + } + + /** + * Extract payLoad from generic transport container. + * + * @param container JSON + * @param joseTools JWS implementation + * @return Signature verification result that contains the payLoad + * @throws SlCommandoParserException In case of an error + */ + public static VerificationResult extractSL20PayLoad(final JsonNode container, final IJoseTools joseTools, + final boolean mustBeSigned) throws SL20Exception { + + final JsonNode sl20Payload = container.get(SL20Constants.SL20_PAYLOAD); + final JsonNode sl20SignedPayload = container.get(SL20Constants.SL20_SIGNEDPAYLOAD); + + if (mustBeSigned && joseTools == null) { + throw new SlCommandoParserException("'joseTools' MUST be set if 'mustBeSigned' is 'true'"); + } + + if (sl20Payload == null && sl20SignedPayload == null) { + throw new SlCommandoParserException("NO payLoad OR signedPayload FOUND."); + } else if (sl20SignedPayload == null && mustBeSigned) { + throw new SlCommandoParserException("payLoad MUST be signed."); + } else if (joseTools != null && sl20SignedPayload != null && sl20SignedPayload.isTextual()) { + return joseTools.validateSignature(sl20SignedPayload.asText()); + + } else if (sl20Payload != null) { + return new VerificationResult(sl20Payload); + } else { + throw new SlCommandoParserException("Internal build error"); + } + + } + + /** + * Extract generic transport container from httpResponse. + * + * @param httpResp Http response object + * @return JSON with SL2.0 response + * @throws SlCommandoParserException In case of an error + */ + public static JsonNode getSL20ContainerFromResponse(final HttpResponse httpResp) throws SlCommandoParserException { + try { + JsonNode sl20Resp = null; + if (httpResp.getStatusLine().getStatusCode() == 303 || httpResp.getStatusLine().getStatusCode() == 307) { + final Header[] locationHeader = httpResp.getHeaders("Location"); + if (locationHeader == null) { + throw new SlCommandoParserException("Find Redirect statuscode but not Location header"); + } + + final String sl20RespString = new URIBuilder(locationHeader[0].getValue()).getQueryParams().get(0).getValue(); + sl20Resp = mapper.getMapper().readTree(Base64Url.decode(sl20RespString)); + + } else if (httpResp.getStatusLine().getStatusCode() == 200) { + if (httpResp.getEntity().getContentType() == null) { + throw new SlCommandoParserException("SL20 response contains NO ContentType"); + } + + if (!httpResp.getEntity().getContentType().getValue().startsWith("application/json")) { + throw new SlCommandoParserException( + "SL20 response with a wrong ContentType: " + httpResp.getEntity().getContentType().getValue()); + } + sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity()); + + } else if (httpResp.getStatusLine().getStatusCode() == 500 || httpResp.getStatusLine().getStatusCode() == 401 + || httpResp.getStatusLine().getStatusCode() == 400) { + log.info( + "SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode() + ". Search for error message"); + + try { + sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity()); + + } catch (final Exception e) { + log.warn("SL20 response contains no valid JSON", e); + throw new SlCommandoParserException("SL20 response with http-code: " + + httpResp.getStatusLine().getStatusCode() + " AND NO valid JSON errormsg", e); + + } + + } else { + throw new SlCommandoParserException( + "SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode()); + } + + log.info("Find JSON object in http response"); + return sl20Resp; + + } catch (final Exception e) { + throw new SlCommandoParserException("SL20 response parsing FAILED! Reason: " + e.getMessage(), e); + + } + } + + private static JsonNode parseSL20ResultFromResponse(final HttpEntity resp) throws Exception { + if (resp != null && resp.getContent() != null) { + final String rawSL20Resp = EntityUtils.toString(resp); + final JsonNode sl20Resp = mapper.getMapper().readTree(rawSL20Resp); + + // TODO: check sl20Resp type like && sl20Resp.isJsonObject() + if (sl20Resp != null) { + return sl20Resp; + + } else { + throw new SlCommandoParserException("SL2.0 can NOT parse to a JSON object"); + } + + } else { + throw new SlCommandoParserException("Can NOT find content in http response"); + } + + } + + private static JsonNode getAndCheck(final JsonNode input, final String keyID, final boolean isRequired) + throws SlCommandoParserException { + final JsonNode internal = input.get(keyID); + + if (internal == null && isRequired) { + throw new SlCommandoParserException("REQUIRED Element with keyId: " + keyID + " does not exist"); + } + + return internal; + + } +} diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java new file mode 100644 index 00000000..4bb91634 --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java @@ -0,0 +1,166 @@ +package at.gv.egiz.eaaf.modules.auth.sl20.utils; + +import java.io.IOException; +import java.io.StringWriter; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.modules.auth.sl20.Constants; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SL20ResponseUtils { + private static final String PATTERN_PENDING_REQ_ID = "#PENDINGREQID#"; + + /** + * Build a generic SL2.x error-response without redirect to AuthHandler. + * + * @param response http response object + * @param errorCode ErrorCode + * @param errorMsg Error message + * @throws Exception In case of a message generation error + */ + public static void buildErrorResponse(final HttpServletResponse response, + final String errorCode, final String errorMsg) + throws Exception { + final ObjectNode error = SL20JsonBuilderUtils.createErrorCommandResult(errorCode, errorMsg); + final ObjectNode errorCommand = SL20JsonBuilderUtils + .createCommandResponse(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, error, null); + + final ObjectNode respContainer = SL20JsonBuilderUtils.createGenericResponse(UUID.randomUUID().toString(), null, + null, errorCommand, null); + + log.trace("SL20 response to VDA: " + respContainer); + final StringWriter writer = new StringWriter(); + writer.write(respContainer.toString()); + final byte[] content = writer.toString().getBytes("UTF-8"); + response.setStatus(HttpServletResponse.SC_OK); + response.setContentLength(content.length); + response.setContentType(ContentType.APPLICATION_JSON.toString()); + response.getOutputStream().write(content); + + } + + /** + * Build a Security-Layer 2.x conform redirect response. + * + * @param request http request + * @param response http response + * @param pendingReq Current pending request + * @param fullRedirectUrl Endpoint, where the auth. process should be resumed after redirect + * @param transactionId SL2.0 transactionId if available + * @param authConfig Basic application configuration + * @throws IOException In case of a http servlet error + * @throws SL20Exception In case of a SL2.0 request generation error + * @throws URISyntaxException In case of an invalid Redirect URL + */ + public static void buildResponse(final HttpServletRequest request, final HttpServletResponse response, + IRequest pendingReq, String fullRedirectUrl, String transactionId, IConfiguration authConfig) + throws IOException, SL20Exception, URISyntaxException { + // create response + final Map<String, String> reqParameters = new HashMap<>(); + + final URL redirectUrl = new URL(fullRedirectUrl); + if (redirectUrl.getQuery() != null) { + final String [] elements = redirectUrl.getQuery().split("&"); + for (final String element : elements) { + final String[] keyValue = element.split("="); + if (keyValue.length == 2) { + reqParameters.put(keyValue[0], keyValue[1]); + + } else { + log.warn("Ignore parameter with name: {}", keyValue[0]); + + } + } + } + + //reqParameters.put(EaafConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReq.getPendingRequestId()); + + final ObjectNode callReqParams = SL20JsonBuilderUtils.createCallCommandParameters( + fullRedirectUrl.split("\\?")[0], + SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET, false, reqParameters); + final ObjectNode callCommand = SL20JsonBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, + callReqParams); + + // build first redirect command for app + final ObjectNode redirectOneParams = SL20JsonBuilderUtils + .createRedirectCommandParameters(generateIpcRedirectUrlForDebugging( + pendingReq, + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_IPC_RETURN_URL)), + callCommand, null, true); + final ObjectNode redirectOneCommand = SL20JsonBuilderUtils + .createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams); + + // build second redirect command for IDP + final ObjectNode redirectTwoParams = SL20JsonBuilderUtils.createRedirectCommandParameters( + fullRedirectUrl, + redirectOneCommand, null, false); + final ObjectNode redirectTwoCommand = SL20JsonBuilderUtils + .createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectTwoParams); + + // build generic SL2.0 response container + final ObjectNode respContainer = SL20JsonBuilderUtils.createGenericRequest(UUID.randomUUID().toString(), + transactionId, redirectTwoCommand, null); + + if (request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null && request + .getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) { + log.debug("Client request containts 'native client' header ... "); + log.trace("SL20 response to VDA: " + respContainer); + final StringWriter writer = new StringWriter(); + writer.write(respContainer.toString()); + final byte[] content = writer.toString().getBytes("UTF-8"); + response.setStatus(HttpServletResponse.SC_OK); + response.setContentLength(content.length); + response.setContentType(ContentType.APPLICATION_JSON.toString()); + response.getOutputStream().write(content); + + } else { + log.info("SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"); + + log.debug("Client request containts is no native client ... "); + final URIBuilder clientRedirectUri = new URIBuilder(fullRedirectUrl); + response.setStatus(Integer.parseInt(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_HTTP_REDIRECT_CODE, + Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE))); + response.setHeader("Location", clientRedirectUri.build().toString()); + + } + } + + /** + * Generates a IPC redirect URL that is configured on IDP side. + * + * @return IPC ReturnURL, or null if no URL is configured + */ + private static String generateIpcRedirectUrlForDebugging(IRequest pendingReq, String ipcRedirectUrlConfig) { + if (StringUtils.isNotEmpty(ipcRedirectUrlConfig)) { + if (ipcRedirectUrlConfig.contains(PATTERN_PENDING_REQ_ID)) { + log.trace("Find 'pendingReqId' pattern in IPC redirect URL. Update url ... "); + ipcRedirectUrlConfig = ipcRedirectUrlConfig.replaceAll("#PENDINGREQID#", + EaafConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID + "=" + pendingReq.getPendingRequestId()); + + } + + return ipcRedirectUrlConfig; + } + + return null; + + } +} |