diff options
Diffstat (limited to 'id/server/modules/moa-id-module-eIDAS/src/main/java/at')
27 files changed, 2226 insertions, 1035 deletions
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java index 369d77863..c0101b553 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java @@ -25,10 +25,6 @@ package at.gv.egovernment.moa.id.auth.modules.eidas; import org.apache.xml.security.signature.XMLSignature; import org.opensaml.xml.encryption.EncryptionConstants; import org.opensaml.xml.signature.SignatureConstants; -//import eu.eidas.auth.engine.core.validator.eidas.EIDASAttributes; - -import eu.eidas.auth.commons.attribute.AttributeRegistries; -import eu.eidas.auth.commons.attribute.AttributeRegistry; /** * @author tlenz @@ -61,17 +57,23 @@ public class Constants { public static final String CONIG_PROPS_EIDAS_SAMLENGINE_SIGN_CONFIGFILE = CONIG_PROPS_EIDAS_SAMLENGINE_PREFIX + "." + CONIG_PROPS_EIDAS_SAMLENGINE_SIGN + ".config.file"; public static final String CONIG_PROPS_EIDAS_SAMLENGINE_ENC_CONFIGFILE = CONIG_PROPS_EIDAS_SAMLENGINE_PREFIX + "." - + CONIG_PROPS_EIDAS_SAMLENGINE_ENCRYPT + ".config.file"; + + CONIG_PROPS_EIDAS_SAMLENGINE_ENCRYPT + ".config.file"; + public static final String CONIG_PROPS_EIDAS_SAMLENGINE_ATTIONAL_ATTRIBUTE_DEFINITIONS = + CONIG_PROPS_EIDAS_SAMLENGINE_PREFIX + ".attributes.addition.config"; public static final String CONIG_PROPS_EIDAS_METADATA_VALIDATION_TRUSTSTORE = CONIG_PROPS_EIDAS_PREFIX + ".metadata.validation.truststore"; + public static final String CONIG_PROPS_EIDAS_NODE_COUNTRYCODE = CONIG_PROPS_EIDAS_NODE + ".countrycode"; public static final String CONIG_PROPS_EIDAS_NODE_COUNTRY = CONIG_PROPS_EIDAS_NODE + ".country"; - public static final String CONIG_PROPS_EIDAS_NODE_LoA = CONIG_PROPS_EIDAS_NODE + ".LoA"; + public static final String CONIG_PROPS_EIDAS_NODE_LoA = CONIG_PROPS_EIDAS_NODE + ".LoA"; + + public static final String CONIG_PROPS_EIDAS_METADATA_URLS_LIST_PREFIX = CONIG_PROPS_EIDAS_PREFIX + ".metadata.url"; + //timeouts and clock skews - public static final int CONFIG_PROPS_SKEWTIME = 2 * 60 * 1000; //2 minutes skew time for response validation - public static final int CONFIG_PROPS_METADATA_SOCKED_TIMEOUT = 20 * 1000; //20 seconds metadata socked timeout + public static final long CONFIG_PROPS_SKEWTIME_BEFORE = -2 * 60 * 1000; //5 minutes skew time for response validation + public static final long CONFIG_PROPS_SKEWTIME_AFTER = 2 * 60 * 1000; //5 minutes skew time for response validation public static final long CONFIG_PROPS_METADATA_GARBAGE_TIMEOUT = 7 * 24 * 60 * 60 * 1000; //remove unused eIDAS metadata after 7 days //eIDAS request parameters @@ -88,8 +90,6 @@ public class Constants { //http endpoint descriptions public static final String eIDAS_HTTP_ENDPOINT_SP_POST = "/eidas/sp/post"; public static final String eIDAS_HTTP_ENDPOINT_SP_REDIRECT = "/eidas/sp/redirect"; - //public static final String eIDAS_HTTP_ENDPOINT_IDP_POST = "/eidas/idp/post"; - //public static final String eIDAS_HTTP_ENDPOINT_IDP_REDIRECT = "/eidas/idp/redirect"; public static final String eIDAS_HTTP_ENDPOINT_IDP_COLLEAGUEREQUEST = "/eidas/ColleagueRequest"; public static final String eIDAS_HTTP_ENDPOINT_METADATA = "/eidas/metadata"; @@ -99,38 +99,6 @@ public class Constants { public static final int eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST = 3401; public static final int eIDAS_REVERSIONSLOG_IDP_AUTHRESPONSE = 3402; - //metadata constants -// public final static Map<String, EidasAttributesTypes> METADATA_POSSIBLE_ATTRIBUTES = Collections.unmodifiableMap( -// new HashMap<String, EidasAttributesTypes>(){ -// private static final long serialVersionUID = 1L; -// { -// put(EIDASAttributes.ATTRIBUTE_GIVENNAME, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// put(EIDASAttributes.ATTRIBUTE_FIRSTNAME, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// put(EIDASAttributes.ATTRIBUTE_DATEOFBIRTH, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// put(EIDASAttributes.ATTRIBUTE_PERSONIDENTIFIER, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// -// //TODO: add additional attributes for eIDAS with mandates -// //put(EIDASAttributes.ATTRIBUTE_LEGALIDENTIFIER, EidasAttributesTypes.LEGAL_PERSON_MANDATORY); -// //put(EIDASAttributes.ATTRIBUTE_LEGALNAME, EidasAttributesTypes.LEGAL_PERSON_MANDATORY); -// } -// } -// ); - - public static final AttributeRegistry NAT_ATTR = - AttributeRegistries.of( eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER, - eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_FAMILY_NAME, - eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_GIVEN_NAME, - eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.DATE_OF_BIRTH - ); - - public static final AttributeRegistry LEGAL_ATTR = - AttributeRegistries.of( eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_PERSON_IDENTIFIER, - eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_NAME - ); - - public static final AttributeRegistry MOA_IDP_ATTR_REGISTRY = - AttributeRegistries.copyOf(NAT_ATTR, LEGAL_ATTR); - public static final String METADATA_ALLOWED_ALG_DIGIST = SignatureConstants.ALGO_ID_DIGEST_SHA256 + ";" + diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java index e08d302f6..6a48e5030 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java @@ -98,8 +98,11 @@ public class MOAExtendedSWSigner implements ProtocolSignerI, MetadataSignerI { private final ImmutableList<X509Credential> trustedCredentials; private final String signatureAlgorithm; - public MOAExtendedSWSigner(Map<String, String> properties) throws SamlEngineConfigurationException { - this(new KeyStoreSignatureConfigurator().getSignatureConfiguration(properties)); + + //TODO: check if it is required any more + + public MOAExtendedSWSigner(Map<String, String> properties, String defaultConfigPath) throws SamlEngineConfigurationException { + this(new KeyStoreSignatureConfigurator().getSignatureConfiguration(properties, null)); } @@ -109,7 +112,7 @@ public class MOAExtendedSWSigner implements ProtocolSignerI, MetadataSignerI { */ public MOAExtendedSWSigner(CertificateConfigurationManager configManager) throws SamlEngineConfigurationException { this(new KeyStoreSignatureConfigurator().getSignatureConfiguration( - ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters())); + ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters(), null)); } @@ -226,7 +229,7 @@ public class MOAExtendedSWSigner implements ProtocolSignerI, MetadataSignerI { checkCertificateIssuer(credential.getEntityCertificate()); Signature signature; try { - Logger.debug("Creating an OpenSAML signature object"); + Logger.trace("Creating an OpenSAML signature object"); signature = (Signature) Configuration.getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME) .buildObject(Signature.DEFAULT_ELEMENT_NAME); diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java index 5cf5e83ec..3cc9787df 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java @@ -79,8 +79,8 @@ public class MOASWSigner extends KeyStoreProtocolSigner { //Set other algorithms which are not supported by openSAML in default StringUtils.lowerCase(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, Locale.ENGLISH)); - public MOASWSigner(Map<String, String> properties) throws SamlEngineConfigurationException { - super(properties); + public MOASWSigner(Map<String, String> properties, String defaultConfigPath) throws SamlEngineConfigurationException { + super(properties, null); props = properties; } @@ -90,7 +90,7 @@ public class MOASWSigner extends KeyStoreProtocolSigner { * @throws SamlEngineConfigurationException */ public MOASWSigner(CertificateConfigurationManager configManager) throws SamlEngineConfigurationException { - super(props = ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters()); + super(props = ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters(), null); } @@ -100,7 +100,7 @@ public class MOASWSigner extends KeyStoreProtocolSigner { if (sigAlgWhiteList == null) { sigAlgWhiteList = MOAWhiteListConfigurator.getAllowedAlgorithms(DEFAULT_ALGORITHM_WHITE_LIST, ALLOWED_ALGORITHMS_FOR_VERIFYING, - (new KeyStoreSignatureConfigurator().getSignatureConfiguration(props)).getSignatureAlgorithmWhiteList()); + (new KeyStoreSignatureConfigurator().getSignatureConfiguration(props, null)).getSignatureAlgorithmWhiteList()); } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java index de4f3fc9c..d5cbb2cfd 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java @@ -33,15 +33,15 @@ public class ModifiedEncryptionSW extends KeyStoreSamlEngineEncryption { private static ReloadableProperties initActivationConf(Map<String, String> properties) { String activationConfigurationFile = EncryptionKey.ENCRYPTION_ACTIVATION.getAsString(properties); Logger.debug("File containing encryption configuration: \"" + activationConfigurationFile + "\""); - return new ReloadableProperties(activationConfigurationFile); + return new ReloadableProperties(activationConfigurationFile, null); } /** * @param properties * @throws SamlEngineConfigurationException */ - public ModifiedEncryptionSW(Map<String, String> properties) throws SamlEngineConfigurationException { - super(properties); + public ModifiedEncryptionSW(Map<String, String> properties, String defaultConfigPath) throws SamlEngineConfigurationException { + super(properties, null); this.properties = ImmutableMap.copyOf(properties); encryptionActivationProperties = initActivationConf(properties); } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java index c24c5efca..28d74075e 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java @@ -22,7 +22,9 @@ */ package at.gv.egovernment.moa.id.auth.modules.eidas.engine; +import eu.eidas.auth.commons.attribute.AttributeRegistry; import eu.eidas.auth.engine.core.eidas.EidasProtocolProcessor; +import eu.eidas.auth.engine.core.eidas.spec.EidasSpec; import eu.eidas.auth.engine.metadata.MetadataFetcherI; import eu.eidas.auth.engine.metadata.MetadataSignerI; @@ -38,11 +40,14 @@ public class MOAEidasProtocolProcesser extends EidasProtocolProcessor { private final MetadataSignerI metadataSigner; /** - * @param metadataFetcher - * @param metadataSigner + * Build a MOA specific eIDAS-engine protocol processor + * + * @param metadataFetcher eIDAS-engine Metadata fetcher implementation + * @param metadataSigner eIDAS-engine Signer implementation + * @param addAttrDefinitions additinal eIDAS attributes */ - public MOAEidasProtocolProcesser(MetadataFetcherI metadataFetcher, MetadataSignerI metadataSigner) { - super(metadataFetcher, metadataSigner); + public MOAEidasProtocolProcesser(MetadataFetcherI metadataFetcher, MetadataSignerI metadataSigner, AttributeRegistry addAttrDefinitions) { + super(EidasSpec.REGISTRY, addAttrDefinitions, metadataFetcher, metadataSigner); this.metadataFetcher = metadataFetcher; this.metadataSigner = metadataSigner; @@ -53,5 +58,11 @@ public class MOAEidasProtocolProcesser extends EidasProtocolProcessor { public String getResponseValidatorId() { return OWN_EIDAS_RESPONSE_VALIDATOR_SUITE_ID; } - + + + public MetadataFetcherI getMetadataFetcher() { + return this.metadataFetcher; + } + + } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java index d8fcd1694..f347022b8 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java @@ -1,16 +1,17 @@ package at.gv.egovernment.moa.id.auth.modules.eidas.engine; -import java.security.cert.X509Certificate; - -import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.Response; +import org.w3c.dom.Document; import at.gv.egovernment.moa.logging.Logger; -import eu.eidas.auth.commons.EidasErrorKey; -import eu.eidas.auth.commons.protocol.IAuthenticationRequest; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.engine.Correlated; import eu.eidas.auth.engine.ProtocolEngine; import eu.eidas.auth.engine.configuration.ProtocolConfigurationAccessor; -import eu.eidas.auth.engine.xml.opensaml.SAMLEngineUtils; +import eu.eidas.auth.engine.core.ProtocolProcessorI; +import eu.eidas.auth.engine.metadata.MetadataFetcherI; +import eu.eidas.auth.engine.xml.opensaml.XmlSchemaUtil; import eu.eidas.engine.exceptions.EIDASSAMLEngineException; public class MOAProtocolEngine extends ProtocolEngine { @@ -20,6 +21,98 @@ public class MOAProtocolEngine extends ProtocolEngine { } + /** + * Add SAML2 metadata refresh functionality if first validation failed + * + */ + @Override + public Correlated unmarshallResponse(byte[] responseBytes) throws EIDASSAMLEngineException { + try { + return super.unmarshallResponse(responseBytes); + + } catch (EIDASSAMLEngineException e) { + if (responseBytes != null ) { + Logger.info("eIDAS Response validation FAILED. Starting metadata reloading process ..."); + Document document = XmlSchemaUtil.validateSamlSchema(responseBytes); + Response response = (Response) unmarshall(document); + String entityID = response.getIssuer().getValue(); + + if (MiscUtil.isEmpty(entityID)) { + Logger.debug("eIDAS Response contains no EntityID."); + throw e; + + } + + if (startInternalMetadataRefesh(entityID)) { + Logger.debug("Metadata refresh success. Revalidate eIDAS Response ..."); + return super.unmarshallResponse(responseBytes); + + } + Logger.info("eIDAS metadata refresh not possible or not successful."); + + } + throw e; + + } + } + + /** + * Add SAML2 metadata refresh functionality if first validation failed + * + */ + @Override + public AuthnRequest unmarshallRequest(byte[] requestBytes) throws EIDASSAMLEngineException { + try { + return super.unmarshallRequest(requestBytes); + + + } catch (EIDASSAMLEngineException e) { + if (null != requestBytes) { + Logger.info("eIDAS Request validation FAILED. Starting metadata reloading process ..."); + Document document = XmlSchemaUtil.validateSamlSchema(requestBytes); + AuthnRequest request = (AuthnRequest) unmarshall(document); + String entityID = request.getIssuer().getValue(); + + if (MiscUtil.isEmpty(entityID)) { + Logger.debug("eIDAS Authn. Request contains no EntityID."); + throw e; + + } + + if (startInternalMetadataRefesh(entityID)) { + Logger.debug("Metadata refresh success. Revalidate eIDAS Authn. Request ..."); + return super.unmarshallRequest(requestBytes); + + } + + Logger.info("eIDAS metadata refresh not possible or not successful."); + } + + throw e; + + } + } + + /** + * Refresh SAML2 metadata if the internal metadata provider supports this functionality + * + * @param entityID + * @return true if refresh was success, otherwise false + */ + private boolean startInternalMetadataRefesh(String entityID) { + //check if eIDAS SAML-Engine implementation supports metadata refresh + ProtocolProcessorI protocolProcessor = this.getProtocolProcessor(); + if (protocolProcessor instanceof MOAEidasProtocolProcesser) { + MetadataFetcherI metadataFetcher = + ((MOAEidasProtocolProcesser)protocolProcessor).getMetadataFetcher(); + if (metadataFetcher instanceof MOAeIDASMetadataProviderDecorator) + return ((MOAeIDASMetadataProviderDecorator)metadataFetcher).refreshMetadata(entityID); + + } + + return false; + } + // @Override // protected X509Certificate getEncryptionCertificate(String requestIssuer, // String destinationCountryCode) throws EIDASSAMLEngineException { diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASChainingMetadataProvider.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASChainingMetadataProvider.java index ffa74b92b..490dc9dcf 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASChainingMetadataProvider.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASChainingMetadataProvider.java @@ -9,15 +9,13 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Timer; -import javax.net.ssl.SSLHandshakeException; import javax.xml.namespace.QName; -import org.apache.commons.httpclient.MOAHttpClient; -import org.apache.commons.httpclient.params.HttpClientParams; import org.opensaml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.RoleDescriptor; import org.opensaml.saml2.metadata.provider.ChainingMetadataProvider; +import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataFilter; import org.opensaml.saml2.metadata.provider.MetadataProvider; @@ -28,25 +26,22 @@ import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.IDestroyableObject; import at.gv.egovernment.moa.id.auth.IGarbageCollectorProcessing; +import at.gv.egovernment.moa.id.auth.IPostStartupInitializable; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; -import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; -import at.gv.egovernment.moa.id.commons.ex.MOAHttpProtocolSocketFactoryException; -import at.gv.egovernment.moa.id.commons.utils.MOAHttpProtocolSocketFactory; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.filter.SchemaValidationException; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.filter.SignatureValidationException; +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IMOARefreshableMetadataProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.SimpleMOAMetadataProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.metadata.MOASPMetadataSignatureFilter; import at.gv.egovernment.moa.id.saml2.MetadataFilterChain; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.FileUtils; import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.engine.AbstractProtocolEngine; @Service("eIDASMetadataProvider") -public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvider, - IGarbageCollectorProcessing, IDestroyableObject { +public class MOAeIDASChainingMetadataProvider extends SimpleMOAMetadataProvider implements ObservableMetadataProvider, + IGarbageCollectorProcessing, IDestroyableObject, IMOARefreshableMetadataProvider, IPostStartupInitializable{ -// private static MOAeIDASChainingMetadataProvider instance = null; - private static Object mutex = new Object(); + private Timer timer = null; private MetadataProvider internalProvider; private Map<String, Date> lastAccess = null; @@ -70,12 +65,41 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi lastAccess = new HashMap<String, Date>(); } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.IPostStartupInitializable#executeAfterStartup() + */ + @Override + public void executeAfterStartup() { + initializeEidasMetadataFromFileSystem(); + + } + + protected void initializeEidasMetadataFromFileSystem() { + Map<String, String> metadataToLoad = authConfig.getBasicMOAIDConfigurationWithPrefix(Constants.CONIG_PROPS_EIDAS_METADATA_URLS_LIST_PREFIX); + if (!metadataToLoad.isEmpty()) { + Logger.info("Load static configurated eIDAS metadata ... "); + for (String metaatalocation : metadataToLoad.values()) { + String absMetadataLocation = FileUtils.makeAbsoluteURL(metaatalocation, authConfig.getRootConfigFileDir()); + Logger.info(" Load eIDAS metadata from: " + absMetadataLocation); + refreshMetadataProvider(absMetadataLocation); + + } + + Logger.info("Load static configurated eIDAS metadata finished "); + } + } + /* (non-Javadoc) * @see at.gv.egovernment.moa.id.auth.IDestroyableObject#fullyDestroy() */ @Override public void fullyDestroy() { + + if (timer != null) + timer.cancel(); + Map<String, HTTPMetadataProvider> loadedproviders = getAllActuallyLoadedProviders(); if (loadedproviders != null) { for (Entry<String, HTTPMetadataProvider> el : loadedproviders.entrySet()) { @@ -140,8 +164,8 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi + " after timeout."); } else - Logger.warn("eIDAS metadata for EntityID: " + expired - + " is marked as unsed, but no loaded metadata provider is found."); + Logger.info("eIDAS metadata for EntityID: " + expired + + " is marked as expired, but no currently loaded HTTPMetadataProvider metadata provider is found."); } } @@ -187,108 +211,50 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi } } - - - private HTTPMetadataProvider createNewHTTPMetaDataProvider(String metadataURL) { - HTTPMetadataProvider httpProvider = null; - Timer timer= null; - MOAHttpClient httpClient = null; - try { - AuthConfiguration authConfig = AuthConfigurationProviderFactory.getInstance(); - - httpClient = new MOAHttpClient(); - - HttpClientParams httpClientParams = new HttpClientParams(); - httpClientParams.setSoTimeout(Constants.CONFIG_PROPS_METADATA_SOCKED_TIMEOUT); - httpClient.setParams(httpClientParams); - - if (metadataURL.startsWith("https:")) { - try { - //FIX: change hostname validation default flag to true when httpClient is updated to > 4.4 - MOAHttpProtocolSocketFactory protoSocketFactory = new MOAHttpProtocolSocketFactory( - Constants.SSLSOCKETFACTORYNAME, - authConfig.getTrustedCACertificates(), - null, - AuthConfiguration.DEFAULT_X509_CHAININGMODE, - authConfig.isTrustmanagerrevoationchecking(), - authConfig.getRevocationMethodOrder(), - authConfig.getBasicMOAIDConfigurationBoolean( - AuthConfiguration.PROP_KEY_SSL_HOSTNAME_VALIDATION, false)); - - httpClient.setCustomSSLTrustStore(metadataURL, protoSocketFactory); - - } catch (MOAHttpProtocolSocketFactoryException e) { - Logger.warn("MOA SSL-TrustStore can not initialized. Use default Java TrustStore."); - - } - } - + + private MetadataProvider createNewHTTPMetaDataProvider(String metadataURL) { + if (timer == null) timer = new Timer(true); - httpProvider = new HTTPMetadataProvider(timer, httpClient, - metadataURL); - httpProvider.setParserPool(AbstractProtocolEngine.getSecuredParserPool()); - httpProvider.setRequireValidMetadata(true); - httpProvider.setMinRefreshDelay(1000*60*15); //15 minutes - httpProvider.setMaxRefreshDelay(1000*60*60*24); //24 hours - //httpProvider.setRefreshDelayFactor(0.1F); - - //add Metadata filters - MetadataFilterChain filter = new MetadataFilterChain(); - filter.addFilter(new MOASPMetadataSignatureFilter( - authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_METADATA_VALIDATION_TRUSTSTORE))); - httpProvider.setMetadataFilter(filter); - - httpProvider.initialize(); - - return httpProvider; - - } catch (Throwable e) { - if (e.getCause() != null && e.getCause().getCause() instanceof SSLHandshakeException) { - Logger.warn("SSL-Server certificate for metadata " - + metadataURL + " not trusted.", e); - - } if (e.getCause() != null && e.getCause().getCause() instanceof SignatureValidationException) { - Logger.warn("Signature verification for metadata" - + metadataURL + " FAILED.", e); - - } if (e.getCause() != null && e.getCause().getCause() instanceof SchemaValidationException) { - Logger.warn("Schema validation for metadata " - + metadataURL + " FAILED.", e); - } - - Logger.error( - "Failed to add Metadata file for " - + metadataURL + "[ " - + e.getMessage() + " ]", e); - - if (httpProvider != null) { - Logger.debug("Destroy failed Metadata provider"); - httpProvider.destroy(); - } - - if (timer != null) { - Logger.debug("Destroy Timer."); - timer.cancel(); - } - - - } - return null; + //add Metadata filters + MetadataFilterChain filter = new MetadataFilterChain(); + filter.addFilter(new MOASPMetadataSignatureFilter( + authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_METADATA_VALIDATION_TRUSTSTORE))); + + return createNewMoaMetadataProvider(metadataURL, filter, + "eIDAS metadata-provider", + timer, AbstractProtocolEngine.getSecuredParserPool()); + } private Map<String, HTTPMetadataProvider> getAllActuallyLoadedProviders() { Map<String, HTTPMetadataProvider> loadedproviders = new HashMap<String, HTTPMetadataProvider>(); ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; - + //make a Map of all actually loaded HTTPMetadataProvider List<MetadataProvider> providers = chainProvider.getProviders(); for (MetadataProvider provider : providers) { if (provider instanceof HTTPMetadataProvider) { HTTPMetadataProvider httpprovider = (HTTPMetadataProvider) provider; loadedproviders.put(httpprovider.getMetadataURI(), httpprovider); - - } + + } else if (provider instanceof FilesystemMetadataProvider) { + String entityID = "'!!NO-ENTITYID!!'"; + try { + if (provider.getMetadata() instanceof EntityDescriptor) + entityID = ((EntityDescriptor)provider.getMetadata()).getEntityID(); + + Logger.debug("Skip eIDAS metadata: " + entityID + " because it is loaded from local Filesystem"); + + } catch (MetadataProviderException e) { + Logger.info("Collect currently loaded eIDAS metadata provider has an internel process error: " + e.getMessage()); + + } + + } else + Logger.info("Skip " + provider.getClass().getName() + " from list of currently loaded " + + "eIDAS metadata provider"); + } return loadedproviders; @@ -309,7 +275,7 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi } else { //load new Metadata Provider ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; - HTTPMetadataProvider newMetadataProvider = createNewHTTPMetaDataProvider(metadataURL); + MetadataProvider newMetadataProvider = createNewHTTPMetaDataProvider(metadataURL); if (newMetadataProvider != null) { chainProvider.addMetadataProvider(newMetadataProvider); @@ -319,7 +285,8 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi + metadataURL + " is added."); return true; - } + } else + Logger.warn("Can not load eIDAS metadata from URL: " + metadataURL); } } else @@ -435,4 +402,5 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi if (observer != null) observer.onEvent(this); } + } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASMetadataProviderDecorator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASMetadataProviderDecorator.java index c5e56502b..9adc221e5 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASMetadataProviderDecorator.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASMetadataProviderDecorator.java @@ -31,6 +31,7 @@ import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml2.metadata.provider.MetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IMOARefreshableMetadataProvider; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.metadata.MetadataFetcherI; import eu.eidas.auth.engine.metadata.MetadataSignerI; @@ -54,6 +55,23 @@ public class MOAeIDASMetadataProviderDecorator implements MetadataFetcherI { } + /** + * Refresh the SAML2 metadata of a specific Entity + * <br> + * <b>Info:</b> A refresh is only possible if the internal metadata provider implements + * the 'RefeshableMetadataProvider' interface + * + * @param entityId EntityID that should be refreshed + * @return true if refresh was successful, otherwise false + */ + public boolean refreshMetadata(String entityId) { + if (this.metadataprovider instanceof IMOARefreshableMetadataProvider ) + return ((IMOARefreshableMetadataProvider)this.metadataprovider).refreshMetadataProvider(entityId); + else + return false; + + } + /* (non-Javadoc) * @see eu.eidas.auth.engine.metadata.MetadataFetcherI#getEntityDescriptor(java.lang.String, eu.eidas.auth.engine.metadata.MetadataSignerI) */ diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/validation/MoaEidasConditionsValidator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/validation/MoaEidasConditionsValidator.java index d9453322f..9895ca79f 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/validation/MoaEidasConditionsValidator.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/validation/MoaEidasConditionsValidator.java @@ -56,7 +56,7 @@ public class MoaEidasConditionsValidator extends ConditionsSpecValidator { throw new ValidationException("NotBefore is required."); } - if (conditions.getNotBefore().minusMillis(Constants.CONFIG_PROPS_SKEWTIME).isAfterNow()) { + if (conditions.getNotBefore().plusMillis((int)Constants.CONFIG_PROPS_SKEWTIME_BEFORE).isAfterNow()) { throw new ValidationException("Current time is before NotBefore condition"); } @@ -64,7 +64,7 @@ public class MoaEidasConditionsValidator extends ConditionsSpecValidator { throw new ValidationException("NotOnOrAfter is required."); } - if (conditions.getNotOnOrAfter().isBeforeNow()) { + if (conditions.getNotOnOrAfter().plusMillis((int)Constants.CONFIG_PROPS_SKEWTIME_AFTER).isBeforeNow()) { throw new ValidationException("Current time is after NotOnOrAfter condition"); } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java index 7155040c6..6f1d75bfe 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java @@ -228,9 +228,9 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { //set correct SPType for this online application if (oaConfig.getBusinessService()) - authnRequestBuilder.spType(SpType.PRIVATE); + authnRequestBuilder.spType(SpType.PRIVATE.getValue()); else - authnRequestBuilder.spType(SpType.PUBLIC); + authnRequestBuilder.spType(SpType.PUBLIC.getValue()); //set service provider (eIDAS node) countryCode diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java index 45ba3d64e..17e112c4c 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java @@ -57,7 +57,8 @@ public class ReceiveAuthnResponseTask extends AbstractAuthServletTask { //validate SAML token IAuthenticationResponse samlResp = engine.unmarshallResponseAndValidate(decSamlToken, request.getRemoteHost(), - Constants.CONFIG_PROPS_SKEWTIME, + Constants.CONFIG_PROPS_SKEWTIME_BEFORE, + Constants.CONFIG_PROPS_SKEWTIME_AFTER, pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_METADATA); if (samlResp.isEncrypted()) { diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java index 47cdb4ade..dbe11c12e 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java @@ -23,10 +23,16 @@ package at.gv.egovernment.moa.id.auth.modules.eidas.utils; import at.gv.egovernment.moa.id.auth.modules.eidas.config.MOAIDCertificateManagerConfigurationImpl; +import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAProtocolEngine; import at.gv.egovernment.moa.logging.Logger; import eu.eidas.auth.engine.ProtocolEngineFactory; +import eu.eidas.auth.engine.ProtocolEngineI; +import eu.eidas.auth.engine.SamlEngineClock; +import eu.eidas.auth.engine.configuration.FixedProtocolConfigurationAccessor; +import eu.eidas.auth.engine.configuration.ProtocolEngineConfiguration; import eu.eidas.auth.engine.configuration.SamlEngineConfigurationException; import eu.eidas.auth.engine.configuration.dom.ProtocolEngineConfigurationFactory; +import eu.eidas.auth.engine.core.ProtocolProcessorI; import eu.eidas.samlengineconfig.CertificateConfigurationManager; /** @@ -95,22 +101,32 @@ public class MOAProtocolEngineFactory extends ProtocolEngineFactory { } -// public static ProtocolEngineI createProtocolEngine(String instanceName, -// ProtocolEngineConfigurationFactory protocolEngineConfigurationFactory, -// ProtocolProcessorI protocolProcessor, SamlEngineClock samlEngineClock) -// throws SamlEngineConfigurationException { -// -// ProtocolEngineConfiguration preConfiguration = protocolEngineConfigurationFactory -// .getConfiguration(instanceName); -// -// protocolProcessor.configure(); -// -// ProtocolEngineConfiguration configuration = ProtocolEngineConfiguration.builder(preConfiguration) -// .protocolProcessor(protocolProcessor).clock(samlEngineClock).build(); -// -// ProtocolEngineI samlEngine = new MOAProtocolEngine(new FixedProtocolConfigurationAccessor(configuration)); -// -// return samlEngine; -// } + public static ProtocolEngineI ownCreateProtocolEngine(String instanceName, + CertificateConfigurationManager configManager, ProtocolProcessorI protocolProcessor, + SamlEngineClock samlEngineClock) throws SamlEngineConfigurationException { + ProtocolEngineConfigurationFactory protocolEngineConfigurationFactory = new ProtocolEngineConfigurationFactory( + configManager); + + return createProtocolEngine(instanceName, protocolEngineConfigurationFactory, protocolProcessor, + samlEngineClock); + } + + public static ProtocolEngineI createProtocolEngine(String instanceName, + ProtocolEngineConfigurationFactory protocolEngineConfigurationFactory, + ProtocolProcessorI protocolProcessor, SamlEngineClock samlEngineClock) + throws SamlEngineConfigurationException { + + ProtocolEngineConfiguration preConfiguration = protocolEngineConfigurationFactory + .getConfiguration(instanceName); + + protocolProcessor.configure(); + + ProtocolEngineConfiguration configuration = ProtocolEngineConfiguration.builder(preConfiguration) + .protocolProcessor(protocolProcessor).clock(samlEngineClock).build(); + + ProtocolEngineI samlEngine = new MOAProtocolEngine(new FixedProtocolConfigurationAccessor(configuration)); + + return samlEngine; + } } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java index 8faaf1874..9683db503 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java @@ -1,675 +1,681 @@ -/* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - */ -package at.gv.egovernment.moa.id.auth.modules.eidas.utils; - -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.joda.time.DateTime; -import org.joda.time.DurationFieldType; -import org.opensaml.Configuration; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.common.Extensions; -import org.opensaml.saml2.common.impl.ExtensionsBuilder; -import org.opensaml.saml2.core.Attribute; -import org.opensaml.saml2.core.AttributeValue; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.Company; -import org.opensaml.saml2.metadata.ContactPerson; -import org.opensaml.saml2.metadata.ContactPersonTypeEnumeration; -import org.opensaml.saml2.metadata.EmailAddress; -import org.opensaml.saml2.metadata.EncryptionMethod; -import org.opensaml.saml2.metadata.EntitiesDescriptor; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.GivenName; -import org.opensaml.saml2.metadata.IDPSSODescriptor; -import org.opensaml.saml2.metadata.KeyDescriptor; -import org.opensaml.saml2.metadata.LocalizedString; -import org.opensaml.saml2.metadata.NameIDFormat; -import org.opensaml.saml2.metadata.Organization; -import org.opensaml.saml2.metadata.OrganizationDisplayName; -import org.opensaml.saml2.metadata.OrganizationName; -import org.opensaml.saml2.metadata.OrganizationURL; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.saml2.metadata.SSODescriptor; -import org.opensaml.saml2.metadata.SingleSignOnService; -import org.opensaml.saml2.metadata.SurName; -import org.opensaml.saml2.metadata.TelephoneNumber; -import org.opensaml.samlext.saml2mdattr.EntityAttributes; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.XMLObjectBuilderFactory; -import org.opensaml.xml.schema.XSString; -import org.opensaml.xml.schema.impl.XSStringBuilder; -import org.opensaml.xml.security.SecurityException; -import org.opensaml.xml.security.credential.Credential; -import org.opensaml.xml.security.credential.UsageType; -import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; -import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; -import org.opensaml.xml.signature.KeyInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableSortedSet; -import com.google.common.collect.Ordering; - -import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; -import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; -import eu.eidas.auth.commons.EIDASUtil; -import eu.eidas.auth.commons.EidasStringUtil; -import eu.eidas.auth.commons.attribute.AttributeDefinition; -import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; -import eu.eidas.auth.commons.xml.opensaml.OpenSamlHelper; -import eu.eidas.auth.engine.ProtocolEngineI; -import eu.eidas.auth.engine.core.SAMLExtensionFormat; -import eu.eidas.auth.engine.core.eidas.DigestMethod; -import eu.eidas.auth.engine.core.eidas.EidasConstants; -import eu.eidas.auth.engine.core.eidas.SPType; -import eu.eidas.auth.engine.core.eidas.SigningMethod; -import eu.eidas.auth.engine.metadata.Contact; -import eu.eidas.auth.engine.metadata.EntityDescriptorContainer; -import eu.eidas.auth.engine.metadata.MetadataConfigParams; -import eu.eidas.auth.engine.metadata.MetadataGenerator; -import eu.eidas.auth.engine.metadata.MetadataSignerI; -import eu.eidas.auth.engine.xml.opensaml.BuilderFactoryUtil; -import eu.eidas.auth.engine.xml.opensaml.CertificateUtil; -import eu.eidas.encryption.exception.UnmarshallException; -import eu.eidas.engine.exceptions.EIDASSAMLEngineException; -import eu.eidas.engine.exceptions.SAMLEngineException; - -/** - * @author tlenz - * - */ -public class MOAeIDASMetadataGenerator extends MetadataGenerator { - private static final Logger LOGGER = LoggerFactory.getLogger(MetadataGenerator.class.getName()); - - MetadataConfigParams params; - - XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); - - SPSSODescriptor spSSODescriptor = null; - - IDPSSODescriptor idpSSODescriptor = null; - - private String ssoLocation; - - /** - * @return a String representation of the entityDescriptr built based on the attributes previously set - */ - public String generateMetadata() throws EIDASSAMLEngineException { - EntityDescriptor entityDescriptor; - try { - entityDescriptor = (EntityDescriptor) builderFactory.getBuilder(EntityDescriptor.DEFAULT_ELEMENT_NAME) - .buildObject(EntityDescriptor.DEFAULT_ELEMENT_NAME); - - entityDescriptor.setEntityID(params.getEntityID()); - entityDescriptor.setOrganization(buildOrganization()); - - /**FIXME: - * HOTFIX: do not add empty contactPerson elements - */ - ContactPerson contactSupport = buildContact(ContactPersonTypeEnumeration.SUPPORT); - if (contactSupport != null) - entityDescriptor.getContactPersons().add(contactSupport); - ContactPerson contactTech = buildContact(ContactPersonTypeEnumeration.TECHNICAL); - if (contactTech != null) - entityDescriptor.getContactPersons().add(contactTech); - - entityDescriptor.setValidUntil(getExpireDate()); - - X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory(); - keyInfoGeneratorFactory.setEmitEntityCertificate(true); - Extensions e = generateExtensions(); - if (!e.getUnknownXMLObjects().isEmpty()) { - entityDescriptor.setExtensions(e); - } - if (spSSODescriptor != null) { - generateSPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); - } - if (idpSSODescriptor != null) { - generateIDPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); - } - if (params.getSpEngine() != null) { - ProtocolEngineI spEngine = params.getSpEngine(); - ((MetadataSignerI) spEngine.getSigner()).signMetadata(entityDescriptor); - } else if (params.getIdpEngine() != null) { - ProtocolEngineI idpEngine = params.getIdpEngine(); - ((MetadataSignerI) idpEngine.getSigner()).signMetadata(entityDescriptor); - } - return EidasStringUtil.toString(OpenSamlHelper.marshall(entityDescriptor, false)); - } catch (Exception ex) { - LOGGER.info("ERROR : SAMLException ", ex.getMessage()); - LOGGER.debug("ERROR : SAMLException ", ex); - throw new IllegalStateException(ex); - } - } - - private void generateSPSSODescriptor(final EntityDescriptor entityDescriptor, - final X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) - throws org.opensaml.xml.security.SecurityException, IllegalAccessException, NoSuchFieldException, - SAMLEngineException, EIDASSAMLEngineException { - //the node has SP role - spSSODescriptor.setWantAssertionsSigned(params.isWantAssertionsSigned()); - spSSODescriptor.setAuthnRequestsSigned(true); - - - /**FIXME: - * "SP" + params.getEntityID()) is not a valid XML ID attribute value - */ - //spSSODescriptor.setID(idpSSODescriptor == null ? params.getEntityID() : ("SP" + params.getEntityID())); - spSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); - - - if (params.getSPSignature() != null) { - spSSODescriptor.setSignature(params.getSPSignature()); - } - if (params.getSpSigningCredential() != null) { - spSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSpSigningCredential(), UsageType.SIGNING)); - - } else if (params.getSigningCredential() != null) { - spSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSigningCredential(), UsageType.SIGNING)); - } - - if (params.getSpEncryptionCredential() != null) { - spSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSpEncryptionCredential(), - UsageType.ENCRYPTION)); - } else if (params.getEncryptionCredential() != null) { - spSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getEncryptionCredential(), UsageType.ENCRYPTION)); - } - spSSODescriptor.addSupportedProtocol(params.getSpSamlProtocol()); - if (!StringUtils.isEmpty(params.getAssertionConsumerUrl())) { - addAssertionConsumerService(); - } - fillNameIDFormat(spSSODescriptor); - - /**FIXME: - * Double signing of SPSSODescribtor is not required - */ -// if (params.getSpEngine() != null) { -// ProtocolEngineI spEngine = params.getSpEngine(); -// ((MetadataSignerI) spEngine.getSigner()).signMetadata(spSSODescriptor); -// } - - entityDescriptor.getRoleDescriptors().add(spSSODescriptor); - - } - - private void fillNameIDFormat(SSODescriptor ssoDescriptor) throws EIDASSAMLEngineException { - NameIDFormat persistentFormat = - (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); - persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); - ssoDescriptor.getNameIDFormats().add(persistentFormat); - NameIDFormat transientFormat = - (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); - transientFormat.setFormat(SamlNameIdFormat.TRANSIENT.getNameIdFormat()); - ssoDescriptor.getNameIDFormats().add(transientFormat); - NameIDFormat unspecifiedFormat = - (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); - unspecifiedFormat.setFormat(SamlNameIdFormat.UNSPECIFIED.getNameIdFormat()); - ssoDescriptor.getNameIDFormats().add(unspecifiedFormat); - } - - private void generateIDPSSODescriptor(final EntityDescriptor entityDescriptor, - final X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) - throws org.opensaml.xml.security.SecurityException, IllegalAccessException, NoSuchFieldException, - SAMLEngineException, EIDASSAMLEngineException { - //the node has IDP role - idpSSODescriptor.setWantAuthnRequestsSigned(true); - - /**FIXME: - * "IDP" + params.getEntityID()) is not a valid XML ID attribute value - */ - //idpSSODescriptor.setID(spSSODescriptor == null ? params.getEntityID() : ("IDP" + params.getEntityID())); - idpSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); - - if (params.getIDPSignature() != null) { - idpSSODescriptor.setSignature(params.getIDPSignature()); - } - if (params.getIdpSigningCredential() != null) { - idpSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getIdpSigningCredential(), UsageType.SIGNING)); - } else if (params.getSigningCredential() != null) { - idpSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSigningCredential(), UsageType.SIGNING)); - } - if (params.getIdpEncryptionCredential() != null) { - idpSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getIdpEncryptionCredential(), - UsageType.ENCRYPTION)); - } else if (params.getEncryptionCredential() != null) { - idpSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getEncryptionCredential(), UsageType.ENCRYPTION)); - } - idpSSODescriptor.addSupportedProtocol(params.getIdpSamlProtocol()); - fillNameIDFormat(idpSSODescriptor); - - - if (params.getIdpEngine() != null) { - if (params.getIdpEngine().getProtocolProcessor() != null - && params.getIdpEngine().getProtocolProcessor().getFormat() == SAMLExtensionFormat.EIDAS10) { - - /*TODO: Only a work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata - * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. - * - * INFO: Maybe, this code can be removed in a future version of the eIDAS engine - */ - generateSupportedAttributes(idpSSODescriptor, getAllSupportedAttributes()); - } - - - /**FIXME: - * Double signing of IDPSSODescribtor is not required - */ -// ProtocolEngineI idpEngine = params.getIdpEngine(); -// ((MetadataSignerI) idpEngine.getSigner()).signMetadata(idpSSODescriptor); - } - - idpSSODescriptor.getSingleSignOnServices().addAll(buildSingleSignOnServicesBindingLocations()); - - entityDescriptor.getRoleDescriptors().add(idpSSODescriptor); - - } - - /*TODO: Only a work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata - * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. - */ - public ImmutableSortedSet<AttributeDefinition<?>> getAllSupportedAttributes() { - ImmutableSortedSet.Builder<AttributeDefinition<?>> builder = - new ImmutableSortedSet.Builder<>(Ordering.<AttributeDefinition<?>>natural()); - builder.addAll(Constants.MOA_IDP_ATTR_REGISTRY.getAttributes()); - return builder.build(); - } - - private ArrayList<SingleSignOnService> buildSingleSignOnServicesBindingLocations() - throws NoSuchFieldException, IllegalAccessException { - ArrayList<SingleSignOnService> singleSignOnServices = new ArrayList<SingleSignOnService>(); - - HashMap<String, String> bindingLocations = params.getProtocolBindingLocation(); - for (String binding : bindingLocations.keySet()) { - SingleSignOnService ssos = BuilderFactoryUtil.buildXmlObject(SingleSignOnService.class); - ssos.setBinding(binding); - ssos.setLocation(bindingLocations.get(binding)); - singleSignOnServices.add(ssos); - } - - return singleSignOnServices; - } - - /** - * @param metadata - * @return an EntityDescriptor parsed from the given String or null - */ - // TODO (commented by donydgr) Move to a eu.eidas.auth.engine.metadata.MetadataUtil ? Throw an exception if the metadata is invalid instead of returning null ? - public static EntityDescriptorContainer deserializeEntityDescriptor(String metadata) { - EntityDescriptorContainer result = new EntityDescriptorContainer(); - try { - byte[] metaDataBytes = EidasStringUtil.getBytes(metadata); - XMLObject obj = OpenSamlHelper.unmarshall(metaDataBytes); - if (obj instanceof EntityDescriptor) { - result.addEntityDescriptor((EntityDescriptor) obj, metaDataBytes); - } else if (obj instanceof EntitiesDescriptor) { - EntitiesDescriptor ed = (EntitiesDescriptor) obj; - result.setEntitiesDescriptor(ed); - result.getEntityDescriptors().addAll(((EntitiesDescriptor) obj).getEntityDescriptors()); - result.setSerializedEntitesDescriptor(metaDataBytes); - } - } catch (UnmarshallException ue) { - LOGGER.info("ERROR : unmarshalling error", ue.getMessage()); - LOGGER.debug("ERROR : unmarshalling error", ue); - } - return result; - } - - private KeyDescriptor getKeyDescriptor(X509KeyInfoGeneratorFactory keyInfoGeneratorFactory, - Credential credential, - UsageType usage) - throws NoSuchFieldException, IllegalAccessException, SecurityException, EIDASSAMLEngineException { - KeyDescriptor keyDescriptor = null; - if (credential != null) { - keyDescriptor = BuilderFactoryUtil.buildXmlObject(KeyDescriptor.class); - KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance(); - - KeyInfo keyInfo = keyInfoGenerator.generate(credential); - keyDescriptor.setUse(usage); - keyDescriptor.setKeyInfo(keyInfo); - if (usage == UsageType.ENCRYPTION && params.getEncryptionAlgorithms() != null) { - Set<String> encryptionAlgos = EIDASUtil.parseSemicolonSeparatedList(params.getEncryptionAlgorithms()); - for (String encryptionAlgo : encryptionAlgos) { - EncryptionMethod em = - (EncryptionMethod) BuilderFactoryUtil.buildXmlObject(EncryptionMethod.DEFAULT_ELEMENT_NAME); - em.setAlgorithm(encryptionAlgo); - keyDescriptor.getEncryptionMethods().add(em); - } - } - - } - return keyDescriptor; - } - - private Organization buildOrganization() { - Organization organization = null; - try { - organization = BuilderFactoryUtil.buildXmlObject(Organization.class); - - /**FIXME: - * set correct OrganizationName value if it is not fixed in next eIDAS node version - */ - OrganizationName orgName = BuilderFactoryUtil.buildXmlObject(OrganizationName.class); - orgName.setName(new LocalizedString(params.getNodeUrl(), "en")); - organization.getOrganizationNames().add(orgName); - - OrganizationDisplayName odn = BuilderFactoryUtil.buildXmlObject(OrganizationDisplayName.class); - odn.setName(new LocalizedString(params.getCountryName(), "en")); - organization.getDisplayNames().add(odn); - OrganizationURL url = BuilderFactoryUtil.buildXmlObject(OrganizationURL.class); - url.setURL(new LocalizedString(params.getNodeUrl(), "en")); - organization.getURLs().add(url); - } catch (IllegalAccessException iae) { - LOGGER.info("ERROR : error generating the Organization: {}", iae.getMessage()); - LOGGER.debug("ERROR : error generating the Organization: {}", iae); - } catch (NoSuchFieldException nfe) { - LOGGER.info("ERROR : error generating the Organization: {}", nfe.getMessage()); - LOGGER.debug("ERROR : error generating the Organization: {}", nfe); - } - return organization; - } - - private ContactPerson buildContact(ContactPersonTypeEnumeration contactType) { - ContactPerson contact = null; - try { - Contact currentContact = null; - if (contactType == ContactPersonTypeEnumeration.SUPPORT) { - currentContact = params.getSupportContact(); - } else if (contactType == ContactPersonTypeEnumeration.TECHNICAL) { - currentContact = params.getTechnicalContact(); - } else { - LOGGER.error("ERROR: unsupported contact type"); - } - contact = BuilderFactoryUtil.buildXmlObject(ContactPerson.class); - if (currentContact == null) { - LOGGER.error("ERROR: cannot retrieve contact from the configuration"); - return null; - } - - EmailAddress emailAddressObj = BuilderFactoryUtil.buildXmlObject(EmailAddress.class); - Company company = BuilderFactoryUtil.buildXmlObject(Company.class); - GivenName givenName = BuilderFactoryUtil.buildXmlObject(GivenName.class); - SurName surName = BuilderFactoryUtil.buildXmlObject(SurName.class); - TelephoneNumber phoneNumber = BuilderFactoryUtil.buildXmlObject(TelephoneNumber.class); - contact.setType(contactType); - emailAddressObj.setAddress(currentContact.getEmail()); - company.setName(currentContact.getCompany()); - givenName.setName(currentContact.getGivenName()); - surName.setName(currentContact.getSurName()); - phoneNumber.setNumber(currentContact.getPhone()); - - populateContact(contact, currentContact, emailAddressObj, company, givenName, surName, phoneNumber); - - } catch (IllegalAccessException iae) { - LOGGER.info("ERROR : error generating the Organization: {}", iae.getMessage()); - LOGGER.debug("ERROR : error generating the Organization: {}", iae); - } catch (NoSuchFieldException nfe) { - LOGGER.info("ERROR : error generating the Organization: {}", nfe.getMessage()); - LOGGER.debug("ERROR : error generating the Organization: {}", nfe); - } - return contact; - } - - private void populateContact(ContactPerson contact, - Contact currentContact, - EmailAddress emailAddressObj, - Company company, - GivenName givenName, - SurName surName, - TelephoneNumber phoneNumber) { - if (!StringUtils.isEmpty(currentContact.getEmail())) { - contact.getEmailAddresses().add(emailAddressObj); - } - if (!StringUtils.isEmpty(currentContact.getCompany())) { - contact.setCompany(company); - } - if (!StringUtils.isEmpty(currentContact.getGivenName())) { - contact.setGivenName(givenName); - } - if (!StringUtils.isEmpty(currentContact.getSurName())) { - contact.setSurName(surName); - } - if (!StringUtils.isEmpty(currentContact.getPhone())) { - contact.getTelephoneNumbers().add(phoneNumber); - } - - } - - /** - * @param engine a EIDASSamlEngine from which signing and encryption information is extracted - */ - - public void initialize(ProtocolEngineI engine) throws EIDASSAMLEngineException { - - X509Certificate decryptionCertificate = engine.getDecryptionCertificate(); - if (null != decryptionCertificate) { - params.setSpEncryptionCredential(CertificateUtil.toCredential(decryptionCertificate)); - } - params.setSigningCredential(CertificateUtil.toCredential(engine.getSigningCertificate())); - params.setIdpEngine(engine); - params.setSpEngine(engine); - } - - /** - * @param spEngine a EIDASSamlEngine for the - */ - - public void initialize(ProtocolEngineI spEngine, ProtocolEngineI idpEngine) throws EIDASSAMLEngineException { - if (idpEngine != null) { - idpEngine.getProtocolProcessor().configure(); - params.setIdpSigningCredential(CertificateUtil.toCredential(idpEngine.getSigningCertificate())); - - final X509Certificate idpEngineDecryptionCertificate = idpEngine.getDecryptionCertificate(); - if (idpEngineDecryptionCertificate != null) { - params.setIdpEncryptionCredential(CertificateUtil.toCredential(idpEngineDecryptionCertificate)); - } - - } - if (spEngine != null) { - spEngine.getProtocolProcessor().configure(); - params.setSpSigningCredential(CertificateUtil.toCredential(spEngine.getSigningCertificate())); - - final X509Certificate spEngineDecryptionCertificate = spEngine.getDecryptionCertificate(); - if (spEngineDecryptionCertificate != null) { - params.setSpEncryptionCredential(CertificateUtil.toCredential(spEngineDecryptionCertificate)); - } - } - - params.setIdpEngine(idpEngine); - params.setSpEngine(spEngine); - } - - public void addSPRole() throws EIDASSAMLEngineException { - try { - if (spSSODescriptor == null) { - spSSODescriptor = BuilderFactoryUtil.buildXmlObject(SPSSODescriptor.class); - } - } catch (IllegalAccessException iae) { - throw new EIDASSAMLEngineException(iae); - } catch (NoSuchFieldException nsfe) { - throw new EIDASSAMLEngineException(nsfe); - } - } - - public void addIDPRole() throws EIDASSAMLEngineException { - try { - if (idpSSODescriptor == null) { - idpSSODescriptor = BuilderFactoryUtil.buildXmlObject(IDPSSODescriptor.class); - } - } catch (IllegalAccessException iae) { - throw new EIDASSAMLEngineException(iae); - } catch (NoSuchFieldException nsfe) { - throw new EIDASSAMLEngineException(nsfe); - } - } - - private void generateDigest(Extensions eidasExtensions) throws EIDASSAMLEngineException { - if (!StringUtils.isEmpty(params.getDigestMethods())) { - Set<String> signatureMethods = EIDASUtil.parseSemicolonSeparatedList(params.getDigestMethods()); - Set<String> digestMethods = new HashSet<String>(); - for (String signatureMethod : signatureMethods) { - - //BUGFIX: eIDAS implementation does not allow MGF1 signature schemes - digestMethods.add(signatureMethod); - //digestMethods.add(CertificateUtil.validateDigestAlgorithm(signatureMethod)); - } - for (String digestMethod : digestMethods) { - final DigestMethod dm = (DigestMethod) BuilderFactoryUtil.buildXmlObject(DigestMethod.DEF_ELEMENT_NAME); - if (dm != null) { - dm.setAlgorithm(digestMethod); - eidasExtensions.getUnknownXMLObjects().add(dm); - } else { - LOGGER.info("BUSINESS EXCEPTION error adding DigestMethod extension"); - } - } - } - - } - - private Extensions generateExtensions() throws EIDASSAMLEngineException { - /**FIXME: BuilderFactoryUtil.generateExtension() generates extensions from SAML2 request namespace - * but SAML2 metadata namespace is required - **/ - //Extensions eidasExtensions = BuilderFactoryUtil.generateExtension(); - - ExtensionsBuilder extensionsBuilder = new ExtensionsBuilder(); - Extensions eidasExtensions = extensionsBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:metadata", "Extensions", "md"); - - if (params.getAssuranceLevel() != null) { - generateLoA(eidasExtensions); - } - if (!StringUtils.isEmpty(params.getSpType())) { - final SPType spTypeObj = (SPType) BuilderFactoryUtil.buildXmlObject(SPType.DEF_ELEMENT_NAME); - if (spTypeObj != null) { - spTypeObj.setSPType(params.getSpType()); - eidasExtensions.getUnknownXMLObjects().add(spTypeObj); - } else { - LOGGER.info("BUSINESS EXCEPTION error adding SPType extension"); - } - } - generateDigest(eidasExtensions); - - if (!StringUtils.isEmpty(params.getSigningMethods())) { - Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(params.getSigningMethods()); - for (String signMethod : signMethods) { - final SigningMethod sm = - (SigningMethod) BuilderFactoryUtil.buildXmlObject(SigningMethod.DEF_ELEMENT_NAME); - if (sm != null) { - sm.setAlgorithm(signMethod); - eidasExtensions.getUnknownXMLObjects().add(sm); - } else { - LOGGER.info("BUSINESS EXCEPTION error adding SigningMethod extension"); - } - } - } - return eidasExtensions; - } - - private void generateLoA(Extensions eidasExtensions) throws EIDASSAMLEngineException { - EntityAttributes loa = - (EntityAttributes) BuilderFactoryUtil.buildXmlObject(EntityAttributes.DEFAULT_ELEMENT_NAME); - Attribute loaAttrib = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); - loaAttrib.setName(EidasConstants.LEVEL_OF_ASSURANCE_NAME); - loaAttrib.setNameFormat(Attribute.URI_REFERENCE); - XSStringBuilder stringBuilder = - (XSStringBuilder) Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME); - XSString stringValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME); - stringValue.setValue(params.getAssuranceLevel()); - loaAttrib.getAttributeValues().add(stringValue); - loa.getAttributes().add(loaAttrib); - eidasExtensions.getUnknownXMLObjects().add(loa); - - } - - private static final Set<String> DEFAULT_BINDING = new HashSet<String>() {{ - this.add(SAMLConstants.SAML2_POST_BINDING_URI); - }}; - - private void addAssertionConsumerService() throws EIDASSAMLEngineException { - int index = 0; - Set<String> bindings = params.getProtocolBinding().isEmpty() ? DEFAULT_BINDING : params.getProtocolBinding(); - for (String binding : bindings) { - AssertionConsumerService asc = (AssertionConsumerService) BuilderFactoryUtil.buildXmlObject( - AssertionConsumerService.DEFAULT_ELEMENT_NAME); - asc.setLocation(params.getAssertionConsumerUrl()); - asc.setBinding(checkBinding(binding)); - asc.setIndex(index); - if (index == 0) { - asc.setIsDefault(true); - } - index++; - spSSODescriptor.getAssertionConsumerServices().add(asc); - } - } - - private String checkBinding(String binding) { - if (binding != null && (binding.equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) || binding.equals( - SAMLConstants.SAML2_POST_BINDING_URI))) { - return binding; - } - return SAMLConstants.SAML2_POST_BINDING_URI; - } - - private DateTime getExpireDate() { - DateTime expiryDate = DateTime.now(); - expiryDate = - expiryDate.withFieldAdded(DurationFieldType.seconds(), (int) (getConfigParams().getValidityDuration())); - return expiryDate; - } - - private void generateSupportedAttributes(IDPSSODescriptor idpssoDescriptor, - ImmutableSortedSet<AttributeDefinition<?>> attributeDefinitions) - throws EIDASSAMLEngineException { - List<Attribute> attributes = idpssoDescriptor.getAttributes(); - for (AttributeDefinition<?> attributeDefinition : attributeDefinitions) { - Attribute a = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); - a.setName(attributeDefinition.getNameUri().toASCIIString()); - a.setFriendlyName(attributeDefinition.getFriendlyName()); - a.setNameFormat(Attribute.URI_REFERENCE); - attributes.add(a); - } - } - - public MetadataConfigParams getConfigParams() { - return params; - } - - public void setConfigParams(MetadataConfigParams params) { - this.params = params; - } - -} +///* +// * Copyright 2014 Federal Chancellery Austria +// * MOA-ID has been developed in a cooperation between BRZ, the Federal +// * Chancellery Austria - ICT staff unit, and Graz University of Technology. +// * +// * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by +// * the European Commission - subsequent versions of the EUPL (the "Licence"); +// * You may not use this work except in compliance with the Licence. +// * You may obtain a copy of the Licence at: +// * http://www.osor.eu/eupl/ +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the Licence is distributed on an "AS IS" basis, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the Licence for the specific language governing permissions and +// * limitations under the Licence. +// * +// * This product combines work with different licenses. See the "NOTICE" text +// * file for details on the various modules and licenses. +// * The "NOTICE" text file is part of the distribution. Any derivative works +// * that you distribute must include a readable copy of the "NOTICE" text file. +// */ +//package at.gv.egovernment.moa.id.auth.modules.eidas.utils; +// +//import java.security.cert.X509Certificate; +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.HashSet; +//import java.util.List; +//import java.util.Set; +// +//import org.apache.commons.lang.StringUtils; +//import org.joda.time.DateTime; +//import org.joda.time.DurationFieldType; +//import org.opensaml.Configuration; +//import org.opensaml.common.xml.SAMLConstants; +//import org.opensaml.saml2.common.Extensions; +//import org.opensaml.saml2.common.impl.ExtensionsBuilder; +//import org.opensaml.saml2.core.Attribute; +//import org.opensaml.saml2.core.AttributeValue; +//import org.opensaml.saml2.metadata.AssertionConsumerService; +//import org.opensaml.saml2.metadata.Company; +//import org.opensaml.saml2.metadata.ContactPerson; +//import org.opensaml.saml2.metadata.ContactPersonTypeEnumeration; +//import org.opensaml.saml2.metadata.EmailAddress; +//import org.opensaml.saml2.metadata.EncryptionMethod; +//import org.opensaml.saml2.metadata.EntitiesDescriptor; +//import org.opensaml.saml2.metadata.EntityDescriptor; +//import org.opensaml.saml2.metadata.GivenName; +//import org.opensaml.saml2.metadata.IDPSSODescriptor; +//import org.opensaml.saml2.metadata.KeyDescriptor; +//import org.opensaml.saml2.metadata.LocalizedString; +//import org.opensaml.saml2.metadata.NameIDFormat; +//import org.opensaml.saml2.metadata.Organization; +//import org.opensaml.saml2.metadata.OrganizationDisplayName; +//import org.opensaml.saml2.metadata.OrganizationName; +//import org.opensaml.saml2.metadata.OrganizationURL; +//import org.opensaml.saml2.metadata.SPSSODescriptor; +//import org.opensaml.saml2.metadata.SSODescriptor; +//import org.opensaml.saml2.metadata.SingleSignOnService; +//import org.opensaml.saml2.metadata.SurName; +//import org.opensaml.saml2.metadata.TelephoneNumber; +//import org.opensaml.samlext.saml2mdattr.EntityAttributes; +//import org.opensaml.xml.XMLObject; +//import org.opensaml.xml.XMLObjectBuilderFactory; +//import org.opensaml.xml.schema.XSString; +//import org.opensaml.xml.schema.impl.XSStringBuilder; +//import org.opensaml.xml.security.SecurityException; +//import org.opensaml.xml.security.credential.Credential; +//import org.opensaml.xml.security.credential.UsageType; +//import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +//import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; +//import org.opensaml.xml.signature.KeyInfo; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import com.google.common.collect.ImmutableSortedSet; +//import com.google.common.collect.Ordering; +// +//import at.gv.egovernment.moa.id.commons.db.dao.config.deprecated.Contact; +//import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +//import eu.eidas.auth.commons.EIDASUtil; +//import eu.eidas.auth.commons.EidasStringUtil; +//import eu.eidas.auth.commons.attribute.AttributeDefinition; +//import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; +//import eu.eidas.auth.commons.xml.opensaml.OpenSamlHelper; +//import eu.eidas.auth.engine.ProtocolEngineI; +//import eu.eidas.auth.engine.core.SAMLExtensionFormat; +//import eu.eidas.auth.engine.core.eidas.DigestMethod; +//import eu.eidas.auth.engine.core.eidas.EidasConstants; +//import eu.eidas.auth.engine.core.eidas.SPType; +//import eu.eidas.auth.engine.core.eidas.SigningMethod; +//import eu.eidas.auth.engine.metadata.EntityDescriptorContainer; +//import eu.eidas.auth.engine.metadata.MetadataConfigParams; +//import eu.eidas.auth.engine.metadata.MetadataGenerator; +//import eu.eidas.auth.engine.metadata.MetadataSignerI; +//import eu.eidas.auth.engine.xml.opensaml.BuilderFactoryUtil; +//import eu.eidas.auth.engine.xml.opensaml.CertificateUtil; +//import eu.eidas.encryption.exception.UnmarshallException; +//import eu.eidas.engine.exceptions.EIDASSAMLEngineException; +//import eu.eidas.engine.exceptions.SAMLEngineException; +// +///** +// * @author tlenz +// * +// */ +//public class MOAeIDASMetadataGenerator extends MetadataGenerator { +// private static final Logger LOGGER = LoggerFactory.getLogger(MetadataGenerator.class.getName()); +// +// MetadataConfigParams params; +// +// XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); +// +// SPSSODescriptor spSSODescriptor = null; +// +// IDPSSODescriptor idpSSODescriptor = null; +// +// private String ssoLocation; +// +// /** +// * @return a String representation of the entityDescriptr built based on the attributes previously set +// */ +// public String generateMetadata() throws EIDASSAMLEngineException { +// EntityDescriptor entityDescriptor; +// try { +// entityDescriptor = (EntityDescriptor) builderFactory.getBuilder(EntityDescriptor.DEFAULT_ELEMENT_NAME) +// .buildObject(EntityDescriptor.DEFAULT_ELEMENT_NAME); +// +// entityDescriptor.setEntityID(params.getEntityID()); +// entityDescriptor.setOrganization(buildOrganization()); +// +// /**FIXME: +// * HOTFIX: do not add empty contactPerson elements +// */ +// ContactPerson contactSupport = buildContact(ContactPersonTypeEnumeration.SUPPORT); +// if (contactSupport != null) +// entityDescriptor.getContactPersons().add(contactSupport); +// ContactPerson contactTech = buildContact(ContactPersonTypeEnumeration.TECHNICAL); +// if (contactTech != null) +// entityDescriptor.getContactPersons().add(contactTech); +// +// entityDescriptor.setValidUntil(getExpireDate()); +// +// X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory(); +// keyInfoGeneratorFactory.setEmitEntityCertificate(true); +// Extensions e = generateExtensions(); +// if (!e.getUnknownXMLObjects().isEmpty()) { +// entityDescriptor.setExtensions(e); +// } +// if (spSSODescriptor != null) { +// generateSPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); +// } +// if (idpSSODescriptor != null) { +// generateIDPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); +// } +// if (params.getSpEngine() != null) { +// ProtocolEngineI spEngine = params.getSpEngine(); +// ((MetadataSignerI) spEngine.getSigner()).signMetadata(entityDescriptor); +// } else if (params.getIdpEngine() != null) { +// ProtocolEngineI idpEngine = params.getIdpEngine(); +// ((MetadataSignerI) idpEngine.getSigner()).signMetadata(entityDescriptor); +// } +// return EidasStringUtil.toString(OpenSamlHelper.marshall(entityDescriptor, false)); +// } catch (Exception ex) { +// LOGGER.info("ERROR : SAMLException ", ex.getMessage()); +// LOGGER.debug("ERROR : SAMLException ", ex); +// throw new IllegalStateException(ex); +// } +// } +// +// private void generateSPSSODescriptor(final EntityDescriptor entityDescriptor, +// final X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) +// throws org.opensaml.xml.security.SecurityException, IllegalAccessException, NoSuchFieldException, +// SAMLEngineException, EIDASSAMLEngineException { +// //the node has SP role +// spSSODescriptor.setWantAssertionsSigned(params.isWantAssertionsSigned()); +// spSSODescriptor.setAuthnRequestsSigned(true); +// +// +// /**FIXME: +// * "SP" + params.getEntityID()) is not a valid XML ID attribute value +// */ +// //spSSODescriptor.setID(idpSSODescriptor == null ? params.getEntityID() : ("SP" + params.getEntityID())); +// spSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); +// +// +// if (params.getSPSignature() != null) { +// spSSODescriptor.setSignature(params.getSPSignature()); +// } +// if (params.getSpSigningCredential() != null) { +// spSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSpSigningCredential(), UsageType.SIGNING)); +// +// } else if (params.getSigningCredential() != null) { +// spSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSigningCredential(), UsageType.SIGNING)); +// } +// +// if (params.getSpEncryptionCredential() != null) { +// spSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSpEncryptionCredential(), +// UsageType.ENCRYPTION)); +// } else if (params.getEncryptionCredential() != null) { +// spSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getEncryptionCredential(), UsageType.ENCRYPTION)); +// } +// spSSODescriptor.addSupportedProtocol(params.getSpSamlProtocol()); +// if (!StringUtils.isEmpty(params.getAssertionConsumerUrl())) { +// addAssertionConsumerService(); +// } +// +// //FIX: Austrian eIDAS node SP only needs persistent identifiers +// NameIDFormat persistentFormat = +// (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); +// persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); +// spSSODescriptor.getNameIDFormats().add(persistentFormat); +// +// /**FIXME: +// * Double signing of SPSSODescribtor is not required +// */ +//// if (params.getSpEngine() != null) { +//// ProtocolEngineI spEngine = params.getSpEngine(); +//// ((MetadataSignerI) spEngine.getSigner()).signMetadata(spSSODescriptor); +//// } +// +// entityDescriptor.getRoleDescriptors().add(spSSODescriptor); +// +// } +// +// private void fillIDPNameIDFormat(SSODescriptor ssoDescriptor) throws EIDASSAMLEngineException { +// NameIDFormat persistentFormat = +// (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); +// persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); +// ssoDescriptor.getNameIDFormats().add(persistentFormat); +// NameIDFormat transientFormat = +// (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); +// transientFormat.setFormat(SamlNameIdFormat.TRANSIENT.getNameIdFormat()); +// ssoDescriptor.getNameIDFormats().add(transientFormat); +// NameIDFormat unspecifiedFormat = +// (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); +// unspecifiedFormat.setFormat(SamlNameIdFormat.UNSPECIFIED.getNameIdFormat()); +// ssoDescriptor.getNameIDFormats().add(unspecifiedFormat); +// } +// +// private void generateIDPSSODescriptor(final EntityDescriptor entityDescriptor, +// final X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) +// throws org.opensaml.xml.security.SecurityException, IllegalAccessException, NoSuchFieldException, +// SAMLEngineException, EIDASSAMLEngineException { +// //the node has IDP role +// idpSSODescriptor.setWantAuthnRequestsSigned(true); +// +// /**FIXME: +// * "IDP" + params.getEntityID()) is not a valid XML ID attribute value +// */ +// //idpSSODescriptor.setID(spSSODescriptor == null ? params.getEntityID() : ("IDP" + params.getEntityID())); +// idpSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); +// +// if (params.getIDPSignature() != null) { +// idpSSODescriptor.setSignature(params.getIDPSignature()); +// } +// if (params.getIdpSigningCredential() != null) { +// idpSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getIdpSigningCredential(), UsageType.SIGNING)); +// } else if (params.getSigningCredential() != null) { +// idpSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSigningCredential(), UsageType.SIGNING)); +// } +// if (params.getIdpEncryptionCredential() != null) { +// idpSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getIdpEncryptionCredential(), +// UsageType.ENCRYPTION)); +// } else if (params.getEncryptionCredential() != null) { +// idpSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getEncryptionCredential(), UsageType.ENCRYPTION)); +// } +// idpSSODescriptor.addSupportedProtocol(params.getIdpSamlProtocol()); +// +// //Austrian eIDAS node IDP can provided persistent, transient, and unspecified identifiers +// fillIDPNameIDFormat(idpSSODescriptor); +// +// +// if (params.getIdpEngine() != null) { +// if (params.getIdpEngine().getProtocolProcessor() != null +// && params.getIdpEngine().getProtocolProcessor().getFormat() == SAMLExtensionFormat.EIDAS10) { +// +// generateSupportedAttributes(idpSSODescriptor, getAllSupportedAttributes()); +// } +// +// +// /**FIXME: +// * Double signing of IDPSSODescribtor is not required +// */ +//// ProtocolEngineI idpEngine = params.getIdpEngine(); +//// ((MetadataSignerI) idpEngine.getSigner()).signMetadata(idpSSODescriptor); +// } +// +// idpSSODescriptor.getSingleSignOnServices().addAll(buildSingleSignOnServicesBindingLocations()); +// +// entityDescriptor.getRoleDescriptors().add(idpSSODescriptor); +// +// } +// +// /* FIX: Work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata +// * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. +// */ +// public ImmutableSortedSet<AttributeDefinition<?>> getAllSupportedAttributes() { +// ImmutableSortedSet.Builder<AttributeDefinition<?>> builder = +// new ImmutableSortedSet.Builder<>(Ordering.<AttributeDefinition<?>>natural()); +// +// for (String attr : eIDASAttributeBuilder.getAllProvideableeIDASAttributes()) { +// AttributeDefinition<?> supAttr = params.getIdpEngine().getProtocolProcessor().getAttributeDefinitionNullable(attr); +// builder.add(supAttr); +// } +// +// return builder.build(); +// } +// +// private ArrayList<SingleSignOnService> buildSingleSignOnServicesBindingLocations() +// throws NoSuchFieldException, IllegalAccessException { +// ArrayList<SingleSignOnService> singleSignOnServices = new ArrayList<SingleSignOnService>(); +// +// HashMap<String, String> bindingLocations = params.getProtocolBindingLocation(); +// for (String binding : bindingLocations.keySet()) { +// SingleSignOnService ssos = BuilderFactoryUtil.buildXmlObject(SingleSignOnService.class); +// ssos.setBinding(binding); +// ssos.setLocation(bindingLocations.get(binding)); +// singleSignOnServices.add(ssos); +// } +// +// return singleSignOnServices; +// } +// +// /** +// * @param metadata +// * @return an EntityDescriptor parsed from the given String or null +// */ +// // TODO (commented by donydgr) Move to a eu.eidas.auth.engine.metadata.MetadataUtil ? Throw an exception if the metadata is invalid instead of returning null ? +// public static EntityDescriptorContainer deserializeEntityDescriptor(String metadata) { +// EntityDescriptorContainer result = new EntityDescriptorContainer(); +// try { +// byte[] metaDataBytes = EidasStringUtil.getBytes(metadata); +// XMLObject obj = OpenSamlHelper.unmarshall(metaDataBytes); +// if (obj instanceof EntityDescriptor) { +// result.addEntityDescriptor((EntityDescriptor) obj, metaDataBytes); +// } else if (obj instanceof EntitiesDescriptor) { +// EntitiesDescriptor ed = (EntitiesDescriptor) obj; +// result.setEntitiesDescriptor(ed); +// result.getEntityDescriptors().addAll(((EntitiesDescriptor) obj).getEntityDescriptors()); +// result.setSerializedEntitesDescriptor(metaDataBytes); +// } +// } catch (UnmarshallException ue) { +// LOGGER.info("ERROR : unmarshalling error", ue.getMessage()); +// LOGGER.debug("ERROR : unmarshalling error", ue); +// } +// return result; +// } +// +// private KeyDescriptor getKeyDescriptor(X509KeyInfoGeneratorFactory keyInfoGeneratorFactory, +// Credential credential, +// UsageType usage) +// throws NoSuchFieldException, IllegalAccessException, SecurityException, EIDASSAMLEngineException { +// KeyDescriptor keyDescriptor = null; +// if (credential != null) { +// keyDescriptor = BuilderFactoryUtil.buildXmlObject(KeyDescriptor.class); +// KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance(); +// +// KeyInfo keyInfo = keyInfoGenerator.generate(credential); +// keyDescriptor.setUse(usage); +// keyDescriptor.setKeyInfo(keyInfo); +// if (usage == UsageType.ENCRYPTION && params.getEncryptionAlgorithms() != null) { +// Set<String> encryptionAlgos = EIDASUtil.parseSemicolonSeparatedList(params.getEncryptionAlgorithms()); +// for (String encryptionAlgo : encryptionAlgos) { +// EncryptionMethod em = +// (EncryptionMethod) BuilderFactoryUtil.buildXmlObject(EncryptionMethod.DEFAULT_ELEMENT_NAME); +// em.setAlgorithm(encryptionAlgo); +// keyDescriptor.getEncryptionMethods().add(em); +// } +// } +// +// } +// return keyDescriptor; +// } +// +// private Organization buildOrganization() { +// Organization organization = null; +// try { +// organization = BuilderFactoryUtil.buildXmlObject(Organization.class); +// +// /**FIXME: +// * set correct OrganizationName value if it is not fixed in next eIDAS node version +// */ +// OrganizationName orgName = BuilderFactoryUtil.buildXmlObject(OrganizationName.class); +// orgName.setName(new LocalizedString(params.getNodeUrl(), "en")); +// organization.getOrganizationNames().add(orgName); +// +// OrganizationDisplayName odn = BuilderFactoryUtil.buildXmlObject(OrganizationDisplayName.class); +// odn.setName(new LocalizedString(params.getCountryName(), "en")); +// organization.getDisplayNames().add(odn); +// OrganizationURL url = BuilderFactoryUtil.buildXmlObject(OrganizationURL.class); +// url.setURL(new LocalizedString(params.getNodeUrl(), "en")); +// organization.getURLs().add(url); +// } catch (IllegalAccessException iae) { +// LOGGER.info("ERROR : error generating the Organization: {}", iae.getMessage()); +// LOGGER.debug("ERROR : error generating the Organization: {}", iae); +// } catch (NoSuchFieldException nfe) { +// LOGGER.info("ERROR : error generating the Organization: {}", nfe.getMessage()); +// LOGGER.debug("ERROR : error generating the Organization: {}", nfe); +// } +// return organization; +// } +// +// private ContactPerson buildContact(ContactPersonTypeEnumeration contactType) { +// ContactPerson contact = null; +// try { +// Contact currentContact = null; +// if (contactType == ContactPersonTypeEnumeration.SUPPORT) { +// currentContact = params.getSupportContact(); +// } else if (contactType == ContactPersonTypeEnumeration.TECHNICAL) { +// currentContact = params.getTechnicalContact(); +// } else { +// LOGGER.error("ERROR: unsupported contact type"); +// } +// contact = BuilderFactoryUtil.buildXmlObject(ContactPerson.class); +// if (currentContact == null) { +// LOGGER.error("ERROR: cannot retrieve contact from the configuration"); +// return null; +// } +// +// EmailAddress emailAddressObj = BuilderFactoryUtil.buildXmlObject(EmailAddress.class); +// Company company = BuilderFactoryUtil.buildXmlObject(Company.class); +// GivenName givenName = BuilderFactoryUtil.buildXmlObject(GivenName.class); +// SurName surName = BuilderFactoryUtil.buildXmlObject(SurName.class); +// TelephoneNumber phoneNumber = BuilderFactoryUtil.buildXmlObject(TelephoneNumber.class); +// contact.setType(contactType); +// emailAddressObj.setAddress(currentContact.getEmail()); +// company.setName(currentContact.getCompany()); +// givenName.setName(currentContact.getGivenName()); +// surName.setName(currentContact.getSurName()); +// phoneNumber.setNumber(currentContact.getPhone()); +// +// populateContact(contact, currentContact, emailAddressObj, company, givenName, surName, phoneNumber); +// +// } catch (IllegalAccessException iae) { +// LOGGER.info("ERROR : error generating the Organization: {}", iae.getMessage()); +// LOGGER.debug("ERROR : error generating the Organization: {}", iae); +// } catch (NoSuchFieldException nfe) { +// LOGGER.info("ERROR : error generating the Organization: {}", nfe.getMessage()); +// LOGGER.debug("ERROR : error generating the Organization: {}", nfe); +// } +// return contact; +// } +// +// private void populateContact(ContactPerson contact, +// Contact currentContact, +// EmailAddress emailAddressObj, +// Company company, +// GivenName givenName, +// SurName surName, +// TelephoneNumber phoneNumber) { +// if (!StringUtils.isEmpty(currentContact.getEmail())) { +// contact.getEmailAddresses().add(emailAddressObj); +// } +// if (!StringUtils.isEmpty(currentContact.getCompany())) { +// contact.setCompany(company); +// } +// if (!StringUtils.isEmpty(currentContact.getGivenName())) { +// contact.setGivenName(givenName); +// } +// if (!StringUtils.isEmpty(currentContact.getSurName())) { +// contact.setSurName(surName); +// } +// if (!StringUtils.isEmpty(currentContact.getPhone())) { +// contact.getTelephoneNumbers().add(phoneNumber); +// } +// +// } +// +// /** +// * @param engine a EIDASSamlEngine from which signing and encryption information is extracted +// */ +// +// public void initialize(ProtocolEngineI engine) throws EIDASSAMLEngineException { +// +// X509Certificate decryptionCertificate = engine.getDecryptionCertificate(); +// if (null != decryptionCertificate) { +// params.setSpEncryptionCredential(CertificateUtil.toCredential(decryptionCertificate)); +// } +// params.setSigningCredential(CertificateUtil.toCredential(engine.getSigningCertificate())); +// params.setIdpEngine(engine); +// params.setSpEngine(engine); +// } +// +// /** +// * @param spEngine a EIDASSamlEngine for the +// */ +// +// public void initialize(ProtocolEngineI spEngine, ProtocolEngineI idpEngine) throws EIDASSAMLEngineException { +// if (idpEngine != null) { +// idpEngine.getProtocolProcessor().configure(); +// params.setIdpSigningCredential(CertificateUtil.toCredential(idpEngine.getSigningCertificate())); +// +// final X509Certificate idpEngineDecryptionCertificate = idpEngine.getDecryptionCertificate(); +// if (idpEngineDecryptionCertificate != null) { +// params.setIdpEncryptionCredential(CertificateUtil.toCredential(idpEngineDecryptionCertificate)); +// } +// +// } +// if (spEngine != null) { +// spEngine.getProtocolProcessor().configure(); +// params.setSpSigningCredential(CertificateUtil.toCredential(spEngine.getSigningCertificate())); +// +// final X509Certificate spEngineDecryptionCertificate = spEngine.getDecryptionCertificate(); +// if (spEngineDecryptionCertificate != null) { +// params.setSpEncryptionCredential(CertificateUtil.toCredential(spEngineDecryptionCertificate)); +// } +// } +// +// params.setIdpEngine(idpEngine); +// params.setSpEngine(spEngine); +// } +// +// public void addSPRole() throws EIDASSAMLEngineException { +// try { +// if (spSSODescriptor == null) { +// spSSODescriptor = BuilderFactoryUtil.buildXmlObject(SPSSODescriptor.class); +// } +// } catch (IllegalAccessException iae) { +// throw new EIDASSAMLEngineException(iae); +// } catch (NoSuchFieldException nsfe) { +// throw new EIDASSAMLEngineException(nsfe); +// } +// } +// +// public void addIDPRole() throws EIDASSAMLEngineException { +// try { +// if (idpSSODescriptor == null) { +// idpSSODescriptor = BuilderFactoryUtil.buildXmlObject(IDPSSODescriptor.class); +// } +// } catch (IllegalAccessException iae) { +// throw new EIDASSAMLEngineException(iae); +// } catch (NoSuchFieldException nsfe) { +// throw new EIDASSAMLEngineException(nsfe); +// } +// } +// +// private void generateDigest(Extensions eidasExtensions) throws EIDASSAMLEngineException { +// if (!StringUtils.isEmpty(params.getDigestMethods())) { +// Set<String> signatureMethods = EIDASUtil.parseSemicolonSeparatedList(params.getDigestMethods()); +// Set<String> digestMethods = new HashSet<String>(); +// for (String signatureMethod : signatureMethods) { +// +// //BUGFIX: eIDAS implementation does not allow MGF1 signature schemes +// digestMethods.add(signatureMethod); +// //digestMethods.add(CertificateUtil.validateDigestAlgorithm(signatureMethod)); +// } +// for (String digestMethod : digestMethods) { +// final DigestMethod dm = (DigestMethod) BuilderFactoryUtil.buildXmlObject(DigestMethod.DEF_ELEMENT_NAME); +// if (dm != null) { +// dm.setAlgorithm(digestMethod); +// eidasExtensions.getUnknownXMLObjects().add(dm); +// } else { +// LOGGER.info("BUSINESS EXCEPTION error adding DigestMethod extension"); +// } +// } +// } +// +// } +// +// private Extensions generateExtensions() throws EIDASSAMLEngineException { +// /**FIXME: BuilderFactoryUtil.generateExtension() generates extensions from SAML2 request namespace +// * but SAML2 metadata namespace is required +// **/ +// //Extensions eidasExtensions = BuilderFactoryUtil.generateExtension(); +// +// ExtensionsBuilder extensionsBuilder = new ExtensionsBuilder(); +// Extensions eidasExtensions = extensionsBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:metadata", "Extensions", "md"); +// +// if (params.getAssuranceLevel() != null) { +// generateLoA(eidasExtensions); +// } +// if (!StringUtils.isEmpty(params.getSpType())) { +// final SPType spTypeObj = (SPType) BuilderFactoryUtil.buildXmlObject(SPType.DEF_ELEMENT_NAME); +// if (spTypeObj != null) { +// spTypeObj.setSPType(params.getSpType()); +// eidasExtensions.getUnknownXMLObjects().add(spTypeObj); +// } else { +// LOGGER.info("BUSINESS EXCEPTION error adding SPType extension"); +// } +// } +// generateDigest(eidasExtensions); +// +// if (!StringUtils.isEmpty(params.getSigningMethods())) { +// Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(params.getSigningMethods()); +// for (String signMethod : signMethods) { +// final SigningMethod sm = +// (SigningMethod) BuilderFactoryUtil.buildXmlObject(SigningMethod.DEF_ELEMENT_NAME); +// if (sm != null) { +// sm.setAlgorithm(signMethod); +// eidasExtensions.getUnknownXMLObjects().add(sm); +// } else { +// LOGGER.info("BUSINESS EXCEPTION error adding SigningMethod extension"); +// } +// } +// } +// return eidasExtensions; +// } +// +// private void generateLoA(Extensions eidasExtensions) throws EIDASSAMLEngineException { +// EntityAttributes loa = +// (EntityAttributes) BuilderFactoryUtil.buildXmlObject(EntityAttributes.DEFAULT_ELEMENT_NAME); +// Attribute loaAttrib = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); +// loaAttrib.setName(EidasConstants.LEVEL_OF_ASSURANCE_NAME); +// loaAttrib.setNameFormat(Attribute.URI_REFERENCE); +// XSStringBuilder stringBuilder = +// (XSStringBuilder) Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME); +// XSString stringValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME); +// stringValue.setValue(params.getAssuranceLevel()); +// loaAttrib.getAttributeValues().add(stringValue); +// loa.getAttributes().add(loaAttrib); +// eidasExtensions.getUnknownXMLObjects().add(loa); +// +// } +// +// private static final Set<String> DEFAULT_BINDING = new HashSet<String>() {{ +// this.add(SAMLConstants.SAML2_POST_BINDING_URI); +// }}; +// +// private void addAssertionConsumerService() throws EIDASSAMLEngineException { +// int index = 0; +// Set<String> bindings = params.getProtocolBinding().isEmpty() ? DEFAULT_BINDING : params.getProtocolBinding(); +// for (String binding : bindings) { +// AssertionConsumerService asc = (AssertionConsumerService) BuilderFactoryUtil.buildXmlObject( +// AssertionConsumerService.DEFAULT_ELEMENT_NAME); +// asc.setLocation(params.getAssertionConsumerUrl()); +// asc.setBinding(checkBinding(binding)); +// asc.setIndex(index); +// if (index == 0) { +// asc.setIsDefault(true); +// } +// index++; +// spSSODescriptor.getAssertionConsumerServices().add(asc); +// } +// } +// +// private String checkBinding(String binding) { +// if (binding != null && (binding.equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) || binding.equals( +// SAMLConstants.SAML2_POST_BINDING_URI))) { +// return binding; +// } +// return SAMLConstants.SAML2_POST_BINDING_URI; +// } +// +// private DateTime getExpireDate() { +// DateTime expiryDate = DateTime.now(); +// expiryDate = +// expiryDate.withFieldAdded(DurationFieldType.seconds(), (int) (getConfigParams().getValidityDuration())); +// return expiryDate; +// } +// +// private void generateSupportedAttributes(IDPSSODescriptor idpssoDescriptor, +// ImmutableSortedSet<AttributeDefinition<?>> attributeDefinitions) +// throws EIDASSAMLEngineException { +// List<Attribute> attributes = idpssoDescriptor.getAttributes(); +// for (AttributeDefinition<?> attributeDefinition : attributeDefinitions) { +// Attribute a = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); +// a.setName(attributeDefinition.getNameUri().toASCIIString()); +// a.setFriendlyName(attributeDefinition.getFriendlyName()); +// a.setNameFormat(Attribute.URI_REFERENCE); +// attributes.add(a); +// } +// } +// +// public MetadataConfigParams getConfigParams() { +// return params; +// } +// +// public void setConfigParams(MetadataConfigParams params) { +// this.params = params; +// } +// +//} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/NewMoaEidasMetadata.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/NewMoaEidasMetadata.java new file mode 100644 index 000000000..bb52d2ffe --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/NewMoaEidasMetadata.java @@ -0,0 +1,602 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.eidas.utils; + +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.DateTime; +import org.joda.time.DurationFieldType; +import org.opensaml.Configuration; +import org.opensaml.saml2.common.Extensions; +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.core.AttributeValue; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.Company; +import org.opensaml.saml2.metadata.ContactPerson; +import org.opensaml.saml2.metadata.ContactPersonTypeEnumeration; +import org.opensaml.saml2.metadata.EmailAddress; +import org.opensaml.saml2.metadata.EncryptionMethod; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.GivenName; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.KeyDescriptor; +import org.opensaml.saml2.metadata.LocalizedString; +import org.opensaml.saml2.metadata.NameIDFormat; +import org.opensaml.saml2.metadata.Organization; +import org.opensaml.saml2.metadata.OrganizationDisplayName; +import org.opensaml.saml2.metadata.OrganizationName; +import org.opensaml.saml2.metadata.OrganizationURL; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml2.metadata.SSODescriptor; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.saml2.metadata.SurName; +import org.opensaml.saml2.metadata.TelephoneNumber; +import org.opensaml.samlext.saml2mdattr.EntityAttributes; +import org.opensaml.xml.XMLObjectBuilderFactory; +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.schema.impl.XSStringBuilder; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; +import org.opensaml.xml.signature.KeyInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Ordering; + +import eu.eidas.auth.commons.EIDASUtil; +import eu.eidas.auth.commons.EidasStringUtil; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; +import eu.eidas.auth.commons.xml.opensaml.OpenSamlHelper; +import eu.eidas.auth.engine.ProtocolEngineI; +import eu.eidas.auth.engine.core.SAMLExtensionFormat; +import eu.eidas.auth.engine.core.eidas.DigestMethod; +import eu.eidas.auth.engine.core.eidas.SPType; +import eu.eidas.auth.engine.core.eidas.SigningMethod; +import eu.eidas.auth.engine.metadata.ContactData; +import eu.eidas.auth.engine.metadata.EidasMetadata; +import eu.eidas.auth.engine.metadata.MetadataConfigParams; +import eu.eidas.auth.engine.metadata.MetadataSignerI; +import eu.eidas.auth.engine.xml.opensaml.BuilderFactoryUtil; +import eu.eidas.auth.engine.xml.opensaml.CertificateUtil; +import eu.eidas.engine.exceptions.EIDASSAMLEngineException; +import eu.eidas.engine.exceptions.SAMLEngineException; +import eu.eidas.util.Preconditions; + +/** + * @author tlenz + * + * MOA specific implementation of {@link EidasMetadata} + * This version fix some bugs<br> + * <ul> + * <li>Does not add an encryption certificated to IDPSSODescriptor</li> + * <li>Only set provideable eIDAS attributes to IDPSSODescriptor</li> + * <li>SPSSODescriptor only requests 'persistent' subject nameIDs</li> + * </ul> + * + */ +public class NewMoaEidasMetadata { + private static final Logger LOGGER = LoggerFactory.getLogger(EidasMetadata.class.getName()); + private final String metadata; + private final String entityId; + private static final Set<String> DEFAULT_BINDING = new HashSet() { + }; + + private NewMoaEidasMetadata( Generator generator) throws EIDASSAMLEngineException { + this.entityId = generator.entityId; + this.metadata = generator.metadata; + } + + public String getMetadata() { + return this.metadata; + } + + + public static Generator generator() { + return new Generator(); + } + + + public static Generator generator( Generator copy) { + return new Generator(copy); + } + + public static final class Generator { + private XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); + private MetadataConfigParams params; + private SPSSODescriptor spSSODescriptor = null; + private IDPSSODescriptor idpSSODescriptor = null; + private String ssoLocation; + private String metadata; + private String entityId; + + public Generator() { + } + + public Generator( Generator copy) { + Preconditions.checkNotNull(copy, "copy"); + this.params = copy.params; + this.spSSODescriptor = copy.spSSODescriptor; + this.idpSSODescriptor = copy.idpSSODescriptor; + this.ssoLocation = copy.ssoLocation; + this.entityId = copy.entityId; + } + + + public NewMoaEidasMetadata build() throws EIDASSAMLEngineException { + initialize(); + this.entityId = this.params.getEntityID(); + this.metadata = generateMetadata(); + return new NewMoaEidasMetadata(this); + } + + public Generator configParams(MetadataConfigParams params) { + this.params = params; + return this; + } + + private void generateDigest(Extensions eidasExtensions) throws EIDASSAMLEngineException { + if (!(StringUtils.isEmpty(this.params.getSigningMethods()))) { + Set<String> signatureMethods = EIDASUtil.parseSemicolonSeparatedList(this.params.getSigningMethods()); + Set<String> digestMethods = new HashSet(); + for (String signatureMethod : signatureMethods) { + digestMethods.add(CertificateUtil.validateDigestAlgorithm(signatureMethod)); + } + for (String digestMethod : digestMethods) { + DigestMethod dm = (DigestMethod) BuilderFactoryUtil.buildXmlObject(DigestMethod.DEF_ELEMENT_NAME); + if (dm != null) { + dm.setAlgorithm(digestMethod); + eidasExtensions.getUnknownXMLObjects().add(dm); + } else { + NewMoaEidasMetadata.LOGGER.info("BUSINESS EXCEPTION error adding DigestMethod extension"); + } + } + } + } + + private Extensions generateExtensions() throws EIDASSAMLEngineException { + Extensions eidasExtensions = BuilderFactoryUtil.generateMetadataExtension(); + if (this.params.getAssuranceLevel() != null) { + generateLoA(eidasExtensions); + } + if (!(StringUtils.isEmpty(this.params.getSpType()))) { + SPType spTypeObj = (SPType) BuilderFactoryUtil.buildXmlObject(SPType.DEF_ELEMENT_NAME); + if (spTypeObj != null) { + spTypeObj.setSPType(this.params.getSpType()); + eidasExtensions.getUnknownXMLObjects().add(spTypeObj); + } else { + NewMoaEidasMetadata.LOGGER.info("BUSINESS EXCEPTION error adding SPType extension"); + } + } + generateDigest(eidasExtensions); + + if (!(StringUtils.isEmpty(this.params.getSigningMethods()))) { + Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(this.params.getSigningMethods()); + for (String signMethod : signMethods) { + SigningMethod sm = (SigningMethod) BuilderFactoryUtil + .buildXmlObject(SigningMethod.DEF_ELEMENT_NAME); + + if (sm != null) { + sm.setAlgorithm(signMethod); + eidasExtensions.getUnknownXMLObjects().add(sm); + } else { + NewMoaEidasMetadata.LOGGER.info("BUSINESS EXCEPTION error adding SigningMethod extension"); + } + } + } + return eidasExtensions; + } + + private void generateLoA(Extensions eidasExtensions) throws EIDASSAMLEngineException { + EntityAttributes loa = (EntityAttributes) BuilderFactoryUtil + .buildXmlObject(EntityAttributes.DEFAULT_ELEMENT_NAME); + + Attribute loaAttrib = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); + loaAttrib.setName("urn:oasis:names:tc:SAML:attribute:assurance-certification"); + loaAttrib.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"); + XSStringBuilder stringBuilder = (XSStringBuilder) Configuration.getBuilderFactory() + .getBuilder(XSString.TYPE_NAME); + + XSString stringValue = (XSString) stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, + XSString.TYPE_NAME); + stringValue.setValue(this.params.getAssuranceLevel()); + loaAttrib.getAttributeValues().add(stringValue); + loa.getAttributes().add(loaAttrib); + eidasExtensions.getUnknownXMLObjects().add(loa); + } + + private void addAssertionConsumerService() throws EIDASSAMLEngineException { + int index = 0; + Set<String> bindings = (this.params.getProtocolBinding().isEmpty()) ? NewMoaEidasMetadata.DEFAULT_BINDING + : this.params.getProtocolBinding(); + for (String binding : bindings) { + AssertionConsumerService asc = (AssertionConsumerService) BuilderFactoryUtil + .buildXmlObject(AssertionConsumerService.DEFAULT_ELEMENT_NAME); + + asc.setLocation(this.params.getAssertionConsumerUrl()); + asc.setBinding(checkBinding(binding)); + asc.setIndex(Integer.valueOf(index)); + if (index == 0) { + asc.setIsDefault(Boolean.valueOf(true)); + } + ++index; + this.spSSODescriptor.getAssertionConsumerServices().add(asc); + } + } + + private String checkBinding(String binding) { + if ((binding != null) && (((binding.equals("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")) + || (binding.equals("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"))))) { + return binding; + } + return "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"; + } + + private DateTime getExpireDate() { + DateTime expiryDate = DateTime.now(); + expiryDate = expiryDate.withFieldAdded(DurationFieldType.seconds(), + (int) this.params.getValidityDuration()); + + return expiryDate; + } + + private void generateSupportedAttributes(IDPSSODescriptor idpssoDescriptor, + ImmutableSortedSet<AttributeDefinition<?>> attributeDefinitions) throws EIDASSAMLEngineException { + List attributes = idpssoDescriptor.getAttributes(); + for (AttributeDefinition attributeDefinition : attributeDefinitions) { + Attribute a = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); + a.setName(attributeDefinition.getNameUri().toASCIIString()); + a.setFriendlyName(attributeDefinition.getFriendlyName()); + a.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"); + attributes.add(a); + } + } + + private void generateSPSSODescriptor(EntityDescriptor entityDescriptor, + X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) throws SecurityException, IllegalAccessException, + NoSuchFieldException, SAMLEngineException, EIDASSAMLEngineException { + this.spSSODescriptor.setWantAssertionsSigned(Boolean.valueOf(this.params.isWantAssertionsSigned())); + this.spSSODescriptor.setAuthnRequestsSigned(Boolean.valueOf(true)); + if (this.params.getSpSignature() != null) { + this.spSSODescriptor.setSignature(this.params.getSpSignature()); + } + if (this.params.getSpSigningCredential() != null) { + this.spSSODescriptor.getKeyDescriptors().add(getKeyDescriptor(keyInfoGeneratorFactory, + this.params.getSpSigningCredential(), UsageType.SIGNING)); + } + + if (this.params.getSpEncryptionCredential() != null) { + this.spSSODescriptor.getKeyDescriptors().add(getKeyDescriptor(keyInfoGeneratorFactory, + this.params.getSpEncryptionCredential(), UsageType.ENCRYPTION)); + } + + this.spSSODescriptor.addSupportedProtocol(this.params.getSpSamlProtocol()); + if (!(StringUtils.isEmpty(this.params.getAssertionConsumerUrl()))) { + addAssertionConsumerService(); + } + + + //fillNameIDFormat(this.spSSODescriptor); + //FIX: Austrian eIDAS node SP only needs persistent identifiers + NameIDFormat persistentFormat = + (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); + persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); + spSSODescriptor.getNameIDFormats().add(persistentFormat); + + entityDescriptor.getRoleDescriptors().add(this.spSSODescriptor); + } + + private void fillNameIDFormatIDP(SSODescriptor ssoDescriptor) throws EIDASSAMLEngineException { + NameIDFormat persistentFormat = (NameIDFormat) BuilderFactoryUtil + .buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); + + persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); + ssoDescriptor.getNameIDFormats().add(persistentFormat); + NameIDFormat transientFormat = (NameIDFormat) BuilderFactoryUtil + .buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); + + transientFormat.setFormat(SamlNameIdFormat.TRANSIENT.getNameIdFormat()); + ssoDescriptor.getNameIDFormats().add(transientFormat); + NameIDFormat unspecifiedFormat = (NameIDFormat) BuilderFactoryUtil + .buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); + + unspecifiedFormat.setFormat(SamlNameIdFormat.UNSPECIFIED.getNameIdFormat()); + ssoDescriptor.getNameIDFormats().add(unspecifiedFormat); + } + + private void generateIDPSSODescriptor(EntityDescriptor entityDescriptor, + X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) throws SecurityException, IllegalAccessException, + NoSuchFieldException, SAMLEngineException, EIDASSAMLEngineException { + this.idpSSODescriptor.setWantAuthnRequestsSigned(Boolean.valueOf(true)); + if (this.params.getIdpSignature() != null) { + this.idpSSODescriptor.setSignature(this.params.getIdpSignature()); + } + if (this.params.getIdpSigningCredential() != null) { + this.idpSSODescriptor.getKeyDescriptors().add(getKeyDescriptor(keyInfoGeneratorFactory, + this.params.getIdpSigningCredential(), UsageType.SIGNING)); + } + + //INFO: IDP requires no encryption certificate +// if (this.params.getIdpEncryptionCredential() != null) { +// this.idpSSODescriptor.getKeyDescriptors().add(getKeyDescriptor(keyInfoGeneratorFactory, +// this.params.getIdpEncryptionCredential(), UsageType.ENCRYPTION)); +// } + + this.idpSSODescriptor.addSupportedProtocol(this.params.getIdpSamlProtocol()); + fillNameIDFormatIDP(this.idpSSODescriptor); + this.idpSSODescriptor.getSingleSignOnServices().addAll(buildSingleSignOnServicesBindingLocations()); + if ((this.params.getIdpEngine() != null) && (this.params.getIdpEngine().getProtocolProcessor() != null) + && (this.params.getIdpEngine().getProtocolProcessor().getFormat() == SAMLExtensionFormat.EIDAS10)) { + + /*TODO: Only a work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata + * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. + * + * INFO: Maybe, this code can be removed in a future version of the eIDAS engine + */ + generateSupportedAttributes(this.idpSSODescriptor, getAllSupportedAttributes()); + } + entityDescriptor.getRoleDescriptors().add(this.idpSSODescriptor); + } + + /* FIX: Work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata + * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. + */ + public ImmutableSortedSet<AttributeDefinition<?>> getAllSupportedAttributes() { + ImmutableSortedSet.Builder<AttributeDefinition<?>> builder = + new ImmutableSortedSet.Builder<>(Ordering.<AttributeDefinition<?>>natural()); + + for (String attr : eIDASAttributeBuilder.getAllProvideableeIDASAttributes()) { + AttributeDefinition<?> supAttr = params.getIdpEngine().getProtocolProcessor().getAttributeDefinitionNullable(attr); + builder.add(supAttr); + } + + return builder.build(); + } + + private ArrayList<SingleSignOnService> buildSingleSignOnServicesBindingLocations() + throws NoSuchFieldException, IllegalAccessException { + ArrayList singleSignOnServices = new ArrayList(); + + HashMap<String, String> bindingLocations = this.params.getProtocolBindingLocation(); + Iterator bindLocs = bindingLocations.entrySet().iterator(); + while (bindLocs.hasNext()) { + Map.Entry bindingLoc = (Map.Entry) bindLocs.next(); + SingleSignOnService ssos = (SingleSignOnService) BuilderFactoryUtil + .buildXmlObject(SingleSignOnService.class); + ssos.setBinding((String) bindingLoc.getKey()); + ssos.setLocation((String) bindingLoc.getValue()); + singleSignOnServices.add(ssos); + } + return singleSignOnServices; + } + + private KeyDescriptor getKeyDescriptor(X509KeyInfoGeneratorFactory keyInfoGeneratorFactory, + Credential credential, UsageType usage) + throws NoSuchFieldException, IllegalAccessException, SecurityException, EIDASSAMLEngineException { + KeyDescriptor keyDescriptor = null; + if (credential != null) { + keyDescriptor = (KeyDescriptor) BuilderFactoryUtil.buildXmlObject(KeyDescriptor.class); + KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance(); + + KeyInfo keyInfo = keyInfoGenerator.generate(credential); + keyDescriptor.setUse(usage); + keyDescriptor.setKeyInfo(keyInfo); + if ((usage == UsageType.ENCRYPTION) && (this.params.getEncryptionAlgorithms() != null)) { + Set<String> encryptionAlgos = EIDASUtil.parseSemicolonSeparatedList(this.params.getEncryptionAlgorithms()); + for (String encryptionAlgo : encryptionAlgos) { + EncryptionMethod em = (EncryptionMethod) BuilderFactoryUtil + .buildXmlObject(EncryptionMethod.DEFAULT_ELEMENT_NAME); + + em.setAlgorithm(encryptionAlgo); + keyDescriptor.getEncryptionMethods().add(em); + } + } + } + + return keyDescriptor; + } + + private Organization buildOrganization() { + Organization organization = null; + if (this.params.getOrganization() != null) { + try { + organization = (Organization) BuilderFactoryUtil.buildXmlObject(Organization.class); + OrganizationDisplayName odn = (OrganizationDisplayName) BuilderFactoryUtil + .buildXmlObject(OrganizationDisplayName.class); + odn.setName(new LocalizedString(this.params.getOrganization().getDisplayName(), "en")); + organization.getDisplayNames().add(odn); + OrganizationName on = (OrganizationName) BuilderFactoryUtil.buildXmlObject(OrganizationName.class); + on.setName(new LocalizedString(this.params.getOrganization().getName(), "en")); + organization.getOrganizationNames().add(on); + OrganizationURL url = (OrganizationURL) BuilderFactoryUtil.buildXmlObject(OrganizationURL.class); + url.setURL(new LocalizedString(this.params.getOrganization().getUrl(), "en")); + organization.getURLs().add(url); + } catch (IllegalAccessException iae) { + NewMoaEidasMetadata.LOGGER.info("ERROR : error generating the OrganizationData: {}", iae.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : error generating the OrganizationData: {}", iae); + } catch (NoSuchFieldException nfe) { + NewMoaEidasMetadata.LOGGER.info("ERROR : error generating the OrganizationData: {}", nfe.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : error generating the OrganizationData: {}", nfe); + } + } + return organization; + } + + private ContactPerson buildContact(ContactPersonTypeEnumeration contactType) { + ContactPerson contact = null; + try { + ContactData currentContact = null; + if (contactType == ContactPersonTypeEnumeration.SUPPORT) + currentContact = this.params.getSupportContact(); + else if (contactType == ContactPersonTypeEnumeration.TECHNICAL) + currentContact = this.params.getTechnicalContact(); + else { + NewMoaEidasMetadata.LOGGER.error("ERROR: unsupported contact type"); + } + contact = (ContactPerson) BuilderFactoryUtil.buildXmlObject(ContactPerson.class); + if (currentContact == null) { + NewMoaEidasMetadata.LOGGER.error("ERROR: cannot retrieve contact from the configuration"); + return contact; + } + + EmailAddress emailAddressObj = (EmailAddress) BuilderFactoryUtil.buildXmlObject(EmailAddress.class); + Company company = (Company) BuilderFactoryUtil.buildXmlObject(Company.class); + GivenName givenName = (GivenName) BuilderFactoryUtil.buildXmlObject(GivenName.class); + SurName surName = (SurName) BuilderFactoryUtil.buildXmlObject(SurName.class); + TelephoneNumber phoneNumber = (TelephoneNumber) BuilderFactoryUtil + .buildXmlObject(TelephoneNumber.class); + contact.setType(contactType); + emailAddressObj.setAddress(currentContact.getEmail()); + company.setName(currentContact.getCompany()); + givenName.setName(currentContact.getGivenName()); + surName.setName(currentContact.getSurName()); + phoneNumber.setNumber(currentContact.getPhone()); + + populateContact(contact, currentContact, emailAddressObj, company, givenName, surName, phoneNumber); + } catch (IllegalAccessException iae) { + NewMoaEidasMetadata.LOGGER.info("ERROR : error generating the OrganizationData: {}", iae.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : error generating the OrganizationData: {}", iae); + } catch (NoSuchFieldException nfe) { + NewMoaEidasMetadata.LOGGER.info("ERROR : error generating the OrganizationData: {}", nfe.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : error generating the OrganizationData: {}", nfe); + } + return contact; + } + + private void populateContact(ContactPerson contact, ContactData currentContact, EmailAddress emailAddressObj, + Company company, GivenName givenName, SurName surName, TelephoneNumber phoneNumber) { + if (!(StringUtils.isEmpty(currentContact.getEmail()))) { + contact.getEmailAddresses().add(emailAddressObj); + } + if (!(StringUtils.isEmpty(currentContact.getCompany()))) { + contact.setCompany(company); + } + if (!(StringUtils.isEmpty(currentContact.getGivenName()))) { + contact.setGivenName(givenName); + } + if (!(StringUtils.isEmpty(currentContact.getSurName()))) { + contact.setSurName(surName); + } + if (!(StringUtils.isEmpty(currentContact.getPhone()))) + contact.getTelephoneNumbers().add(phoneNumber); + } + + private String generateMetadata() throws EIDASSAMLEngineException { + try { + EntityDescriptor entityDescriptor = (EntityDescriptor) this.builderFactory + .getBuilder(EntityDescriptor.DEFAULT_ELEMENT_NAME) + .buildObject(EntityDescriptor.DEFAULT_ELEMENT_NAME); + + entityDescriptor.setEntityID(this.params.getEntityID()); + entityDescriptor.setOrganization(buildOrganization()); + entityDescriptor.getContactPersons().add(buildContact(ContactPersonTypeEnumeration.SUPPORT)); + entityDescriptor.getContactPersons().add(buildContact(ContactPersonTypeEnumeration.TECHNICAL)); + entityDescriptor.setValidUntil(getExpireDate()); + + X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory(); + keyInfoGeneratorFactory.setEmitEntityCertificate(true); + Extensions e = generateExtensions(); + if (!(e.getUnknownXMLObjects().isEmpty())) { + entityDescriptor.setExtensions(e); + } + if (this.spSSODescriptor != null) { + generateSPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); + } + if (this.idpSSODescriptor != null) { + generateIDPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); + } + if (this.params.getSpEngine() != null) { + ProtocolEngineI spEngine = this.params.getSpEngine(); + ((MetadataSignerI) spEngine.getSigner()).signMetadata(entityDescriptor); + } else if (this.params.getIdpEngine() != null) { + ProtocolEngineI idpEngine = this.params.getIdpEngine(); + ((MetadataSignerI) idpEngine.getSigner()).signMetadata(entityDescriptor); + } + return EidasStringUtil.toString(OpenSamlHelper.marshall(entityDescriptor, false)); + } catch (Exception ex) { + NewMoaEidasMetadata.LOGGER.info("ERROR : SAMLException ", ex.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : SAMLException ", ex); + throw new IllegalStateException(ex); + } + } + + private void initialize() throws EIDASSAMLEngineException { + ProtocolEngineI idpEngine = this.params.getIdpEngine(); + ProtocolEngineI spEngine = this.params.getSpEngine(); + MetadataConfigParams.Builder initParamBuilder = MetadataConfigParams.builder(this.params); + if (idpEngine != null) { + idpEngine.getProtocolProcessor().configure(); + initParamBuilder.idpSigningCredential(CertificateUtil.toCredential(idpEngine.getSigningCertificate())); + + X509Certificate idpEngineDecryptionCertificate = idpEngine.getDecryptionCertificate(); + if (idpEngineDecryptionCertificate != null) { + initParamBuilder + .idpEncryptionCredential(CertificateUtil.toCredential(idpEngineDecryptionCertificate)); + } + if (this.idpSSODescriptor == null) { + try { + this.idpSSODescriptor = ((IDPSSODescriptor) BuilderFactoryUtil + .buildXmlObject(IDPSSODescriptor.class)); + } catch (NoSuchFieldException e) { + throw new EIDASSAMLEngineException(e); + } catch (IllegalAccessException e) { + throw new EIDASSAMLEngineException(e); + } + } + } + if (spEngine != null) { + spEngine.getProtocolProcessor().configure(); + initParamBuilder.spSigningCredential(CertificateUtil.toCredential(spEngine.getSigningCertificate())); + + X509Certificate spEngineDecryptionCertificate = spEngine.getDecryptionCertificate(); + if (spEngineDecryptionCertificate != null) { + initParamBuilder + .spEncryptionCredential(CertificateUtil.toCredential(spEngineDecryptionCertificate)); + } + if (this.spSSODescriptor == null) { + try { + this.spSSODescriptor = ((SPSSODescriptor) BuilderFactoryUtil + .buildXmlObject(SPSSODescriptor.class)); + } catch (NoSuchFieldException e) { + throw new EIDASSAMLEngineException(e); + } catch (IllegalAccessException e) { + throw new EIDASSAMLEngineException(e); + } + } + } + this.params = initParamBuilder.build(); + } + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java index 70135c06f..02a5df098 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java @@ -23,9 +23,12 @@ package at.gv.egovernment.moa.id.auth.modules.eidas.utils; import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashMap; import java.util.Map; +import org.opensaml.common.xml.SAMLSchemaBuilder; import org.opensaml.xml.ConfigurationException; import org.opensaml.xml.XMLConfigurator; @@ -36,8 +39,13 @@ import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAEidasProtocolProces import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASMetadataProviderDecorator; import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASEngineException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.FileUtils; +import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeRegistries; +import eu.eidas.auth.commons.attribute.AttributeRegistry; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.SamlEngineSystemClock; import eu.eidas.auth.engine.metadata.MetadataFetcherI; @@ -62,6 +70,7 @@ public class SAMLEngineUtils { if (eIDASEngine == null) { try { + //get eIDAS SAMLengine configuration from MOA-ID configuration CertificateConfigurationManager configManager = new MOAIDCertificateManagerConfigurationImpl(); @@ -70,12 +79,25 @@ public class SAMLEngineUtils { //set metadata signer metadataSigner = new MOAExtendedSWSigner(configManager); - + + //load additional eIDAS attribute definitions + String additionalAttributeConfigFile = + AuthConfigurationProviderFactory.getInstance().getBasicMOAIDConfiguration( + Constants.CONIG_PROPS_EIDAS_SAMLENGINE_ATTIONAL_ATTRIBUTE_DEFINITIONS); + AttributeRegistry addAttrDefinitions = AttributeRegistries.empty(); + if (MiscUtil.isNotEmpty(additionalAttributeConfigFile)) { + URL addAttrConfigUrl = new URL(FileUtils.makeAbsoluteURL( + additionalAttributeConfigFile, + AuthConfigurationProviderFactory.getInstance().getRootConfigFileDir())); + addAttrDefinitions = AttributeRegistries.fromFile(addAttrConfigUrl.getPath(), null); + + } + //build eIDAS SAML eninge - ProtocolEngineI engine = MOAProtocolEngineFactory.createProtocolEngine( + ProtocolEngineI engine = MOAProtocolEngineFactory.ownCreateProtocolEngine( Constants.eIDAS_SAML_ENGINE_NAME, configManager, - new MOAEidasProtocolProcesser(metadataFetcher, metadataSigner), + new MOAEidasProtocolProcesser(metadataFetcher, metadataSigner, addAttrDefinitions), new SamlEngineSystemClock()); //build a map with all actually supported attributes @@ -86,6 +108,9 @@ public class SAMLEngineUtils { //overwrite eIDAS response validator suite because Condition-Valitator has not time jitter initOpenSAMLConfig("own-saml-eidasnode-config.xml"); + //add eIDAS specific SAML2 extensions to eIDAS Schema validatior + SAMLSchemaBuilder.addExtensionSchema( + at.gv.egovernment.moa.util.Constants.SAML2_eIDAS_EXTENSIONS_SCHEMA_LOCATION); eIDASEngine = engine; @@ -93,6 +118,14 @@ public class SAMLEngineUtils { Logger.error("eIDAS SAMLengine initialization FAILED!", e); throw new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e); + } catch (at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException e) { + Logger.error("eIDAS SAMLengine initialization FAILED!", e); + throw new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e); + + } catch (MalformedURLException e) { + Logger.error("eIDAS SAMLengine initialization FAILED!", e); + throw new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e); + } } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeBuilder.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeBuilder.java new file mode 100644 index 000000000..22b94178e --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeBuilder.java @@ -0,0 +1,174 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.eidas.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceLoader; + +import com.google.common.collect.ImmutableSet; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.Pair; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.IeIDASAttribute; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAttributeBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeDefinition.Builder; +import eu.eidas.auth.commons.attribute.AttributeValue; +import eu.eidas.auth.commons.attribute.AttributeValueMarshaller; +import eu.eidas.auth.commons.attribute.AttributeValueMarshallingException; + +/** + * @author tlenz + * + */ +public class eIDASAttributeBuilder extends PVPAttributeBuilder { + private static IAttributeGenerator<String> generator = new SimpleEidasAttributeGenerator(); + + private static List<String> listOfSupportedeIDASAttributes; + private static ServiceLoader<IeIDASAttribute> eIDASAttributLoader = + ServiceLoader.load(IeIDASAttribute.class); + + static { + List<String> supportAttrList = new ArrayList<String>(); + + Logger.info("Select eIDAS attributes that are corrently providable:"); + if (eIDASAttributLoader != null ) { + Iterator<IeIDASAttribute> moduleLoaderInterator = eIDASAttributLoader.iterator(); + while (moduleLoaderInterator.hasNext()) { + try { + IeIDASAttribute modul = moduleLoaderInterator.next(); + Logger.info("Loading eIDAS attribut-builder Modul Information: " + modul.getName()); + supportAttrList.add(modul.getName()); + + } catch(Throwable e) { + Logger.error("Check configuration! " + "Some attribute-builder modul" + + " is not a valid IAttributeBuilder", e); + } + } + } + + listOfSupportedeIDASAttributes = Collections.unmodifiableList(supportAttrList); + Logger.info("Selection of providable eIDAS attributes done"); + + } + + /** + * Get all eIDAS attribute names that can be generated by the Austrian eIDAS node. + * This list is dynamically generated from loaded eIDAS attribute builders that are found in Java Classpath + * + * @return {@link List} of {@link String} of eIDAS attribute names + */ + public static List<String> getAllProvideableeIDASAttributes() { + return listOfSupportedeIDASAttributes; + } + + /** + * This method build an eIDAS response attribute, by using a loaded eIDAS attribute builder. + * + * @param attr eIDAS attribute that should be generated + * @param onlineApplicationConfiguration SP configuration + * @param authData Authentication data that contains user information for attribute generation + * @return eIDAS attribute response {@link Pair} or null if the attribute generation FAILES + */ + public static Pair<AttributeDefinition<?>,ImmutableSet<AttributeValue<?>>> buildAttribute(AttributeDefinition<?> attr, IOAAuthParameters onlineApplicationConfiguration, + IAuthData authData) { + + String attrName = attr.getNameUri().toString(); + Logger.trace("Build eIDAS attribute: "+ attrName); + + + IAttributeBuilder attrBuilder = getAttributeBuilder(attrName); + if (attrBuilder != null) { + try { + String attrValue = attrBuilder.build(onlineApplicationConfiguration, authData, generator); + if (MiscUtil.isNotEmpty(attrValue)) { + //set uniqueIdentifier attribute, because eIDAS SAMLEngine use this flag to select the + // Subject->NameID value from this attribute + Builder<?> eIDASAttrBuilder = AttributeDefinition.builder(attr); + eIDASAttrBuilder.uniqueIdentifier(evaluateUniqueID(attrName, authData.isUseMandate())); + AttributeDefinition<?> returnAttr = eIDASAttrBuilder.build(); + + //unmarshal attribute value into eIDAS attribute + AttributeValueMarshaller<?> attributeValueMarshaller = returnAttr.getAttributeValueMarshaller(); + ImmutableSet.Builder<AttributeValue<?>> builder = ImmutableSet.builder(); + + AttributeValue<?> attributeValue = null; + try { + attributeValue = attributeValueMarshaller.unmarshal(attrValue, false); + builder.add(attributeValue); + + } catch (AttributeValueMarshallingException e) { + throw new IllegalStateException(e); + + } + + return Pair.newInstance(returnAttr, builder.build()); + + } + + } catch (AttributeException e) { + Logger.debug("Attribute can not generate requested attribute:" + attr.getNameUri().toString() + " Reason:" + e.getMessage()); + + } + + } else + Logger.warn("NO attribute builder FOUND for eIDAS attr: " + attrName); + + return null; + } + + /** + * This method use the information from authenticated session and + * evaluate the uniqueID flag according to eIDAS specification + * + * @param attrName eIDAS attribute name that is evaluated + * @param useMandate flag that indicates if the current authenticated session includes a mandate + * @return true if eIDAS attribute holds the unique ID, otherwise false + */ + private static boolean evaluateUniqueID(String attrName, boolean useMandate) { + //if no mandate is used the natural person identifier is the unique ID + if (!useMandate && + attrName.equals(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER.getNameUri().toString())) + return true; + + //if mandates are used the the legal person identifier or the natural person identifier of the mandator is the unique ID + else if (useMandate && + attrName.equals(eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_PERSON_IDENTIFIER.getNameUri().toString())) + return true; + + //TODO: implement flag selector for mandates and natural persons + + + return false; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java index 7647b4cab..694efab80 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java @@ -15,6 +15,8 @@ import eu.eidas.auth.commons.protocol.IAuthenticationRequest; @Scope(value = BeanDefinition.SCOPE_PROTOTYPE) public class EIDASData extends RequestImpl { + public static final String REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID = "transiendIDRequested"; + /** The Constant serialVersionUID. */ private static final long serialVersionUID = 8765755670214923910L; @@ -28,7 +30,7 @@ public class EIDASData extends RequestImpl { private String remoteIPAddress; private String remoteRelayState; - + @Override public Collection<String> getRequestedAttributes(MetadataProvider metadataProvider) { // TODO Auto-generated method stub diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java index 388d65963..940b91b44 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java @@ -67,6 +67,7 @@ import eu.eidas.auth.commons.protocol.eidas.IEidasAuthenticationRequest; import eu.eidas.auth.commons.protocol.eidas.impl.EidasAuthenticationRequest; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse.Builder; +import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.metadata.MetadataUtil; import eu.eidas.engine.exceptions.EIDASSAMLEngineException; @@ -307,6 +308,13 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { pendingReq.setGenericDataToSession(RequestImpl.eIDAS_GENERIC_REQ_DATA_LEVELOFASSURENCE, eIDASSamlReq.getEidasLevelOfAssurance().stringValue()); + //set flag if transiend identifier is requested + if (MiscUtil.isNotEmpty(eIDASSamlReq.getNameIdFormat()) + && eIDASSamlReq.getNameIdFormat().equals(SamlNameIdFormat.TRANSIENT.getNameIdFormat())) + pendingReq.setGenericDataToSession(EIDASData.REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID, true); + else + pendingReq.setGenericDataToSession(EIDASData.REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID, false); + // - memorize requested attributes pendingReq.setEidasRequestedAttributes(eIDASSamlReq.getRequestedAttributes()); @@ -322,7 +330,7 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { // - memorize service-provider type from eIDAS request String spType = null; if (eIDASSamlReq.getSpType() != null) - spType = eIDASSamlReq.getSpType().getValue(); + spType = eIDASSamlReq.getSpType(); if (MiscUtil.isEmpty(spType)) spType = MetadataUtil.getSPTypeFromMetadata(eIDASNodeEntityDesc); diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java index df96bef12..cc9b09107 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java @@ -31,7 +31,7 @@ import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASEngineException; -import at.gv.egovernment.moa.id.auth.modules.eidas.utils.MOAeIDASMetadataGenerator; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.NewMoaEidasMetadata; import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils; import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; @@ -44,8 +44,10 @@ import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.logging.Logger; import eu.eidas.auth.engine.ProtocolEngineI; -import eu.eidas.auth.engine.metadata.Contact; +import eu.eidas.auth.engine.metadata.ContactData; import eu.eidas.auth.engine.metadata.MetadataConfigParams; +import eu.eidas.auth.engine.metadata.MetadataConfigParams.Builder; +import eu.eidas.auth.engine.metadata.OrganizationData; import eu.eidas.engine.exceptions.EIDASSAMLEngineException; @@ -119,22 +121,21 @@ public class EidasMetaDataRequest implements IAction { ProtocolEngineI engine = SAMLEngineUtils.createSAMLEngine(eIDASMetadataProvider); - MOAeIDASMetadataGenerator generator = new MOAeIDASMetadataGenerator(); - MetadataConfigParams mcp=new MetadataConfigParams(); - generator.setConfigParams(mcp); - generator.initialize(engine); - - mcp.setEntityID(metadata_url); - mcp.setAssertionConsumerUrl(sp_return_url); - mcp.getProtocolBindingLocation().put( + //configura metadata builder + Builder metadataConfigBuilder = MetadataConfigParams.builder(); + metadataConfigBuilder.entityID(metadata_url); + metadataConfigBuilder.assertionConsumerUrl(sp_return_url); + + metadataConfigBuilder.addProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI); + metadataConfigBuilder.addProtocolBindingLocation( SAMLConstants.SAML2_POST_BINDING_URI, pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_IDP_COLLEAGUEREQUEST); //TODO: make it configurable - mcp.setAuthnRequestsSigned(true); - mcp.setWantAssertionsSigned(true); - mcp.setAssuranceLevel( + metadataConfigBuilder.authnRequestsSigned(true); + metadataConfigBuilder.wantAssertionsSigned(true); + metadataConfigBuilder.assuranceLevel( authConfig.getBasicMOAIDConfiguration( Constants.CONIG_PROPS_EIDAS_NODE_LoA, MOAIDAuthConstants.eIDAS_LOA_HIGH)); @@ -142,47 +143,71 @@ public class EidasMetaDataRequest implements IAction { //must be set in request, because it could be different for every online-application //mcp.setSpType(SPType.DEFAULT_VALUE); - mcp.setDigestMethods(Constants.METADATA_ALLOWED_ALG_DIGIST); - mcp.setSigningMethods(Constants.METADATA_ALLOWED_ALG_SIGN); - mcp.setEncryptionAlgorithms(Constants.METADATA_ALLOWED_ALG_ENCRYPT); + metadataConfigBuilder.digestMethods(Constants.METADATA_ALLOWED_ALG_DIGIST); + metadataConfigBuilder.signingMethods(Constants.METADATA_ALLOWED_ALG_SIGN); + metadataConfigBuilder.encryptionAlgorithms(Constants.METADATA_ALLOWED_ALG_ENCRYPT); //add organisation information from PVP metadata information Organization pvpOrganisation = null; try { pvpOrganisation = PVPConfiguration.getInstance().getIDPOrganisation(); - Contact technicalContact = new Contact(); + eu.eidas.auth.engine.metadata.ContactData.Builder technicalContact = ContactData.builder(); List<ContactPerson> contacts = PVPConfiguration.getInstance().getIDPContacts(); if (contacts != null && contacts.size() >= 1) { ContactPerson contact = contacts.get(0); - technicalContact.setGivenName(contact.getGivenName().getName()); - technicalContact.setSurName(contact.getSurName().getName()); + technicalContact.givenName(contact.getGivenName().getName()); + technicalContact.surName(contact.getSurName().getName()); if (!contact.getEmailAddresses().isEmpty()) - technicalContact.setEmail(contact.getEmailAddresses().get(0).getAddress()); + technicalContact.email(contact.getEmailAddresses().get(0).getAddress()); if (!contact.getTelephoneNumbers().isEmpty()) - technicalContact.setPhone(contact.getTelephoneNumbers().get(0).getNumber()); + technicalContact.phone(contact.getTelephoneNumbers().get(0).getNumber()); - mcp.setTechnicalContact(technicalContact ); + } if (pvpOrganisation != null) { - mcp.setNodeUrl(pvpOrganisation.getURLs().get(0).getURL().getLocalString()); - mcp.setCountryName(authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRY, "Austria")); - technicalContact.setCompany(pvpOrganisation.getDisplayNames().get(0).getName().getLocalString()); + eu.eidas.auth.engine.metadata.OrganizationData.Builder organizationConfig = OrganizationData.builder(); + organizationConfig.url(pvpOrganisation.getURLs().get(0).getURL().getLocalString()); + organizationConfig.name(authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRY, "Austria")); + //TODO: add display name and maybe update name + + + metadataConfigBuilder.organization(organizationConfig.build()); + + technicalContact.company(pvpOrganisation.getDisplayNames().get(0).getName().getLocalString()); } + + metadataConfigBuilder.technicalContact(technicalContact.build()); + + //TODO: add correct support contact + metadataConfigBuilder.supportContact(ContactData.builder(technicalContact.build()).build()); + } catch (ConfigurationException | NullPointerException e) { Logger.warn("Can not load Organisation or Contact from Configuration", e); } - - generator.addSPRole(); - generator.addIDPRole(); + + metadataConfigBuilder.idpEngine(engine); + metadataConfigBuilder.spEngine(engine); + + //TODO: +// MOAeIDASMetadataGenerator generator = new MOAeIDASMetadataGenerator(); +// generator.initialize(engine); +// generator.addSPRole(); +// generator.addIDPRole(); +// metadata = generator.generateMetadata(); + + //use own implementation that solves some problems in original implementation + NewMoaEidasMetadata.Generator generator = NewMoaEidasMetadata.generator(); + generator.configParams(metadataConfigBuilder.build()); + NewMoaEidasMetadata eidasMetadata = generator.build(); + metadata = eidasMetadata.getMetadata(); - metadata = generator.generateMetadata(); return metadata; } } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/IeIDASAttribute.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/IeIDASAttribute.java new file mode 100644 index 000000000..15060fb52 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/IeIDASAttribute.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder; + +/** + * @author tlenz + * + */ +public interface IeIDASAttribute extends IAttributeBuilder{ + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrDateOfBirth.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrDateOfBirth.java new file mode 100644 index 000000000..64e5ae770 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrDateOfBirth.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.BirthdateAttributeBuilder; + +/** + * @author tlenz + * + */ +public class eIDASAttrDateOfBirth extends BirthdateAttributeBuilder implements IeIDASAttribute { + + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.DATE_OF_BIRTH.getNameUri().toString(); + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrFamilyName.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrFamilyName.java new file mode 100644 index 000000000..4195eeeef --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrFamilyName.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; + +/** + * @author tlenz + * + */ +public class eIDASAttrFamilyName implements IeIDASAttribute{ + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#getName() + */ + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_FAMILY_NAME.getNameUri().toString(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#build(at.gv.egovernment.moa.id.commons.api.IOAAuthParameters, at.gv.egovernment.moa.id.data.IAuthData, at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT build(IOAAuthParameters oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeException { + return g.buildStringAttribute(null, getName(), authData.getFamilyName()); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#buildEmpty(at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return null; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrGivenName.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrGivenName.java new file mode 100644 index 000000000..2a654ac44 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrGivenName.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; + +/** + * @author tlenz + * + */ +public class eIDASAttrGivenName implements IeIDASAttribute{ + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#getName() + */ + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_GIVEN_NAME.getNameUri().toString(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#build(at.gv.egovernment.moa.id.commons.api.IOAAuthParameters, at.gv.egovernment.moa.id.data.IAuthData, at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT build(IOAAuthParameters oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeException { + return g.buildStringAttribute(null, getName(), authData.getGivenName()); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#buildEmpty(at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return null; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalName.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalName.java new file mode 100644 index 000000000..51a2bd69b --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalName.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonFullNameAttributeBuilder; + +/** + * @author tlenz + * + */ +public class eIDASAttrLegalName extends MandateLegalPersonFullNameAttributeBuilder implements IeIDASAttribute { + + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_NAME.getNameUri().toString(); + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalPersonIdentifier.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalPersonIdentifier.java new file mode 100644 index 000000000..c008048cb --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalPersonIdentifier.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonSourcePinAttributeBuilder; + +/** + * @author tlenz + * + */ +public class eIDASAttrLegalPersonIdentifier extends MandateLegalPersonSourcePinAttributeBuilder implements IeIDASAttribute { + + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_PERSON_IDENTIFIER.getNameUri().toString(); + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrNaturalPersonalIdentifier.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrNaturalPersonalIdentifier.java new file mode 100644 index 000000000..cb659c2b1 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrNaturalPersonalIdentifier.java @@ -0,0 +1,116 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import java.security.MessageDigest; + +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils; +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.Trible; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.eidas.EIDASData; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; +import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +public class eIDASAttrNaturalPersonalIdentifier implements IeIDASAttribute{ + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#getName() + */ + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER.getNameUri().toString(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#build(at.gv.egovernment.moa.id.commons.api.IOAAuthParameters, at.gv.egovernment.moa.id.data.IAuthData, at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT build(IOAAuthParameters oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeException { + String personalID = authData.getBPK(); + + //generate eIDAS conform 'PersonalIdentifier' attribute + if (!eIDASAttributeProcessingUtils.validateEidasPersonalIdentifier(personalID)) { + Logger.debug("preCalculated PersonalIdentifier does not include eIDAS conform prefixes ... add prefix now"); + if (MiscUtil.isEmpty(authData.getBPKType()) + || !authData.getBPKType().startsWith(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS)) { + Logger.error("BPKType is empty or does not start with eIDAS bPKType prefix! bPKType:" + authData.getBPKType()); + throw new AttributeException("Suspect bPKType for eIDAS identifier generation"); + + } + + String prefix = authData.getBPKType().substring(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS.length() + 1); + personalID = prefix.replaceAll("\\+", "/") + "/" + personalID; + + } + + //generate a transient unique identifier if it is requested + Boolean isTransiendIDRequested = + authData.getGenericData(EIDASData.REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID, Boolean.class); + if (isTransiendIDRequested != null && isTransiendIDRequested) + personalID = generateTransientNameID(personalID); + + return g.buildStringAttribute(null, getName(), personalID); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#buildEmpty(at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return null; + } + + private String generateTransientNameID(String nameID) { + //extract source-country and destination country from persistent identifier + Trible<String, String, String> split = eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier(nameID); + if (split == null) { + Logger.error("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); + throw new IllegalStateException("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); + + } + + //build correct formated transient identifier + String random = Random.nextLongRandom(); + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] hash = md.digest((split.getThird() + random).getBytes("ISO-8859-1")); + return split.getFirst() + "/" + split.getSecond() + "/" + Base64Utils.encode(hash); + + } catch (Exception e) { + Logger.error("Can not generate transient personal identifier!", e); + return null; + + } + + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java index 2fe52bb4f..d0cda38c7 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java @@ -23,8 +23,6 @@ package at.gv.egovernment.moa.id.protocols.eidas; import java.io.StringWriter; -import java.security.MessageDigest; -import java.text.SimpleDateFormat; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -43,33 +41,23 @@ import at.gv.egovernment.moa.id.auth.frontend.velocity.VelocityProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SimpleEidasAttributeGenerator; -import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeBuilder; import at.gv.egovernment.moa.id.commons.MOAIDConstants; import at.gv.egovernment.moa.id.commons.api.IRequest; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.Pair; import at.gv.egovernment.moa.id.data.SLOInformationImpl; import at.gv.egovernment.moa.id.data.SLOInformationInterface; -import at.gv.egovernment.moa.id.data.Trible; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; -import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonFullNameAttributeBuilder; -import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonSourcePinAttributeBuilder; -import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; -import at.gv.egovernment.moa.id.util.Random; import at.gv.egovernment.moa.logging.Logger; -import at.gv.egovernment.moa.util.Base64Utils; -import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.commons.EidasStringUtil; import eu.eidas.auth.commons.attribute.AttributeDefinition; -import eu.eidas.auth.commons.attribute.AttributeDefinition.Builder; import eu.eidas.auth.commons.attribute.AttributeValue; -import eu.eidas.auth.commons.attribute.AttributeValueMarshaller; -import eu.eidas.auth.commons.attribute.AttributeValueMarshallingException; import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; import eu.eidas.auth.commons.protocol.IResponseMessage; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; -import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.xml.opensaml.SAMLEngineUtils; @@ -97,104 +85,31 @@ public class eIDASAuthenticationRequest implements IAction { else throw new MOAIDException("got wrong IRequest type. is: {}, should be: {}", new String[] {req.getClass().toString(), EIDASData.class.toString()}); - + String subjectNameID = null; - + //gather attributes ImmutableAttributeMap reqAttributeList = (ImmutableAttributeMap) eidasRequest.getEidasRequestedAttributes(); ImmutableAttributeMap.Builder attrMapBuilder = ImmutableAttributeMap.builder(); - - //TODO: if we support more then this minimum required attributes -> redesign to a smoother attribute builder selector + + //generate eIDAS attributes for(AttributeDefinition<?> attr : reqAttributeList.getDefinitions()) { - String newValue = ""; - boolean isUniqueID = false; - try { - switch(attr.getFriendlyName()) { - case Constants.eIDAS_ATTR_DATEOFBIRTH: - newValue = new SimpleDateFormat("YYYY-MM-dd").format(authData.getDateOfBirth()); - break; - case Constants.eIDAS_ATTR_CURRENTFAMILYNAME: - newValue = authData.getFamilyName(); - break; - case Constants.eIDAS_ATTR_CURRENTGIVENNAME: - newValue = authData.getGivenName(); - break; - case Constants.eIDAS_ATTR_PERSONALIDENTIFIER: - newValue = authData.getBPK(); - isUniqueID = true; + Pair<AttributeDefinition<?>, ImmutableSet<AttributeValue<?>>> eIDASAttr = eIDASAttributeBuilder.buildAttribute( + attr, req.getOnlineApplicationConfiguration(), authData); - //generate eIDAS conform 'PersonalIdentifier' attribute - if (!eIDASAttributeProcessingUtils.validateEidasPersonalIdentifier(newValue)) { - Logger.debug("preCalculated PersonalIdentifier does not include eIDAS conform prefixes ... add prefix now"); - if (MiscUtil.isEmpty(authData.getBPKType()) - || !authData.getBPKType().startsWith(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS)) { - Logger.error("BPKType is empty or does not start with eIDAS bPKType prefix! bPKType:" + authData.getBPKType()); - throw new MOAIDException("builder.08", new Object[]{"Suspect bPKType for eIDAS identifier generation"}); - - } - - String prefix = authData.getBPKType().substring(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS.length() + 1); - newValue = prefix.replaceAll("\\+", "/") + "/" + newValue; - - } - - //generate a transient unique identifier if it is requested - String reqNameIDFormat = eidasRequest.getEidasRequest().getNameIdFormat(); - if (MiscUtil.isNotEmpty(reqNameIDFormat) - && reqNameIDFormat.equals(SamlNameIdFormat.TRANSIENT.getNameIdFormat())) - newValue = generateTransientNameID(newValue); - - - subjectNameID = newValue; - break; - case Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER: - newValue = new MandateLegalPersonSourcePinAttributeBuilder().build( - req.getOnlineApplicationConfiguration(), authData, generator); - break; - case Constants.eIDAS_ATTR_LEGALNAME: - newValue = new MandateLegalPersonFullNameAttributeBuilder().build( - req.getOnlineApplicationConfiguration(), authData, generator); - break; - - } - - } catch (AttributeException e) { - Logger.debug("Attribute can not generate requested attribute:" + attr.getFriendlyName() + " Reason:" + e.getMessage()); - - } - - if(MiscUtil.isEmpty(newValue)) { + if(eIDASAttr == null) { if (attr.isRequired()) { Logger.info("eIDAS Attr:" + attr.getNameUri() + " is marked as 'Required' but not available."); throw new MOAIDException("eIDAS.15", new Object[]{attr.getFriendlyName()}); } else Logger.info("eIDAS Attr:" + attr.getNameUri() + " is not available."); - } else { - //set uniqueIdentifier attribute, because eIDAS SAMLEngine use this flag to select the - // Subject->NameID value from this attribute - Builder<?> attrBuilder = AttributeDefinition.builder(attr); - attrBuilder.uniqueIdentifier(isUniqueID); - AttributeDefinition<?> returnAttr = attrBuilder.build(); - - //unmarshal attribute value into eIDAS attribute - AttributeValueMarshaller<?> attributeValueMarshaller = returnAttr.getAttributeValueMarshaller(); - ImmutableSet.Builder<AttributeValue<?>> builder = ImmutableSet.builder(); - - AttributeValue<?> attributeValue = null; - try { - attributeValue = attributeValueMarshaller.unmarshal(newValue, false); - builder.add(attributeValue); - - } catch (AttributeValueMarshallingException e) { - throw new IllegalStateException(e); - - } - - //add attribute to Map - attrMapBuilder.put((AttributeDefinition)returnAttr, (ImmutableSet) builder.build()); + //add attribute to Map + attrMapBuilder.put( + (AttributeDefinition)eIDASAttr.getFirst(), + (ImmutableSet)eIDASAttr.getSecond()); } } @@ -231,19 +146,7 @@ public class eIDASAuthenticationRequest implements IAction { eIDASRespMsg = engine.generateResponseMessage(eidasRequest.getEidasRequest(), response, true, eidasRequest.getRemoteAddress()); - -// if(null == eidasRequest.getEidasRequest().getAssertionConsumerServiceURL()) { -// String assertionConsumerUrl = MetadataUtil.getAssertionUrlFromMetadata( -// new MOAeIDASMetadataProviderDecorator(eIDASMetadataProvider), -// engine, -// eidasRequest.getEidasRequest()); -// eidasRequest.getEidasRequest().setAssertionConsumerServiceURL(assertionConsumerUrl); -// -// } - -// response = engine.generateEIDASAuthnResponse(eidasRequest.getEidasRequest(), response, eidasRequest.getRemoteAddress(), true); - - + token = EidasStringUtil.encodeToBase64(eIDASRespMsg.getMessageBytes()); } catch(Exception e) { @@ -319,28 +222,6 @@ public class eIDASAuthenticationRequest implements IAction { } - private String generateTransientNameID(String nameID) { - //extract source-country and destination country from persistent identifier - Trible<String, String, String> split = eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier(nameID); - if (split == null) { - Logger.error("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); - throw new IllegalStateException("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); - - } - - //build correct formated transient identifier - String random = Random.nextLongRandom(); - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] hash = md.digest((split.getThird() + random).getBytes("ISO-8859-1")); - return split.getFirst() + "/" + split.getSecond() + "/" + Base64Utils.encode(hash); - - } catch (Exception e) { - Logger.error("Can not generate transient personal identifier!", e); - return null; - - } - - } + } |