diff options
53 files changed, 1185 insertions, 723 deletions
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/validation/moaconfig/StorkConfigValidator.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/validation/moaconfig/StorkConfigValidator.java index ed2c2f903..8e8020d75 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/validation/moaconfig/StorkConfigValidator.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/validation/moaconfig/StorkConfigValidator.java @@ -43,7 +43,7 @@ public class StorkConfigValidator { errors.add(LanguageHelper.getErrorString("validation.stork.cpeps.cc", new Object[] {ValidationHelper.getPotentialCSSCharacter(false)}, request )); } - if(!check.toLowerCase().matches("^[a-z][a-z]$")) { + if(!check.toLowerCase().matches("(^[a-z][a-z]$)|(^[a-z][a-z]-[a-z]*)")) { log.warn("CPEPS config countrycode does not comply to ISO 3166-2 : " + check); errors.add(LanguageHelper.getErrorString("validation.stork.cpeps.cc", new Object[] {check}, request )); diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/validation/oa/OATargetConfigValidation.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/validation/oa/OATargetConfigValidation.java index 650553ab3..0062beb96 100644 --- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/validation/oa/OATargetConfigValidation.java +++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/validation/oa/OATargetConfigValidation.java @@ -24,6 +24,8 @@ package at.gv.egovernment.moa.id.configuration.validation.oa; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; @@ -74,6 +76,16 @@ public class OATargetConfigValidation { log.info("Not valid CompanyNumber"); errors.add(LanguageHelper.getErrorString("validation.general.identificationnumber.fn.valid", request)); } + + } else if (form.getIdentificationType().equals(Constants.IDENIFICATIONTYPE_EIDAS)) { + Pattern pattern = Pattern.compile("[A-Z,a-z]{2}\\+[A-Z,a-z]{2}"); + Matcher matcher = pattern.matcher(check); + if (!matcher.matches()) { + log.info("Not valid eIDAS Target"); + errors.add(LanguageHelper.getErrorString("validation.general.identificationnumber.eidas.valid", request)); + + } + } } diff --git a/id/ConfigWebTool/src/main/resources/applicationResources_de.properties b/id/ConfigWebTool/src/main/resources/applicationResources_de.properties index fe1dac063..d75403575 100644 --- a/id/ConfigWebTool/src/main/resources/applicationResources_de.properties +++ b/id/ConfigWebTool/src/main/resources/applicationResources_de.properties @@ -480,6 +480,7 @@ validation.general.identificationtype.valid=Der Identifikationstype wird nicht u validation.general.identificationnumber.empty=Im privatwirtschaftlichen Bereich ist eine Identifikationsnummer erforderlich. validation.general.identificationnumber.valid=Die Identifikationsnummer f\u00FCr den privatwirtschaftlichen Bereich enth\u00E4lt nicht erlaubte Zeichen. Folgende Zeichen sind nicht erlaubt\: {0} validation.general.identificationnumber.fn.valid=Die Firmenbuchnummer hat kein g\u00FCltiges Format. +validation.general.identificationnumber.eidas.valid=Der eIDAS-Node Target hat kein g\u00FCltiges Format. (z.B. AT+NL) validation.general.oaidentifier.empty=Es wurde kein eindeutiger Identifier f\u00FCr die Online-Applikation angegeben. validation.general.oaidentifier.valid=Der eindeutige Identifier f\u00FCr die Online-Applikation ist keine g\u00FCltige URL. validation.general.oaidentifier.notunique=Der gew\u00E4hlte eindeutige Identifier ist bereits vorhanden (kollision mit {0}). Eine Eintragung der Online-Applikation ist nicht m\u00F6glich. diff --git a/id/ConfigWebTool/src/main/resources/applicationResources_en.properties b/id/ConfigWebTool/src/main/resources/applicationResources_en.properties index 126bba7c9..708cc605e 100644 --- a/id/ConfigWebTool/src/main/resources/applicationResources_en.properties +++ b/id/ConfigWebTool/src/main/resources/applicationResources_en.properties @@ -478,6 +478,7 @@ validation.general.identificationtype.valid=The identification type is not suppo validation.general.identificationnumber.empty=The identification number is necessary for private sector. validation.general.identificationnumber.valid=The identification number for the private sector contains forbidden characters. The following characters are not allowed\: {0} validation.general.identificationnumber.fn.valid=The identification number has invalid format. +validation.general.identificationnumber.eidas.valid=The eIDAS-node identification number has invalid format. (e.g. AT+NL) validation.general.oaidentifier.empty=There is no unique identifier for the Online-Application provided. validation.general.oaidentifier.valid=The unique identifier for the Online-Application is not valid URL. validation.general.oaidentifier.notunique=The selected unique identifier is already available (collision with {0}). Registration of the Online-Application was not possible. diff --git a/id/ConfigWebTool/src/main/webapp/css/index.css b/id/ConfigWebTool/src/main/webapp/css/index.css index 80ccf93be..aa83e0c2b 100644 --- a/id/ConfigWebTool/src/main/webapp/css/index.css +++ b/id/ConfigWebTool/src/main/webapp/css/index.css @@ -375,6 +375,11 @@ div .wwgrp br { } +.textfield_PEPS_CC { + width: 70px; + +} + .textfield_middle { width: 100px; diff --git a/id/ConfigWebTool/src/main/webapp/jsp/editMOAConfig.jsp b/id/ConfigWebTool/src/main/webapp/jsp/editMOAConfig.jsp index 6694a4273..6892535a1 100644 --- a/id/ConfigWebTool/src/main/webapp/jsp/editMOAConfig.jsp +++ b/id/ConfigWebTool/src/main/webapp/jsp/editMOAConfig.jsp @@ -296,7 +296,7 @@ <tr> <td style="display:none;"><s:textfield name="storkconfig.cpepslist[%{#stat.index}].hjid" value="%{hjid}" cssStyle="display:none;"/></td> <s:if test="%{countryCode == 'CC'}"> - <td><s:textfield name="storkconfig.cpepslist[%{#stat.index}].countryCode" value="%{countryCode}" cssClass="textfield_short"/></td> + <td><s:textfield name="storkconfig.cpepslist[%{#stat.index}].countryCode" value="%{countryCode}" cssClass="textfield_PEPS_CC"/></td> </s:if> <s:else> <td><s:property value="%{countryCode}" /></td> @@ -307,7 +307,7 @@ </tr> </s:iterator> <s:if test="%{storkconfig.cpepslist == null || storkconfig.cpepslist.isEmpty}"> - <tr><td><s:textfield name="storkconfig.cpepslist[0].countryCode" value="CC" cssClass="textfield_short"/></td> + <tr><td><s:textfield name="storkconfig.cpepslist[0].countryCode" value="CC" cssClass="textfield_PEPS_CC"/></td> <td><s:textfield name="storkconfig.cpepslist[0].URL" value="http://" cssClass="textfield_long"/></td> <td><s:checkbox name="storkconfig.cpepslist[0].supportsXMLSignature" value="true" /></td> <td><input class="button_narrow" type="button" value="<%=LanguageHelper.getGUIString("webpages.moaconfig.stork.removepeps", request) %>" onclick='this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);'/></td></tr> diff --git a/id/moa-id-webgui/src/main/java/at/gv/egovernment/moa/id/config/webgui/validation/task/impl/GeneralSTORKConfigurationTask.java b/id/moa-id-webgui/src/main/java/at/gv/egovernment/moa/id/config/webgui/validation/task/impl/GeneralSTORKConfigurationTask.java index 6d1dafd6c..fb675ad43 100644 --- a/id/moa-id-webgui/src/main/java/at/gv/egovernment/moa/id/config/webgui/validation/task/impl/GeneralSTORKConfigurationTask.java +++ b/id/moa-id-webgui/src/main/java/at/gv/egovernment/moa/id/config/webgui/validation/task/impl/GeneralSTORKConfigurationTask.java @@ -125,7 +125,7 @@ public static final List<String> KEYWHITELIST; LanguageHelper.getErrorString("validation.stork.cpeps.cc", new Object[] {ValidationHelper.getPotentialCSSCharacter(false)}))); } - if(!cc.toLowerCase().matches("^[a-z][a-z]$")) { + if(!cc.toLowerCase().matches("(^[a-z][a-z]$)|(^[a-z][a-z]-[a-z]*)")) { log.warn("CPEPS config countrycode does not comply to ISO 3166-2 : " + cc); errors.add(new ValidationObjectIdentifier( MOAIDConfigurationConstants.GENERAL_AUTH_STORK_CPEPS_LIST diff --git a/id/server/data/deploy/conf/moa-id/eIDAS/EncryptModule.xml b/id/server/data/deploy/conf/moa-id/eIDAS/EncryptModule.xml index 9fef4fa2e..46052053a 100644 --- a/id/server/data/deploy/conf/moa-id/eIDAS/EncryptModule.xml +++ b/id/server/data/deploy/conf/moa-id/eIDAS/EncryptModule.xml @@ -3,14 +3,32 @@ <properties> <comment>SWModule encrypt with JKS.</comment> - <entry key="keystorePath">keys/eidasKeyStore.jks</entry> + + <entry key="check_certificate_validity_period">false</entry> + <entry key="disallow_self_signed_certificate">false</entry> + <entry key="response.encryption.mandatory">false</entry> + + <!-- Data Encryption algorithm --> + <entry key="data.encryption.algorithm">http://www.w3.org/2009/xmlenc11#aes256-gcm</entry> + + <!-- Decryption algorithm Whitelist--> + <entry key="encryption.algorithm.whitelist"> + http://www.w3.org/2009/xmlenc11#aes128-gcm; + http://www.w3.org/2009/xmlenc11#aes256-gcm; + http://www.w3.org/2009/xmlenc11#aes192-gcm + </entry> + + <!-- Key Encryption algorithm --> + <entry key="key.encryption.algorithm">http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p</entry> + + <entry key="keyStorePath">keys/eidasKeyStore.jks</entry> + <entry key="keyStoreType">JKS</entry> <entry key="keyStorePassword">local-demo</entry> <entry key="keyPassword">local-demo</entry> <!-- Management of the encryption activation --> <entry key="encryptionActivation">eIDAS/encryptionConf.xml</entry> - <entry key="responseToPointIssuer.BE">CN=local-demo-cert, OU=DIGIT, O=European Comission, L=Brussels, ST=Belgium,C=BE</entry> <entry key="responseToPointSerialNumber.BE">54C8F779</entry> @@ -18,5 +36,5 @@ <entry key="responseDecryptionIssuer">CN=local-demo-cert, OU=DIGIT, O=European Comission, L=Brussels, ST=Belgium, C=BE</entry> <entry key="serialNumber">54C8F779</entry> - <entry key="keystoreType">JKS</entry> + </properties>
\ No newline at end of file diff --git a/id/server/data/deploy/conf/moa-id/eIDAS/SignModule.xml b/id/server/data/deploy/conf/moa-id/eIDAS/SignModule.xml index 745580428..bf7215cb5 100644 --- a/id/server/data/deploy/conf/moa-id/eIDAS/SignModule.xml +++ b/id/server/data/deploy/conf/moa-id/eIDAS/SignModule.xml @@ -3,17 +3,46 @@ <properties> <comment>SWModule sign with JKS.</comment> - <entry key="keystorePath">keys/eidasKeyStore_Service_CB.jks</entry> + <entry key="check_certificate_validity_period">false</entry> + <entry key="disallow_self_signed_certificate">false</entry> + + <!-- signing Algorithm SHA_512(default),SHA_384,SHA_256 --> + <!-- http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 --> + <!-- http://www.w3.org/2001/04/xmldsig-more#rsa-sha384 --> + <!-- http://www.w3.org/2001/04/xmldsig-more#rsa-sha512 --> + <entry key="signature.algorithm">http://www.w3.org/2001/04/xmldsig-more#rsa-sha512</entry> + + <!-- List of incoming Signature algorithms white list separated by ; (default all) --> + <entry key="signature.algorithm.whitelist"> + http://www.w3.org/2001/04/xmldsig-more#rsa-sha256; + http://www.w3.org/2001/04/xmldsig-more#rsa-sha384; + http://www.w3.org/2001/04/xmldsig-more#rsa-sha512; + http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160; + http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256; + http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384; + http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512; + http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1; + http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-mgf1 + </entry> + + <!-- signing response assertion true/false (default false) --> + <entry key="response.sign.assertions">true</entry> + + <!--AuthnRequest / Assertion signing keyStore--> + <entry key="keyStorePath">keys/eidasKeyStore_Service_CB.jks</entry> + <entry key="keyStoreType">JKS</entry> <entry key="keyStorePassword">local-demo</entry> <entry key="keyPassword">local-demo</entry> <entry key="issuer">CN=cpeps-cb-demo-certificate, OU=STORK, O=CPEPS, L=EU, ST=EU, C=CB</entry> <entry key="serialNumber">54C8F839</entry> - <entry key="keystoreType">JKS</entry> - <entry key="metadata.keystorePath">keys/eidasKeyStore_METADATA.jks</entry> + + <!--Metadata signing keystore--> + <entry key="metadata.keyStorePath">keys/eidasKeyStore_METADATA.jks</entry> + <entry key="metadata.keyStoreType">JKS</entry> <entry key="metadata.keyStorePassword">local-demo</entry> <entry key="metadata.keyPassword">local-demo</entry> <entry key="metadata.issuer">CN=metadata, OU=DIGIT, O=EC, L=Brussels, ST=EU, C=BE</entry> <entry key="metadata.serialNumber">561BC0C8</entry> - <entry key="metadata.keystoreType">JKS</entry> + </properties> diff --git a/id/server/doc/handbook/additional/additional.html b/id/server/doc/handbook/additional/additional.html index ec57a74c6..9e3cdf11e 100644 --- a/id/server/doc/handbook/additional/additional.html +++ b/id/server/doc/handbook/additional/additional.html @@ -361,6 +361,21 @@ <td width="1127" valign="top"><p>SAML1 StartAuthentication Request</p></td> </tr> <tr> + <td valign="top">3400</td> + <td valign="top"> </td> + <td valign="top">eIDAS Metadata Request</td> + </tr> + <tr> + <td valign="top">3401</td> + <td valign="top">Request ID</td> + <td valign="top">Eingehender eIDAS Authentication Request</td> + </tr> + <tr> + <td valign="top">3402</td> + <td valign="top">Response ID</td> + <td valign="top">eIDAS Authentication Response erstellt</td> + </tr> + <tr> <td width="165" valign="top"><p align="center">4000</p></td> <td width="312" valign="top"><p align="left"> </p></td> <td width="1127" valign="top"><p>Identifizierungs- und Authentifizierungsprozess wurde gestartet</p></td> diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java index 3264fc3bd..cad3354f5 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java @@ -71,7 +71,6 @@ import at.gv.egovernment.moa.id.data.AuthenticationRoleFactory; import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.data.MISMandate; import at.gv.egovernment.moa.id.data.Pair; -import at.gv.egovernment.moa.id.moduls.RequestImpl; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.builder.AttributQueryBuilder; @@ -1105,16 +1104,20 @@ public class AuthenticationDataBuilder extends MOAIDAuthConstants { String baseID = authData.getIdentificationValue(); String baseIDType = authData.getIdentificationType(); - - String eIDASOutboundCountry = pendingReq.getGenericData(RequestImpl.eIDAS_GENERIC_REQ_DATA_COUNTRY, String.class); - - //TODO: maybe find a better solution - String cititzenCountryCode = - authConfig.getBasicMOAIDConfiguration("moa.id.protocols.eIDAS.node.countrycode", - MOAIDAuthConstants.COUNTRYCODE_AUSTRIA); - - if (Constants.URN_PREFIX_BASEID.equals(baseIDType)) { - if (MiscUtil.isNotEmpty(eIDASOutboundCountry) && !cititzenCountryCode.equals(eIDASOutboundCountry)) { + + if (Constants.URN_PREFIX_BASEID.equals(baseIDType)) { + //Calculate eIDAS identifier + if (oaParam.getBusinessService() && + oaParam.getIdentityLinkDomainIdentifier().startsWith(Constants.URN_PREFIX_EIDAS)) { + String[] splittedTarget = oaParam.getIdentityLinkDomainIdentifier().split("\\+"); + String cititzenCountryCode = splittedTarget[1]; + String eIDASOutboundCountry = splittedTarget[2]; + + if (cititzenCountryCode.equalsIgnoreCase(eIDASOutboundCountry)) { + Logger.warn("Suspect configuration FOUND!!! CitizenCountry equals DestinationCountry"); + + } + Pair<String, String> eIDASID = new BPKBuilder().buildeIDASIdentifer(baseIDType, baseID, cititzenCountryCode, eIDASOutboundCountry); Logger.debug("Authenticate user with bPK:" + eIDASID.getFirst() + " Type:" + eIDASID.getSecond()); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java index 9e4e36fec..32ac8ad68 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java @@ -238,7 +238,7 @@ public class BPKBuilder { Logger.debug("Building eIDAS identification from: " + sourceCountry+"/"+destinationCountry+"/" + "[identValue]"); String eIdentifier = sourceCountry + "/" + destinationCountry + "/" + bPK; - return Pair.newInstance(eIdentifier, baseIDType); + return Pair.newInstance(eIdentifier, bPKType); } private String calculatebPKwbPK(String basisbegriff) throws BuildException { diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/stork/STORKConfig.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/stork/STORKConfig.java index 8f6dff849..b85938bb7 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/stork/STORKConfig.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/stork/STORKConfig.java @@ -83,11 +83,20 @@ public class STORKConfig implements IStorkConfig { if (MiscUtil.isNotEmpty(storkCPEPSProps.get(listCounter + "." + MOAIDConfigurationConstants.GENERAL_AUTH_STORK_CPEPS_LIST_COUNTRY))) {
try {
+
+ //Assertion encryption is enabled by default
+ boolean enableAssertionEncryption = true;
+ String enableAssertionEncryptionString = storkCPEPSProps.get(listCounter + "." + MOAIDConfigurationConstants.GENERAL_AUTH_STORK_CPEPS_LIST_SUPPORT_XMLDSIG);
+ if (MiscUtil.isNotEmpty(enableAssertionEncryptionString)) {
+ enableAssertionEncryption = Boolean.parseBoolean(enableAssertionEncryptionString);
+
+ }
+
CPEPS moacpep =
new CPEPS(storkCPEPSProps.get(listCounter + "." + MOAIDConfigurationConstants.GENERAL_AUTH_STORK_CPEPS_LIST_COUNTRY),
new URL(storkCPEPSProps.get(listCounter + "." + MOAIDConfigurationConstants.GENERAL_AUTH_STORK_CPEPS_LIST_URL)),
- Boolean.valueOf(storkCPEPSProps.get(listCounter + "." + MOAIDConfigurationConstants.GENERAL_AUTH_STORK_CPEPS_LIST_SUPPORT_XMLDSIG)));
- cpepsMap.put(moacpep.getCountryCode(), moacpep);
+ enableAssertionEncryption);
+ cpepsMap.put(moacpep.getFullCountryCode(), moacpep);
} catch (MalformedURLException e) {
Logger.warn("CPEPS URL " +
@@ -158,7 +167,7 @@ public class STORKConfig implements IStorkConfig { if (StringUtils.isEmpty(ccc) || this.cpepsMap.isEmpty())
return false;
- if (this.cpepsMap.containsKey(ccc.toUpperCase()))
+ if (this.cpepsMap.containsKey(ccc))
return true;
else
return false;
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/RequestImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/RequestImpl.java index b612352c6..b87574d52 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/RequestImpl.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/RequestImpl.java @@ -61,7 +61,7 @@ public abstract class RequestImpl implements IRequest, Serializable{ public static final String DATAID_REQUESTER_IP_ADDRESS = "requesterIP"; - public static final String eIDAS_GENERIC_REQ_DATA_COUNTRY = "country"; +// public static final String eIDAS_GENERIC_REQ_DATA_COUNTRY = "country"; public static final String eIDAS_GENERIC_REQ_DATA_LEVELOFASSURENCE = "eIDAS_LoA"; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/metadata/MOASPMetadataSignatureFilter.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/metadata/MOASPMetadataSignatureFilter.java index b6fed5934..16b179d89 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/metadata/MOASPMetadataSignatureFilter.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/metadata/MOASPMetadataSignatureFilter.java @@ -27,6 +27,7 @@ import java.io.IOException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactoryConfigurationError; +import org.opensaml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.provider.FilterException; import org.opensaml.saml2.metadata.provider.MetadataFilter; @@ -37,6 +38,7 @@ import at.gv.egovernment.moa.id.commons.api.data.IVerifiyXMLSignatureResponse; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.MiscUtil; /** * @author tlenz @@ -61,67 +63,75 @@ public class MOASPMetadataSignatureFilter implements MetadataFilter { @Override public void doFilter(XMLObject metadata) throws FilterException { if (metadata instanceof EntityDescriptor) { - if (((EntityDescriptor) metadata).isSigned()) { - EntityDescriptor entityDes = (EntityDescriptor) metadata; - //check signature; - try { - byte[] serialized = DOMUtils.serializeNode(metadata.getDOM(), "UTF-8"); - -// Transformer transformer = TransformerFactory.newInstance() -// .newTransformer(); -// StringWriter sw = new StringWriter(); -// StreamResult sr = new StreamResult(sw); -// DOMSource source = new DOMSource(metadata.getDOM()); -// transformer.transform(source, sr); -// sw.close(); -// String metadataXML = sw.toString(); - - SignatureVerificationUtils sigVerify = - new SignatureVerificationUtils(); - IVerifiyXMLSignatureResponse result = sigVerify.verify( - serialized, trustProfileID); - - //check signature-verification result - if (result.getSignatureCheckCode() != 0) { - Logger.warn("Metadata signature-verification FAILED!" - + " Metadata: " + entityDes.getEntityID() - + " StatusCode:" + result.getSignatureCheckCode()); - throw new FilterException("Metadata signature-verification FAILED!" - + " Metadata: " + entityDes.getEntityID() - + " StatusCode:" + result.getSignatureCheckCode()); + checkSignature(metadata, ((EntityDescriptor)metadata).getEntityID()); - } - - if (result.getCertificateCheckCode() != 0) { - Logger.warn("Metadata certificate-verification FAILED!" - + " Metadata: " + entityDes.getEntityID() - + " StatusCode:" + result.getCertificateCheckCode()); - throw new FilterException("Metadata certificate-verification FAILED!" - + " Metadata: " + entityDes.getEntityID() - + " StatusCode:" + result.getCertificateCheckCode()); - - } - - Logger.debug("SAML metadata for entityID:" + entityDes.getEntityID() + " is valid"); + } else if (metadata instanceof EntitiesDescriptor) { + EntitiesDescriptor entitiesDesc = (EntitiesDescriptor) metadata; + if (entitiesDesc.getEntityDescriptors() != null && + entitiesDesc.getEntityDescriptors().size() > 1) { + String nameForLogging = entitiesDesc.getName(); + if (MiscUtil.isEmpty(nameForLogging)) + nameForLogging = entitiesDesc.getID(); + + checkSignature(metadata, nameForLogging); + + } else { + Logger.warn("Metadata root-element is of type 'EntitiesDescriptor' but only include one 'EntityDescriptor'"); + throw new FilterException("Metadata root-element is not of type 'EntitiesDescriptor' but only include one 'EntityDescriptor"); + + } + + } else { + Logger.warn("Metadata root-element is not of type 'EntityDescriptor' or 'EntitiesDescriptor'"); + throw new FilterException("Metadata root-element is not of type 'EntityDescriptor' or 'EntitiesDescriptor'"); + + } + + } + + private void checkSignature(XMLObject metadata, String nameForLogging) throws FilterException { + if (((EntityDescriptor) metadata).isSigned()) { + //check signature; + try { + byte[] serialized = DOMUtils.serializeNode(metadata.getDOM(), "UTF-8"); + + SignatureVerificationUtils sigVerify = + new SignatureVerificationUtils(); + IVerifiyXMLSignatureResponse result = sigVerify.verify( + serialized, trustProfileID); - } catch (MOAIDException | TransformerFactoryConfigurationError | TransformerException | IOException e) { - Logger.error("Metadata verification for Entity:" + entityDes.getEntityID() - + " has an interal error.", e); - throw new FilterException("Metadata verification has an interal error." - + " Message:" + e.getMessage()); + //check signature-verification result + if (result.getSignatureCheckCode() != 0) { + Logger.warn("Metadata signature-verification FAILED!" + + " Metadata: " + nameForLogging + + " StatusCode:" + result.getSignatureCheckCode()); } + if (result.getCertificateCheckCode() != 0) { + Logger.warn("Metadata certificate-verification FAILED!" + + " Metadata: " + nameForLogging + + " StatusCode:" + result.getCertificateCheckCode()); + throw new FilterException("Metadata certificate-verification FAILED!" + + " Metadata: " + nameForLogging + + " StatusCode:" + result.getCertificateCheckCode()); + + } - } else { - Logger.warn("Metadata root-element MUST be signed."); - throw new FilterException("Metadata root-element MUST be signed.'"); + Logger.debug("SAML metadata for entityID:" + nameForLogging + " is valid"); + + } catch (MOAIDException | TransformerFactoryConfigurationError | TransformerException | IOException e) { + Logger.error("Metadata verification for Entity:" + nameForLogging + + " has an interal error.", e); + throw new FilterException("Metadata verification has an interal error." + + " Message:" + e.getMessage()); } - + + } else { - Logger.warn("Metadata root-element is not of type 'EntityDescriptor'"); - throw new FilterException("Metadata root-element is not of type 'EntityDescriptor'"); + Logger.warn("Metadata root-element MUST be signed."); + throw new FilterException("Metadata root-element MUST be signed.'"); } diff --git a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties index b88df0b9d..1a2f0d1d3 100644 --- a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties +++ b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties @@ -271,6 +271,8 @@ eIDAS.11=Received eIDAS Error-Response. Reason:{0} eIDAS.12=Received eIDAS AuthnRequest is not valid. Reason:{0}
eIDAS.13=Generation of eIDAS Response FAILED. Reason:{0}
eIDAS.14=eIDAS Response validation FAILED: LevelOfAssurance {0} is to low.
+eIDAS.15=Generation of eIDAS Response FAILED. Required attribute: {0} is NOT available.
+eIDAS.16=eIDAS Response attribute-validation FAILED. Attribute:{0} Reason: {1}.
pvp2.01=Fehler beim kodieren der PVP2 Antwort
pvp2.02=Ungueltiges Datumsformat
diff --git a/id/server/idserverlib/src/main/resources/resources/properties/protocol_response_statuscodes_de.properties b/id/server/idserverlib/src/main/resources/resources/properties/protocol_response_statuscodes_de.properties index e72a28046..c6d0844ce 100644 --- a/id/server/idserverlib/src/main/resources/resources/properties/protocol_response_statuscodes_de.properties +++ b/id/server/idserverlib/src/main/resources/resources/properties/protocol_response_statuscodes_de.properties @@ -228,6 +228,8 @@ eIDAS.11=1302 eIDAS.12=1305 eIDAS.13=1307 eIDAS.14=1301 +eIDAS.15=1307 +eIDAS.16=1301 pvp2.01=6100 pvp2.06=6100 diff --git a/id/server/idserverlib/src/main/resources/resources/templates/pvp_postbinding_template.html b/id/server/idserverlib/src/main/resources/resources/templates/pvp_postbinding_template.html index 2f93428b5..64e88a688 100644 --- a/id/server/idserverlib/src/main/resources/resources/templates/pvp_postbinding_template.html +++ b/id/server/idserverlib/src/main/resources/resources/templates/pvp_postbinding_template.html @@ -1,9 +1,9 @@ ## ## Velocity Template for SAML 2 HTTP-POST binding ## ## Velocity -context may contain the following properties ## action - String - the -action URL for the form ## RelayState - String - the relay state for the -message ## SAMLRequest - String - the Base64 encoded SAML Request ## -SAMLResponse - String - the Base64 encoded SAML Response - +##context may contain the following properties ## action - String - the +##action URL for the form ## RelayState - String - the relay state for the +##message ## SAMLRequest - String - the Base64 encoded SAML Request ## +##SAMLResponse - String - the Base64 encoded SAML Response +<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <body onload="document.forms[0].submit()"> diff --git a/id/server/idserverlib/src/main/resources/resources/templates/saml2-post-binding-moa.vm b/id/server/idserverlib/src/main/resources/resources/templates/saml2-post-binding-moa.vm deleted file mode 100644 index 8beb601c6..000000000 --- a/id/server/idserverlib/src/main/resources/resources/templates/saml2-post-binding-moa.vm +++ /dev/null @@ -1,38 +0,0 @@ -## -## Velocity Template for SAML 2 HTTP-POST binding -## -## Velocity context may contain the following properties -## action - String - the action URL for the form -## RelayState - String - the relay state for the message -## SAMLRequest - String - the Base64 encoded SAML Request -## SAMLResponse - String - the Base64 encoded SAML Response -## Contains target attribute to delegate PEPS authentication out of iFrame - -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> - - <body onload="document.forms[0].submit()"> - <noscript> - <p> - <strong>Note:</strong> Since your browser does not support JavaScript, - you must press the Continue button once to proceed. - </p> - </noscript> - - <form action="${action}" method="post" target="_top"> - <div> - #if($RelayState)<input type="hidden" name="RelayState" value="${RelayState}"/>#end - - #if($SAMLRequest)<input type="hidden" name="SAMLRequest" value="${SAMLRequest}"/>#end - - #if($SAMLResponse)<input type="hidden" name="SAMLResponse" value="${SAMLResponse}"/>#end - - </div> - <noscript> - <div> - <input type="submit" value="Continue"/> - </div> - </noscript> - </form> - - </body> -</html>
\ No newline at end of file diff --git a/id/server/idserverlib/src/main/resources/resources/templates/stork2_consent.html b/id/server/idserverlib/src/main/resources/resources/templates/stork2_consent.html deleted file mode 100644 index 0ab41f146..000000000 --- a/id/server/idserverlib/src/main/resources/resources/templates/stork2_consent.html +++ /dev/null @@ -1,438 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<meta content="text/html; charset=utf-8" http-equiv="Content-Type"> - - <!-- MOA-ID 2.x BKUSelection Layout CSS --> - <style type="text/css"> - @media screen and (min-width: 650px) { - - body { - margin:0; - padding:0; - color : #000; - background-color : #fff; - text-align: center; - background-color: #6B7B8B; - } - - #bku_header h2 { - font-size: 0.8em; - } - - - #page { - display: block; - border: 2px solid rgb(0,0,0); - width: 650px; - height: 460px; - margin: 0 auto; - margin-top: 5%; - position: relative; - border-radius: 25px; - background: rgb(255,255,255); - } - - #page1 { - text-align: center; - } - - #main { - /* clear:both; */ - position:relative; - margin: 0 auto; - width: 250px; - text-align: center; - } - - .OA_header { - /* background-color: white;*/ - font-size: 20pt; - margin-bottom: 25px; - margin-top: 25px; - } - - #leftcontent { - /*float:left; */ - width:250px; - margin-bottom: 25px; - text-align: left; - border: 1px solid rgb(0,0,0); - } - - #selectArea { - font-size: 15px; - padding-bottom: 65px; - } - - #leftcontent { - width: 300px; - margin-top: 30px; - } - - #bku_header { - height: 5%; - padding-bottom: 3px; - padding-top: 3px; - } - - #bkulogin { - overflow:auto; - min-width: 190px; - height: 260px; - padding: 20px; - } - - h2#tabheader{ - font-size: 1.1em; - padding-left: 2%; - padding-right: 2%; - position: relative; - } - - .setAssertionButton_full { - background: #efefef; - cursor: pointer; - margin-top: 15px; - width: 100px; - height: 30px - } - - #leftbutton { - width: 30%; - float:left; - margin-left: 40px; - } - - #rightbutton { - width: 30%; - float:right; - margin-right: 45px; - text-align: right; - } - - button { - height: 25px; - width: 75px; - margin-bottom: 10px; - } - - #validation { - position: absolute; - bottom: 0px; - margin-left: 270px; - padding-bottom: 10px; - } - - } - - @media screen and (max-width: 205px) { - #bku_header h2 { - font-size: 0.8em; - margin-top: -0.4em; - padding-top: 0.4em; - } - - #bkulogin { - min-height: 150px; - padding: 20px; - } - } - - @media screen and (max-width: 249px) and (min-width: 206px) { - #bku_header h2 { - font-size: 0.9em; - margin-top: -0.45em; - padding-top: 0.45em; - } - - #bkulogin { - height: 180px; - padding: 20px; - } - } - - @media screen and (max-width: 299px) and (min-width: 250px) { - #bku_header h2 { - font-size: 1.1em; - margin-top: -0.55em; - padding-top: 0.55em; - } - } - - @media screen and (max-width: 649px) and (min-width: 400px) { - #bku_header h2 { - font-size: 1.3em; - margin-top: -0.65em; - padding-top: 0.65em; - } - } - - - - @media screen and (max-width: 649px) { - - body { - margin:0; - padding:0; - color : #000; - text-align: center; - font-size: 100%; - background-color: ${MAIN_BACKGOUNDCOLOR}; - } - - #page { - visibility: hidden; - margin-top: 0%; - } - - #page1 { - visibility: hidden; - } - - #main { - visibility: hidden; - } - - #validation { - visibility: hidden; - display: none; - } - - .OA_header { - margin-bottom: 0px; - margin-top: 0px; - font-size: 0pt; - visibility: hidden; - } - - #leftcontent { - visibility: visible; - margin-bottom: 0px; - text-align: left; - border:none; - vertical-align: middle; - min-height: 173px; - min-width: 204px; - - } - - #bku_header { - height: 10%; - min-height: 1.2em; - margin-top: 1%; - } - - h2#tabheader{ - padding-left: 2%; - padding-right: 2%; - position: relative; - top: 50%; - } - - #bkulogin { - min-width: 190px; - height: 155px; - padding: 20px; - } - - .setAssertionButton_full { - background: #efefef; - cursor: pointer; - margin-top: 15px; - width: 70px; - height: 25px; - } - - input[type=button] { -/* height: 11%; */ - width: 70%; - } - } - - * { - margin: 0; - padding: 0; - font-family: ${FONTTYPE}; - } - - #selectArea { - padding-top: 10px; - padding-bottom: 55px; - padding-left: 10px; - } - - .setAssertionButton { - background: #efefef; - cursor: pointer; - margin-top: 15px; - width: 70px; - height: 25px; - } - - #leftbutton { - width: 35%; - float:left; - margin-left: 15px; - } - - #rightbutton { - width: 35%; - float:right; - margin-right: 25px; - text-align: right; - } - - .verticalcenter { - vertical-align: middle; - } - - input { - /*border:1px solid #000;*/ - cursor: pointer; - } - - - #installJava, #BrowserNOK { - clear:both; - font-size:0.8em; - padding:4px; - } - - .selectText{ - - } - - .selectTextHeader{ - - } - - .sendButton { - width: 30%; - margin-bottom: 1%; - } - - #leftcontent a { - text-decoration:none; - color: #000; - /* display:block;*/ - padding:4px; - } - - #leftcontent a:hover, #leftcontent a:focus, #leftcontent a:active { - text-decoration:underline; - color: #000; - } - - .infobutton { - background-color: #005a00; - color: white; - font-family: serif; - text-decoration: none; - padding-top: 2px; - padding-right: 4px; - padding-bottom: 2px; - padding-left: 4px; - font-weight: bold; - } - - .hell { - background-color : ${MAIN_BACKGOUNDCOLOR}; - color: ${MAIN_COLOR}; - } - - .dunkel { - background-color: ${HEADER_BACKGROUNDCOLOR}; - color: ${HEADER_COLOR}; - } - - .main_header { - color: black; - font-size: 32pt; - position: absolute; - right: 10%; - top: 40px; - - } - - #controls { - text-align: right; - } - - </style> -<!-- MOA-ID 2.x BKUSelection JavaScript fucnctions--> -<script type="text/javascript"> - function isIE() { - return (/MSIE (\d+\.\d+);/.test(navigator.userAgent)); - } - function isFullscreen() { - try { - return ((top.innerWidth == screen.width) && (top.innerHeight == screen.height)); - } catch (e) { - return false; - } - } - function isActivexEnabled() { - var supported = null; - try { - supported = !!new ActiveXObject("htmlfile"); - } catch (e) { - supported = false; - } - return supported; - } - function generateIFrame(iFrameURL) { - var el = document.getElementById("bkulogin"); - var width = el.clientWidth; - var heigth = el.clientHeight - 20; - var parent = el.parentNode; - - iFrameURL += "&heigth=" + heigth; - iFrameURL += "&width=" + width; - - var iframe = document.createElement("iframe"); - iframe.setAttribute("src", iFrameURL); - iframe.setAttribute("width", el.clientWidth - 1); - iframe.setAttribute("height", el.clientHeight - 1); - iframe.setAttribute("frameborder", "0"); - iframe.setAttribute("scrolling", "no"); - iframe.setAttribute("title", "Login"); - parent.replaceChild(iframe, el); - } - function onChangeChecks() { - if (top.innerWidth < 650) { - document.getElementById("moaidform").setAttribute("target","_parent"); - } else { - document.getElementById("moaidform").removeAttribute("target"); - } - - } - </script> -<title>Informationsfreigabe</title> -</head> -<body onload="onChangeChecks();" onresize="onChangeChecks();"> - <div id="page"> - <div id="page1" class="case selected-case" role="main"> - <h2 class="OA_header" role="heading">STORK Informationsfreigabe</h2> - <div id="main"> - <div id="leftcontent" class="hell" role="application"> - <form method="POST" action="${action}"> - <div id="bku_header" class="dunkel"> - <h2 id="tabheader" class="dunkel" role="heading">STORK Informationsfreigabe</h2> - </div> - <div id="bkulogin" class="hell" role="form"> - Wählen Sie jene Daten, die, wenn verfügbar, an ein Drittland weitergegeben werden sollen:</br> - <table> - ${tablecontent} - </table> - </div> - <div id="controls" class="hell"> - <input type="submit" value="weiter" /> - </div> - </form> - </div> - </div> - </div> - </div> -</body> -</html>
\ No newline at end of file diff --git a/id/server/idserverlib/src/main/resources/resources/templates/stork2_postbinding_template.html b/id/server/idserverlib/src/main/resources/resources/templates/stork2_postbinding_template.html deleted file mode 100644 index f901351a2..000000000 --- a/id/server/idserverlib/src/main/resources/resources/templates/stork2_postbinding_template.html +++ /dev/null @@ -1,42 +0,0 @@ -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> - -<body onload="document.forms[0].submit()"> - <noscript> - <p> - <strong>Note:</strong> Since your browser does not support - JavaScript, you must press the Continue button once to proceed. - </p> - </noscript> - - - <div id="alert">Your login is being processed. Thank you for - waiting.</div> - - <style type="text/css"> -<!-- -#alert { - margin: 100px 250px; - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 14px; - font-weight: normal; -} ---> -</style> - - <form action="${action}" method="post" target="_self"> - <div> - #if($RelayState)<input type="hidden" name="RelayState" - value="${RelayState}" />#end #if($SAMLRequest)<input type="hidden" - name="SAMLRequest" value="${SAMLRequest}" />#end #if($SAMLResponse)<input - type="hidden" name="SAMLResponse" value="${SAMLResponse}" />#end - - </div> - <noscript> - <div> - <input type="submit" value="Continue" /> - </div> - </noscript> - </form> - -</body> -</html> diff --git a/id/server/moa-id-commons/pom.xml b/id/server/moa-id-commons/pom.xml index 51cb6d5af..c4007fc80 100644 --- a/id/server/moa-id-commons/pom.xml +++ b/id/server/moa-id-commons/pom.xml @@ -323,9 +323,10 @@ <target>1.7</target> </configuration> </plugin> - <plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> + <version>3.0.2</version> <configuration> <archive> <addMavenDescriptor>false</addMavenDescriptor> @@ -375,7 +376,7 @@ </executions> </plugin> - <plugin> +<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> @@ -390,7 +391,7 @@ </goals> </execution> </executions> - </plugin> + </plugin> --> <plugin> <artifactId>maven-enforcer-plugin</artifactId> <version>1.1.1</version> diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/MOAIDConstants.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/MOAIDConstants.java index 6d573efe8..e9f9a7e80 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/MOAIDConstants.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/MOAIDConstants.java @@ -36,6 +36,8 @@ public class MOAIDConstants { //general configuration constants + public static final String DEFAULT_CONTENT_TYPE_HTML_UTF8 = "text/html; charset=UTF-8"; + public static final String FILE_URI_PREFIX = "file:/"; public static final String PREFIX_WPBK = "urn:publicid:gv.at:wbpk+"; diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/data/CPEPS.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/data/CPEPS.java index a88aa2171..525a660b4 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/data/CPEPS.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/data/CPEPS.java @@ -62,11 +62,23 @@ public class CPEPS { this.isXMLSignatureSupported = isXMLSignatureSupported;
}
+
+ public String getFullCountryCode() {
+ return countryCode;
+ }
+
/**
* Gets the country code of this C-PEPS
* @return ISO country code
*/
public String getCountryCode() {
+ if (countryCode != null &&
+ countryCode.contains("-")) {
+ //remove trailing information to country code
+ return countryCode.substring(0, countryCode.indexOf("-"));
+
+ }
+
return countryCode;
}
diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/config/ConfigurationMigrationUtils.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/config/ConfigurationMigrationUtils.java index 61b08f3a6..b8284c8f9 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/config/ConfigurationMigrationUtils.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/config/ConfigurationMigrationUtils.java @@ -981,13 +981,17 @@ public class ConfigurationMigrationUtils { } // transfer the incoming data to the database model stork.setStorkLogonEnabled(Boolean.parseBoolean(oa.get(MOAIDConfigurationConstants.SERVICE_AUTH_STORK_ENABLED))); - if (MiscUtil.isNotEmpty(oa.get(MOAIDConfigurationConstants.SERVICE_AUTH_STORK_MINQAALEVEL))) + if (MiscUtil.isNotEmpty(oa.get(MOAIDConfigurationConstants.SERVICE_AUTH_STORK_MINQAALEVEL))) { try { + stork.seteIDAS_LOA(oa.get(MOAIDConfigurationConstants.SERVICE_AUTH_STORK_MINQAALEVEL)); stork.setQaa(Integer.valueOf(oa.get(MOAIDConfigurationConstants.SERVICE_AUTH_STORK_MINQAALEVEL))); + } catch (NumberFormatException e) { Logger.info("Downgraded OA config found -> change eIDAS LoA to STORK QAA"); stork.setQaa(4); + } + } if (MiscUtil.isNotEmpty(oa.get(MOAIDConfigurationConstants.PREFIX_MOAID_SERVICES)) && oa.get(MOAIDConfigurationConstants.PREFIX_MOAID_SERVICES).equals(MOAIDConfigurationConstants.PREFIX_VIDP)) diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java index 260b2ecb1..129478270 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java @@ -449,7 +449,7 @@ public interface Constants { //TODO: update to eIDAS prefix /** URN prefix for context dependent id (eIDAS). */ - public static final String URN_PREFIX_EIDAS = URN_PREFIX + ":storkid"; + public static final String URN_PREFIX_EIDAS = URN_PREFIX + ":eidasid"; /** URN prefix for context dependent id. */ public static final String URN_PREFIX_BASEID = URN_PREFIX + ":baseid"; diff --git a/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/builder/GUIFormBuilderImpl.java b/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/builder/GUIFormBuilderImpl.java index e77933986..e8cd60afb 100644 --- a/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/builder/GUIFormBuilderImpl.java +++ b/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/builder/GUIFormBuilderImpl.java @@ -43,6 +43,7 @@ import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.frontend.exception.GUIBuildException; import at.gv.egovernment.moa.id.auth.frontend.velocity.VelocityProvider; +import at.gv.egovernment.moa.id.commons.MOAIDConstants; import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; @@ -54,7 +55,7 @@ import at.gv.egovernment.moa.util.MiscUtil; @Service("guiFormBuilder") public class GUIFormBuilderImpl implements IGUIFormBuilder { - private static final String DEFAULT_CONTENT_TYPE = "text/html; charset=UTF-8"; + private static final String DEFAULT_CONTENT_TYPE = MOAIDConstants.DEFAULT_CONTENT_TYPE_HTML_UTF8; private static final String CONFIG_HTMLTEMPLATES_DIR = "htmlTemplates/"; private static final String CLASSPATH_HTMLTEMPLATES_DIR = "templates/"; diff --git a/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/builder/ServiceProviderSpecificGUIFormBuilderConfiguration.java b/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/builder/ServiceProviderSpecificGUIFormBuilderConfiguration.java index 0a5cdaf3e..63df81b3c 100644 --- a/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/builder/ServiceProviderSpecificGUIFormBuilderConfiguration.java +++ b/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/builder/ServiceProviderSpecificGUIFormBuilderConfiguration.java @@ -126,12 +126,12 @@ public class ServiceProviderSpecificGUIFormBuilderConfiguration extends Abstract try { for (CPEPS current : oaParam.getPepsList()) { String countryName = null; - if (MiscUtil.isNotEmpty(MOAIDAuthConstants.COUNTRYCODE_XX_TO_NAME.get(current.getCountryCode().toUpperCase()))) - countryName = MOAIDAuthConstants.COUNTRYCODE_XX_TO_NAME.get(current.getCountryCode().toUpperCase()); + if (MiscUtil.isNotEmpty(MOAIDAuthConstants.COUNTRYCODE_XX_TO_NAME.get(current.getFullCountryCode().toUpperCase()))) + countryName = MOAIDAuthConstants.COUNTRYCODE_XX_TO_NAME.get(current.getFullCountryCode().toUpperCase()); else - countryName = current.getCountryCode().toUpperCase(); + countryName = current.getFullCountryCode().toUpperCase(); - pepslist += "<option value=" + current.getCountryCode() + ">" + pepslist += "<option value=" + current.getFullCountryCode() + ">" + countryName + "</option>\n"; diff --git a/id/server/moa-id-jaxb_classes/pom.xml b/id/server/moa-id-jaxb_classes/pom.xml index 9dbb28dfe..3d205bb06 100644 --- a/id/server/moa-id-jaxb_classes/pom.xml +++ b/id/server/moa-id-jaxb_classes/pom.xml @@ -52,4 +52,18 @@ </profiles> <version>${moa-id-version}</version> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + </plugins> + </build> + </project>
\ No newline at end of file diff --git a/id/server/modules/moa-id-module-eIDAS/pom.xml b/id/server/modules/moa-id-module-eIDAS/pom.xml index 174ce40cb..55d02e82a 100644 --- a/id/server/modules/moa-id-module-eIDAS/pom.xml +++ b/id/server/modules/moa-id-module-eIDAS/pom.xml @@ -12,11 +12,11 @@ <properties> <repositoryPath>${basedir}/../../../../repository</repositoryPath> - <eidas-commons.version>1.1.0</eidas-commons.version> - <eidas-light-commons.version>1.1.0</eidas-light-commons.version> - <eidas-saml-engine.version>1.1.0</eidas-saml-engine.version> - <eidas-encryption.version>1.1.0</eidas-encryption.version> - <eidas-configmodule.version>1.1.0</eidas-configmodule.version> + <eidas-commons.version>1.2.0</eidas-commons.version> + <eidas-light-commons.version>1.2.0</eidas-light-commons.version> + <eidas-saml-engine.version>1.2.0</eidas-saml-engine.version> + <eidas-encryption.version>1.2.0</eidas-encryption.version> + <eidas-configmodule.version>1.2.0</eidas-configmodule.version> </properties> @@ -166,6 +166,12 @@ <!-- <scope>provided</scope> --> </dependency> + <dependency> + <groupId>com.ibm.icu</groupId> + <artifactId>icu4j</artifactId> + <version>58.2</version> + </dependency> + </dependencies> 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 02c9a8f5d..369d77863 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 @@ -22,6 +22,7 @@ */ 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; @@ -45,7 +46,8 @@ public class Constants { public static final String eIDAS_SAML_ENGINE_NAME_ID_CLASS = "class"; //default implementations for eIDAS SAML-engine functionality - public static final String SAML_SIGNING_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.MOASWSigner"; + //public static final String SAML_SIGNING_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.MOASWSigner"; + public static final String SAML_SIGNING_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.MOAExtendedSWSigner"; public static final String SAML_ENCRYPTION_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.ModifiedEncryptionSW"; //configuration property keys @@ -96,8 +98,6 @@ public class Constants { public static final int eIDAS_REVERSIONSLOG_METADATA = 3400; public static final int eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST = 3401; public static final int eIDAS_REVERSIONSLOG_IDP_AUTHRESPONSE = 3402; - public static final int eIDAS_REVERSIONSLOG_SP_AUTHREQUEST= 3403; - public static final int eIDAS_REVERSIONSLOG_SP_AUTHRESPONSE= 3404; //metadata constants // public final static Map<String, EidasAttributesTypes> METADATA_POSSIBLE_ATTRIBUTES = Collections.unmodifiableMap( @@ -133,16 +133,20 @@ public class Constants { public static final String METADATA_ALLOWED_ALG_DIGIST = - SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256 + ";" + - SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512 ; + SignatureConstants.ALGO_ID_DIGEST_SHA256 + ";" + + SignatureConstants.ALGO_ID_DIGEST_SHA512 ; public static final String METADATA_ALLOWED_ALG_SIGN = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256 + ";" + - SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512; + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512 + ";" + + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1 + ";" + + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1; public static final String METADATA_ALLOWED_ALG_ENCRYPT = EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM + ";" + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192_GCM + ";" + - EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM; + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM + ";" + + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128 + ";" + + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256; } 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 new file mode 100644 index 000000000..e08d302f6 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java @@ -0,0 +1,479 @@ +/* + * 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.config; + +import java.security.KeyStore; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.Configuration; +import org.opensaml.common.impl.SAMLObjectContentReference; +import org.opensaml.security.SAMLSignatureProfileValidator; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.security.SecurityConfiguration; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorFactory; +import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorManager; +import org.opensaml.xml.security.keyinfo.NamedKeyInfoGeneratorManager; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.SignableXMLObject; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureException; +import org.opensaml.xml.signature.SignatureValidator; +import org.opensaml.xml.signature.Signer; +import org.opensaml.xml.validation.ValidationException; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.sun.istack.Nullable; + +import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.MOAWhiteListConfigurator; +import at.gv.egovernment.moa.logging.Logger; +import eu.eidas.auth.commons.EidasErrorKey; +import eu.eidas.auth.engine.configuration.SamlEngineConfigurationException; +import eu.eidas.auth.engine.configuration.dom.ConfigurationAdapter; +import eu.eidas.auth.engine.configuration.dom.ConfigurationKey; +import eu.eidas.auth.engine.configuration.dom.KeyStoreSignatureConfigurator; +import eu.eidas.auth.engine.configuration.dom.SignatureConfiguration; +import eu.eidas.auth.engine.core.ProtocolSignerI; +import eu.eidas.auth.engine.core.impl.BouncyCastleBootstrap; +import eu.eidas.auth.engine.core.impl.CertificateValidator; +import eu.eidas.auth.engine.metadata.MetadataSignerI; +import eu.eidas.auth.engine.xml.opensaml.CertificateUtil; +import eu.eidas.engine.exceptions.EIDASSAMLEngineException; +import eu.eidas.samlengineconfig.CertificateConfigurationManager; +import eu.eidas.util.Preconditions; + +/** + * @author tlenz + * + */ +public class MOAExtendedSWSigner implements ProtocolSignerI, MetadataSignerI { + + private static final String DEFAULT_SIGNATURE_ALGORITHM = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"; + private static final ImmutableSet<String> ALLOWED_ALGORITHMS_FOR_SIGNING; + private static final ImmutableSet<String> ALLOWED_ALGORITHMS_FOR_VERIFYING; + private static final ImmutableSet<String> DEFAULT_ALGORITHM_WHITE_LIST; + private static final String DEFAULT_DIGEST_ALGORITHM = "http://www.w3.org/2001/04/xmlenc#sha512"; + private static final ImmutableMap<Object, Object> SIGNATURE_TO_DIGEST_ALGORITHM_MAP; + private final boolean checkedValidityPeriod; + private final boolean disallowedSelfSignedCertificate; + private final boolean responseSignAssertions; + private final ImmutableSet<String> signatureAlgorithmWhiteList; + private final X509Credential privateSigningCredential; + private final X509Credential publicSigningCredential; + private final X509Credential privateMetadataSigningCredential; + private final X509Credential publicMetadataSigningCredential; + private final ImmutableList<X509Credential> trustedCredentials; + private final String signatureAlgorithm; + + public MOAExtendedSWSigner(Map<String, String> properties) throws SamlEngineConfigurationException { + this(new KeyStoreSignatureConfigurator().getSignatureConfiguration(properties)); + + } + + /** + * @param configManager + * @throws SamlEngineConfigurationException + */ + 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())); + + } + + protected MOAExtendedSWSigner(SignatureConfiguration signatureConfiguration) + throws SamlEngineConfigurationException { + this(signatureConfiguration.isCheckedValidityPeriod(), + signatureConfiguration.isDisallowedSelfSignedCertificate(), + signatureConfiguration.isResponseSignAssertions(), + signatureConfiguration.getSignatureKeyAndCertificate(), signatureConfiguration.getTrustedCertificates(), + signatureConfiguration.getSignatureAlgorithm(), signatureConfiguration.getSignatureAlgorithmWhiteList(), + signatureConfiguration.getMetadataSigningKeyAndCertificate()); + } + + protected MOAExtendedSWSigner(boolean checkedValidityPeriod, boolean disallowedSelfSignedCertificate, + boolean responseSignAssertions, KeyStore.PrivateKeyEntry signatureKeyAndCertificate, + ImmutableSet<X509Certificate> trustedCertificates, String signatureAlgorithmVal, + String signatureAlgorithmWhiteListStr, + KeyStore.PrivateKeyEntry metadataSigningKeyAndCertificate) + throws SamlEngineConfigurationException { + Preconditions.checkNotNull(signatureKeyAndCertificate, "signatureKeyAndCertificate"); + Preconditions.checkNotNull(trustedCertificates, "trustedCertificates"); + String signatureAlg = signatureAlgorithmVal; + + if (StringUtils.isBlank(signatureAlg)) + signatureAlg = DEFAULT_SIGNATURE_ALGORITHM; + + else { + signatureAlg = validateSigningAlgorithm(signatureAlg); + + } + + ImmutableSet signatureAlgorithmWhiteSet = MOAWhiteListConfigurator.getAllowedAlgorithms( + DEFAULT_ALGORITHM_WHITE_LIST, ALLOWED_ALGORITHMS_FOR_VERIFYING, signatureAlgorithmWhiteListStr); + + this.checkedValidityPeriod = checkedValidityPeriod; + this.disallowedSelfSignedCertificate = disallowedSelfSignedCertificate; + this.responseSignAssertions = responseSignAssertions; + this.trustedCredentials = CertificateUtil.getListOfCredential(trustedCertificates); + this.signatureAlgorithmWhiteList = signatureAlgorithmWhiteSet; + this.signatureAlgorithm = signatureAlg; + this.privateSigningCredential = CertificateUtil.createCredential(signatureKeyAndCertificate); + this.publicSigningCredential = CertificateUtil + .toCredential((X509Certificate) signatureKeyAndCertificate.getCertificate()); + + if (null != metadataSigningKeyAndCertificate) { + this.privateMetadataSigningCredential = CertificateUtil.createCredential(metadataSigningKeyAndCertificate); + this.publicMetadataSigningCredential = CertificateUtil + .toCredential((X509Certificate) metadataSigningKeyAndCertificate.getCertificate()); + } else { + this.privateMetadataSigningCredential = null; + this.publicMetadataSigningCredential = null; + } + } + + private static X509Certificate getSignatureCertificate(Signature signature) throws EIDASSAMLEngineException { + KeyInfo keyInfo = signature.getKeyInfo(); + return CertificateUtil.toCertificate(keyInfo); + } + + public static String validateDigestAlgorithm(String signatureAlgorithmName) + throws SamlEngineConfigurationException { + + if (StringUtils.isBlank(signatureAlgorithmName)) { + return DEFAULT_DIGEST_ALGORITHM; + + } + + //BUGFIX: toLowerCase from original eIDAS SAML-engine produce problems with MGF1 signature algorithms + String canonicalAlgorithm = signatureAlgorithmName.trim(); + String digestAlgorithm = (String) SIGNATURE_TO_DIGEST_ALGORITHM_MAP.get(canonicalAlgorithm); + if (null != digestAlgorithm) { + return digestAlgorithm; + + } + String msg = "Signing algorithm \"" + signatureAlgorithmName + + "\" does not contain an allowed digest algorithm"; + + Logger.error(msg); + throw new SamlEngineConfigurationException(msg); + + } + + public static String validateSigningAlgorithm(@Nullable String signatureAlgorithmName) + throws SamlEngineConfigurationException { + if ((signatureAlgorithmName == null) || (StringUtils.isBlank(signatureAlgorithmName))) { + return DEFAULT_SIGNATURE_ALGORITHM; + + } + + //BUGFIX:: toLowerCase from original eIDAS SAML-engine produce problems with MGF1 signature algorithms + String canonicalAlgorithm = signatureAlgorithmName.trim(); + if (ALLOWED_ALGORITHMS_FOR_SIGNING.contains(canonicalAlgorithm)) { + return canonicalAlgorithm; + + } + String msg = "Signing algorithm \"" + signatureAlgorithmName + "\" is not allowed"; + Logger.error(msg); + throw new SamlEngineConfigurationException(msg); + + } + + protected void checkCertificateIssuer(X509Certificate certificate) throws EIDASSAMLEngineException { + CertificateValidator.checkCertificateIssuer(this.disallowedSelfSignedCertificate, certificate); + + } + + protected void checkCertificateValidityPeriod(X509Certificate certificate) throws EIDASSAMLEngineException { + CertificateValidator.checkCertificateValidityPeriod(this.checkedValidityPeriod, certificate); + + } + + protected Signature createSignature(X509Credential credential) throws EIDASSAMLEngineException { + checkCertificateValidityPeriod(credential.getEntityCertificate()); + checkCertificateIssuer(credential.getEntityCertificate()); + Signature signature; + try { + Logger.debug("Creating an OpenSAML signature object"); + + signature = (Signature) Configuration.getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME) + .buildObject(Signature.DEFAULT_ELEMENT_NAME); + + signature.setSigningCredential(credential); + + signature.setSignatureAlgorithm(getSignatureAlgorithm()); + + SecurityConfiguration secConfiguration = Configuration.getGlobalSecurityConfiguration(); + NamedKeyInfoGeneratorManager keyInfoManager = secConfiguration.getKeyInfoGeneratorManager(); + KeyInfoGeneratorManager keyInfoGenManager = keyInfoManager.getDefaultManager(); + KeyInfoGeneratorFactory keyInfoGenFac = keyInfoGenManager.getFactory(credential); + KeyInfoGenerator keyInfoGenerator = keyInfoGenFac.newInstance(); + + KeyInfo keyInfo = keyInfoGenerator.generate(credential); + + signature.setKeyInfo(keyInfo); + signature.setCanonicalizationAlgorithm("http://www.w3.org/2001/10/xml-exc-c14n#"); + } catch (SecurityException e) { + Logger.error("ERROR : Security exception: " + e, e); + throw new EIDASSAMLEngineException(e); + + } + return signature; + } + + public X509Credential getPublicMetadataSigningCredential() { + return this.publicMetadataSigningCredential; + + } + + public X509Credential getPublicSigningCredential() { + return this.publicSigningCredential; + + } + + protected String getSignatureAlgorithm() { + return this.signatureAlgorithm; + + } + + protected ImmutableSet<String> getSignatureAlgorithmWhiteList() { + return this.signatureAlgorithmWhiteList; + + } + + private X509Credential getTrustedCertificate(Signature signature, + List<? extends Credential> trustedCredentialList) throws EIDASSAMLEngineException { + X509Certificate cert = getSignatureCertificate(signature); + + X509Credential entityX509Cred = CertificateUtil.toCredential(cert); + + CertificateUtil.checkTrust(entityX509Cred, trustedCredentialList); + checkCertificateValidityPeriod(cert); + checkCertificateIssuer(cert); + return entityX509Cred; + + } + + protected ImmutableList<X509Credential> getTrustedCredentials() { + return this.trustedCredentials; + + } + + private boolean isAlgorithmAllowedForVerifying(String signatureAlgorithm) { + return ((StringUtils.isNotBlank(signatureAlgorithm)) + && (getSignatureAlgorithmWhiteList().contains(signatureAlgorithm.trim()))); + + } + + public <T extends SignableXMLObject> T sign(T signableObject) throws EIDASSAMLEngineException { + return sign(signableObject, this.privateSigningCredential); + + } + + protected <T extends SignableXMLObject> T sign(T signableObject, X509Credential signingCredential) + throws EIDASSAMLEngineException { + Logger.trace("Start Sign process."); + try { + Signature signature = createSignature(signingCredential); + signableObject.setSignature(signature); + + String digestAlgorithm = validateDigestAlgorithm(getSignatureAlgorithm()); + List contentReferences = signature.getContentReferences(); + if (CollectionUtils.isNotEmpty(contentReferences)) + ((SAMLObjectContentReference) contentReferences.get(0)).setDigestAlgorithm(digestAlgorithm); + + else { + Logger.error("Unable to set DigestMethodAlgorithm - algorithm " + digestAlgorithm + " not set"); + + } + + Logger.trace("Marshall samlToken."); + Configuration.getMarshallerFactory().getMarshaller(signableObject).marshall(signableObject); + + Logger.trace("Sign samlToken."); + Signer.signObject(signature); + + } catch (MarshallingException e) { + Logger.error("ERROR : MarshallingException: " + e, e); + throw new EIDASSAMLEngineException(e); + + } catch (SignatureException e) { + Logger.error("ERROR : Signature exception: " + e, e); + throw new EIDASSAMLEngineException(e); + + } + + return signableObject; + } + + public <T extends SignableXMLObject> T signMetadata(T signableObject) throws EIDASSAMLEngineException { + if (null == this.privateMetadataSigningCredential) { + throw new SamlEngineConfigurationException("No metadataSigningCredential configured"); + + } + return sign(signableObject, this.privateMetadataSigningCredential); + } + + public <T extends SignableXMLObject> T validateMetadataSignature(T signedMetadata) + throws EIDASSAMLEngineException { + return validateSignature(signedMetadata, null); + + } + + private SAMLSignatureProfileValidator validateSamlSignatureStructure(SignableXMLObject signableObject) + throws EIDASSAMLEngineException { + SAMLSignatureProfileValidator sigProfValidator = new SAMLSignatureProfileValidator(); + try { + sigProfValidator.validate(signableObject.getSignature()); + + } catch (ValidationException e) { + Logger.error("ERROR : ValidationException: signature isn't conform to SAML Signature profile: " + e, e); + throw new EIDASSAMLEngineException(e); + + } + return sigProfValidator; + } + + public <T extends SignableXMLObject> T validateSignature(T signedObject, + Collection<X509Certificate> trustedCertificateCollection) throws EIDASSAMLEngineException { + List trustedCreds; + if (CollectionUtils.isEmpty(trustedCertificateCollection)) + trustedCreds = getTrustedCredentials(); + + else { + trustedCreds = CertificateUtil.getListOfCredential(trustedCertificateCollection); + + } + return (T) validateSignatureWithCredentials(signedObject, trustedCreds); + } + + private <T extends SignableXMLObject> T validateSignatureWithCredentials(T signedObject, + List<? extends Credential> trustedCredentialList) throws EIDASSAMLEngineException { + Logger.debug("Start signature validation."); + + validateSamlSignatureStructure(signedObject); + + verifyCryptographicSignature(signedObject.getSignature(), trustedCredentialList); + + return signedObject; + + } + + private void verifyCryptographicSignature(Signature signature, + List<? extends Credential> trustedCredentialList) throws EIDASSAMLEngineException { + String signatureAlgorithmVal = signature.getSignatureAlgorithm(); + Logger.trace("Key algorithm " + SecurityHelper.getKeyAlgorithmFromURI(signatureAlgorithmVal)); + + if (!(isAlgorithmAllowedForVerifying(signatureAlgorithmVal))) { + Logger.error("ERROR : the algorithm " + signatureAlgorithmVal + " used by the signature is not allowed"); + throw new EIDASSAMLEngineException(EidasErrorKey.INVALID_SIGNATURE_ALGORITHM.errorCode()); + + } + + X509Credential entityX509Cred = getTrustedCertificate(signature, trustedCredentialList); + SignatureValidator sigValidator = new SignatureValidator(entityX509Cred); + + try { + sigValidator.validate(signature); + + } catch (ValidationException e) { + Logger.error("ERROR : Signature Validation Exception: " + e, e); + throw new EIDASSAMLEngineException(e); + + } + } + + public boolean isResponseSignAssertions() { + return this.responseSignAssertions; + } + + static { + BouncyCastleBootstrap.bootstrap(); + + ALLOWED_ALGORITHMS_FOR_SIGNING = ImmutableSet.of("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", + "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", + "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", + "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256", + "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384", + "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512", + + //Set other algorithms which are not supported by openSAML in default + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1); + + ALLOWED_ALGORITHMS_FOR_VERIFYING = ImmutableSet.of("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", + "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", + "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", + "http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160", + "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256", + "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384", + "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512", + + //Set other algorithms which are not supported by openSAML in default + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1_MGF1, + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA224_MGF1, + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384_MGF1, + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1); + + DEFAULT_ALGORITHM_WHITE_LIST = ImmutableSet.of("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", + "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", + "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", + "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256", + "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384", + "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512", + + //Set other algorithms which are not supported by openSAML in default + XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1); + + SIGNATURE_TO_DIGEST_ALGORITHM_MAP = ImmutableMap.builder() + .put("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "http://www.w3.org/2001/04/xmlenc#sha256") + .put("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", + "http://www.w3.org/2001/04/xmldsig-more#sha384") + .put("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", "http://www.w3.org/2001/04/xmlenc#sha512") + .put("http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160", + "http://www.w3.org/2001/04/xmlenc#ripemd160") + .put("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256", "http://www.w3.org/2001/04/xmlenc#sha256") + .put("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384", + "http://www.w3.org/2001/04/xmldsig-more#sha384") + .put("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512", "http://www.w3.org/2001/04/xmlenc#sha512") + + //Set other algorithms which are not supported by openSAML in default + .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, "http://www.w3.org/2001/04/xmlenc#sha256") + .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1, "http://www.w3.org/2001/04/xmlenc#sha512") + + .build(); + } +} 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 9ad5f0db3..de4f3fc9c 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 @@ -90,17 +90,21 @@ public class ModifiedEncryptionSW extends KeyStoreSamlEngineEncryption { */ @Override public boolean isEncryptionEnabled(String countryCode) { - // - encrypt if so configured + //encryption is enabled by default in MOA-ID configuration object try { AuthConfiguration moaconfig = AuthConfigurationProviderFactory.getInstance(); Boolean useEncryption = moaconfig.getStorkConfig().getCPEPS(countryCode).isXMLSignatureSupported(); - Logger.info(useEncryption ? "using encryption" : "do not use encrpytion"); + String logResult = useEncryption ? " using encryption" : " do not use encrpytion"; + Logger.debug("eIDAS respone for country " + countryCode + logResult); return useEncryption; + } catch(NullPointerException | ConfigurationException e) { Logger.warn("failed to gather information about encryption for countryCode " + countryCode + " - thus, enabling encryption"); if(Logger.isDebugEnabled()) e.printStackTrace(); return true; + } + } } 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 new file mode 100644 index 000000000..d8fcd1694 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java @@ -0,0 +1,68 @@ +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.Response; + +import at.gv.egovernment.moa.logging.Logger; +import eu.eidas.auth.commons.EidasErrorKey; +import eu.eidas.auth.commons.protocol.IAuthenticationRequest; +import eu.eidas.auth.engine.ProtocolEngine; +import eu.eidas.auth.engine.configuration.ProtocolConfigurationAccessor; +import eu.eidas.auth.engine.xml.opensaml.SAMLEngineUtils; +import eu.eidas.engine.exceptions.EIDASSAMLEngineException; + +public class MOAProtocolEngine extends ProtocolEngine { + + public MOAProtocolEngine(ProtocolConfigurationAccessor configurationAccessor) { + super(configurationAccessor); + + } + +// @Override +// protected X509Certificate getEncryptionCertificate(String requestIssuer, +// String destinationCountryCode) throws EIDASSAMLEngineException { +// if ((StringUtils.isNotBlank(destinationCountryCode)) && (null != getProtocolEncrypter()) +// && (getProtocolEncrypter().isEncryptionEnabled(destinationCountryCode))) { +// X509Certificate encryptionCertificate = getProtocolProcessor().getEncryptionCertificate(requestIssuer); +// +// if (null == encryptionCertificate) { +// return getProtocolEncrypter().getEncryptionCertificate(destinationCountryCode); +// +// } +// return encryptionCertificate; +// } +// return null; +// } +// +// @Override +// protected Response signResponse(IAuthenticationRequest request, Response response) +// throws EIDASSAMLEngineException { +// Response responseToSign = response; +// +// if ((null != getProtocolEncrypter()) && (!(SAMLEngineUtils.isErrorSamlResponse(responseToSign)))) { +// X509Certificate destinationCertificate = getEncryptionCertificate(request.getIssuer(), +// request.getOriginCountryCode()); +// +// if (null != destinationCertificate) { +// responseToSign = getProtocolEncrypter().encryptSamlResponse(responseToSign, destinationCertificate); +// +// } else if (getProtocolEncrypter().isEncryptionEnabled(request.getOriginCountryCode())) { +//// Logger.error(SAML_EXCHANGE, +//// "BUSINESS EXCEPTION : encryption cannot be performed, no matching certificate for issuer=" +//// + request.getIssuer() + " and country=" + request.getOriginCountryCode()); +// +// throw new EIDASSAMLEngineException(EidasErrorKey.SAML_ENGINE_INVALID_CERTIFICATE.errorCode(), +// EidasErrorKey.SAML_ENGINE_INVALID_CERTIFICATE.errorMessage()); +// } +// +// } else if (!(SAMLEngineUtils.isErrorSamlResponse(responseToSign))) { +// checkSendingUnencryptedResponsesAllowed(); +// +// } +// +// Logger.debug("Signing SAML Response."); +// return ((Response) getSigner().sign(responseToSign)); +// } +} 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 a9c4d5d3a..7155040c6 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 @@ -22,13 +22,10 @@ */ package at.gv.egovernment.moa.id.auth.modules.eidas.tasks; -import java.io.ByteArrayOutputStream; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -42,7 +39,6 @@ import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.SingleSignOnService; import org.opensaml.saml2.metadata.provider.MetadataProviderException; -import org.opensaml.xml.util.Base64; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -197,7 +193,17 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { } } - //build requested attribute set + //request + if (reqAttrList.isEmpty()) { + Logger.info("No attributes requested by OA:" + pendingReq.getOnlineApplicationConfiguration().getPublicURLPrefix() + + " --> Request attr:" + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + " by default"); + AttributeDefinition<?> newAttribute = SAMLEngineUtils.getMapOfAllAvailableAttributes().get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); + Builder<?> attrBuilder = AttributeDefinition.builder(newAttribute).required(true); + reqAttrList.add(attrBuilder.build()); + + } + + //build requested attribute set ImmutableAttributeMap reqAttrMap = new ImmutableAttributeMap.Builder().putAll(reqAttrList).build(); //build eIDAS AuthnRequest @@ -211,8 +217,13 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { authnRequestBuilder.nameIdFormat(Constants.eIDAS_REQ_NAMEID_FORMAT); - //set minimum required eIDAS LoA from OA config - authnRequestBuilder.levelOfAssurance(LevelOfAssurance.fromString(oaConfig.getQaaLevel())); + //set minimum required eIDAS LoA from OA config + String LoA = oaConfig.getQaaLevel(); + if (MiscUtil.isNotEmpty(LoA)) + authnRequestBuilder.levelOfAssurance(LevelOfAssurance.fromString(oaConfig.getQaaLevel())); + else + authnRequestBuilder.levelOfAssurance(LevelOfAssurance.HIGH); + authnRequestBuilder.levelOfAssuranceComparison(LevelOfAssuranceComparison.MINIMUM); //set correct SPType for this online application @@ -234,7 +245,7 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { IRequestMessage authnRequest = engine.generateRequestMessage(authnRequestBuilder.build(), issur); - + //encode AuthnRequest byte[] token = authnRequest.getMessageBytes(); String SAMLRequest = EidasStringUtil.encodeToBase64(token); @@ -269,40 +280,6 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { } } - - /** - * Encode the eIDAS request with Redirect binding - * - * @param pendingReq - * @param authnReqEndpoint - * @param token - * @param authnRequest - * @param response - * @throws MOAIDException - */ - private void buildRedirecttBindingRequest(IRequest pendingReq, SingleSignOnService authnReqEndpoint, - byte[] token, IRequestMessage authnRequest, HttpServletResponse response) - throws MOAIDException { - - //FIXME: implement correct deflat encoding accodring to SAML2 Redirect Binding specification - - try { - ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); - Deflater deflater = new Deflater(Deflater.DEFLATED, true); - DeflaterOutputStream deflaterStream = new DeflaterOutputStream(bytesOut, deflater); - deflaterStream.write(token); - deflaterStream.finish(); - String samlReqBase64 = Base64.encodeBytes(bytesOut.toByteArray(), Base64.DONT_BREAK_LINES); - - - - } catch (Exception e) { - Logger.error("eIDAS Redirect-Binding request encoding error: " + e.getMessage()); - throw new MOAIDException("eIDAS.02", new Object[]{e.getMessage()}, e); - - } - - } /** * Encode the eIDAS request with POST binding 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 c4b2bfeae..45ba3d64e 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 @@ -19,12 +19,12 @@ import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.eidas.validator.eIDASResponseValidator; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.commons.EidasStringUtil; import eu.eidas.auth.commons.protocol.IAuthenticationResponse; -import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.engine.exceptions.EIDASSAMLEngineException; @@ -78,16 +78,8 @@ public class ReceiveAuthnResponseTask extends AbstractAuthServletTask { // ********************************************************** // ******* MOA-ID specific response validation ********** // ********************************************************** - - //validate received LoA against minimum required LoA - LevelOfAssurance reqLoA = LevelOfAssurance.fromString(pendingReq.getOnlineApplicationConfiguration().getQaaLevel()); - LevelOfAssurance respLoA = LevelOfAssurance.fromString(samlResp.getLevelOfAssurance()); - if (respLoA.numericValue() < reqLoA.numericValue()) { - Logger.error("eIDAS Response LevelOfAssurance is lower than the required! " - + "(Resp-LoA:" + respLoA.getValue() + " Req-LoA:" + reqLoA.getValue() + ")"); - throw new MOAIDException("eIDAS.14", new Object[]{respLoA.getValue()}); - - } + String spCountry = authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, "AT"); + eIDASResponseValidator.validateResponse(pendingReq, samlResp, spCountry); // ********************************************************** 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 f29d2bb65..47cdb4ade 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 @@ -95,5 +95,22 @@ 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; +// } } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java index 7d647ff15..a2c6a3ad9 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java @@ -22,7 +22,6 @@ */ package at.gv.egovernment.moa.id.auth.modules.eidas.utils; -import java.util.Locale; import java.util.regex.Pattern; import org.apache.commons.collections.CollectionUtils; @@ -48,6 +47,11 @@ public class MOAWhiteListConfigurator { } ImmutableSet.Builder<String> allowed = ImmutableSet.builder(); String[] wlAlgorithms = WHITE_LIST_SPLITTER.split(algorithmWhiteListValue); + + //BugFix: remove newlines from configuration + for (int i=0; i<wlAlgorithms.length; i++) + wlAlgorithms[i] = StringUtils.trimToNull(KeyValueUtils.removeAllNewlineFromString(wlAlgorithms[i])); + if (null != wlAlgorithms && wlAlgorithms.length > 0) { return getAllowedAlgorithms(defaultWhiteList, allowedValues, ImmutableSet.<String>copyOf(wlAlgorithms)); } @@ -72,7 +76,11 @@ public class MOAWhiteListConfigurator { candidateValue = StringUtils.trimToNull( KeyValueUtils.removeAllNewlineFromString(candidateValue)); if (StringUtils.isNotBlank(candidateValue)) { - String candidateAlgorithm = StringUtils.lowerCase(candidateValue, Locale.ENGLISH); + + //BUGFIX: eIDAS SAML-engine MPF1 signature schemes problem + String candidateAlgorithm = candidateValue; + //String candidateAlgorithm = StringUtils.lowerCase(candidateValue, Locale.ENGLISH); + if (allowedValues.contains(candidateAlgorithm)) { allowed.add(candidateValue); if (!modified && !candidateAlgorithm.equals(candidateValue)) { 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 dd14972e3..8faaf1874 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 @@ -210,10 +210,15 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { addAssertionConsumerService(); } fillNameIDFormat(spSSODescriptor); - if (params.getSpEngine() != null) { - ProtocolEngineI spEngine = params.getSpEngine(); - ((MetadataSignerI) spEngine.getSigner()).signMetadata(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); } @@ -266,6 +271,8 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { } idpSSODescriptor.addSupportedProtocol(params.getIdpSamlProtocol()); fillNameIDFormat(idpSSODescriptor); + + if (params.getIdpEngine() != null) { if (params.getIdpEngine().getProtocolProcessor() != null && params.getIdpEngine().getProtocolProcessor().getFormat() == SAMLExtensionFormat.EIDAS10) { @@ -277,8 +284,13 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { */ generateSupportedAttributes(idpSSODescriptor, getAllSupportedAttributes()); } - ProtocolEngineI idpEngine = params.getIdpEngine(); - ((MetadataSignerI) idpEngine.getSigner()).signMetadata(idpSSODescriptor); + + + /**FIXME: + * Double signing of IDPSSODescribtor is not required + */ +// ProtocolEngineI idpEngine = params.getIdpEngine(); +// ((MetadataSignerI) idpEngine.getSigner()).signMetadata(idpSSODescriptor); } idpSSODescriptor.getSingleSignOnServices().addAll(buildSingleSignOnServicesBindingLocations()); @@ -465,7 +477,7 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { X509Certificate decryptionCertificate = engine.getDecryptionCertificate(); if (null != decryptionCertificate) { - params.setEncryptionCredential(CertificateUtil.toCredential(decryptionCertificate)); + params.setSpEncryptionCredential(CertificateUtil.toCredential(decryptionCertificate)); } params.setSigningCredential(CertificateUtil.toCredential(engine.getSigningCertificate())); params.setIdpEngine(engine); @@ -530,7 +542,10 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { Set<String> signatureMethods = EIDASUtil.parseSemicolonSeparatedList(params.getDigestMethods()); Set<String> digestMethods = new HashSet<String>(); for (String signatureMethod : signatureMethods) { - digestMethods.add(CertificateUtil.validateDigestAlgorithm(signatureMethod)); + + //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); @@ -569,7 +584,7 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { generateDigest(eidasExtensions); if (!StringUtils.isEmpty(params.getSigningMethods())) { - Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(params.getDigestMethods()); + Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(params.getSigningMethods()); for (String signMethod : signMethods) { final SigningMethod sm = (SigningMethod) BuilderFactoryUtil.buildXmlObject(SigningMethod.DEF_ELEMENT_NAME); 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 eb50c113f..70135c06f 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 @@ -30,8 +30,8 @@ import org.opensaml.xml.ConfigurationException; import org.opensaml.xml.XMLConfigurator; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; +import at.gv.egovernment.moa.id.auth.modules.eidas.config.MOAExtendedSWSigner; import at.gv.egovernment.moa.id.auth.modules.eidas.config.MOAIDCertificateManagerConfigurationImpl; -import at.gv.egovernment.moa.id.auth.modules.eidas.config.MOASWSigner; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAEidasProtocolProcesser; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASMetadataProviderDecorator; @@ -69,8 +69,8 @@ public class SAMLEngineUtils { metadataFetcher = new MOAeIDASMetadataProviderDecorator(moaeIDASMetadataProvider); //set metadata signer - metadataSigner = new MOASWSigner(configManager); - + metadataSigner = new MOAExtendedSWSigner(configManager); + //build eIDAS SAML eninge ProtocolEngineI engine = MOAProtocolEngineFactory.createProtocolEngine( Constants.eIDAS_SAML_ENGINE_NAME, diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java new file mode 100644 index 000000000..30e1e4505 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java @@ -0,0 +1,75 @@ +/* + * 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.regex.Matcher; +import java.util.regex.Pattern; + +import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; +import at.gv.egovernment.moa.id.data.Trible; +import at.gv.egovernment.moa.logging.Logger; + +/** + * @author tlenz + * + */ +public class eIDASAttributeProcessingUtils { + public static final String PERSONALIDENIFIER_VALIDATION_PATTERN = "^[A-Z,a-z]{2}/[A-Z,a-z]{2}/.*"; + + /** + * Validate a eIDAS PersonalIdentifier attribute value + * This validation is done according to eIDAS SAML Attribute Profile - Section 2.2.3 Unique Identifier + * + * @param uniqueID eIDAS attribute value of a unique identifier + * @return true if the uniqueID matches to eIDAS to Unique Identifier specification, otherwise false + */ + public static boolean validateEidasPersonalIdentifier(String uniqueID) { + Pattern pattern = Pattern.compile(PERSONALIDENIFIER_VALIDATION_PATTERN ); + Matcher matcher = pattern.matcher(uniqueID); + return matcher.matches(); + + } + + + /** + * Parse an eIDAS PersonalIdentifier attribute value into it components. + * This processing is done according to eIDAS SAML Attribute Profile - Section 2.2.3 Unique Identifier + * + * @param uniqueID eIDAS attribute value of a unique identifier + * @return {@link Trible} that contains: + * <br> First : citizen country + * <br> Second: destination country + * <br> Third : unique identifier + * <br> or null if the attribute value has a wrong format + */ + public static Trible<String, String, String> parseEidasPersonalIdentifier(String uniqueID) { + if (!validateEidasPersonalIdentifier(uniqueID)) { + Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + + " looks wrong formated. Value:" + ((String)uniqueID)); + return null; + + } + return Trible.newInstance(uniqueID.substring(0, 2), uniqueID.substring(3, 5), uniqueID.substring(6)); + + } +} 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 13e64cdd0..388d65963 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 @@ -25,6 +25,8 @@ package at.gv.egovernment.moa.id.protocols.eidas; import java.io.IOException; import java.io.StringWriter; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -36,7 +38,6 @@ import org.opensaml.saml2.core.StatusCode; import org.opensaml.saml2.metadata.AssertionConsumerService; import org.opensaml.saml2.metadata.EntityDescriptor; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -51,6 +52,7 @@ import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASAuthnRequestV import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASException; 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.MOAIDConstants; import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; import at.gv.egovernment.moa.id.commons.api.IRequest; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; @@ -149,7 +151,8 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { //preProcess eIDAS request preProcess(req, resp, pendingReq); - revisionsLogger.logEvent(pendingReq, Constants.eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST); + revisionsLogger.logEvent(pendingReq, Constants.eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST, + pendingReq.getEidasRequest().getId()); //AuthnRequest needs authentication pendingReq.setNeedAuthentication(true); @@ -213,6 +216,11 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { } + //check eIDAS node configuration + IOAAuthParameters oaConfig = authConfig.getOnlineApplicationParameter(samlReq.getIssuer()); + if (oaConfig == null) + throw new EIDASAuthnRequestProcessingException("eIDAS.08", new Object[]{samlReq.getIssuer()}); + //validate AssertionConsumerServiceURL against metadata EntityDescriptor eIDASNodeEntityDesc = new MOAeIDASMetadataProviderDecorator(eIDASMetadataProvider) .getEntityDescriptor(eIDASSamlReq.getIssuer(), SAMLEngineUtils.getMetadataSigner()); @@ -258,8 +266,33 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { } + //validate request country-code against eIDAS node config + String reqCC = samlReq.getOriginCountryCode(); + String eIDASTarget = oaConfig.getIdentityLinkDomainIdentifier(); + + //validate eIDAS target + Pattern pattern = Pattern.compile("^" + at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS + + "\\+[A-Z,a-z]{2}\\+[A-Z,a-z]{2}$"); + Matcher matcher = pattern.matcher(eIDASTarget); + if (MiscUtil.isEmpty(eIDASTarget) || !matcher.matches()) { + Logger.error("Configuration for eIDAS-node:" + samlReq.getIssuer() + + " contains wrong formated eIDAS target:" + eIDASTarget); + throw new MOAIDException("config.08", new Object[]{samlReq.getIssuer()}); + + } else { + String[] splittedTarget = eIDASTarget.split("\\+"); + if (!splittedTarget[2].equalsIgnoreCase(reqCC)) { + Logger.error("Configuration for eIDAS-node:" + samlReq.getIssuer() + + " Destination Country from request (" + reqCC + + ") does not match to configuration:" + eIDASTarget); + throw new MOAIDException("eIDAS.01", + new Object[]{"Destination Country from request does not match to configuration"}); + + } + Logger.debug("CountryCode from request matches eIDAS-node configuration target"); + } - + //************************************************* //***** store eIDAS request information ********* //************************************************* @@ -269,10 +302,6 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { // - memorize relaystate String relayState = request.getParameter("RelayState"); pendingReq.setRemoteRelayState(relayState); - - // - memorize country code of target country - pendingReq.setGenericDataToSession( - RequestImpl.eIDAS_GENERIC_REQ_DATA_COUNTRY, samlReq.getOriginCountryCode()); //store level of assurance pendingReq.setGenericDataToSession(RequestImpl.eIDAS_GENERIC_REQ_DATA_LEVELOFASSURENCE, @@ -288,10 +317,6 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { pendingReq.setOAURL(samlReq.getIssuer()); // - memorize OA config - IOAAuthParameters oaConfig = authConfig.getOnlineApplicationParameter(pendingReq.getOAURL()); - if (oaConfig == null) - throw new EIDASAuthnRequestProcessingException("eIDAS.08", new Object[]{pendingReq.getOAURL()}); - pendingReq.setOnlineApplicationConfiguration(oaConfig); // - memorize service-provider type from eIDAS request @@ -302,7 +327,7 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { if (MiscUtil.isEmpty(spType)) spType = MetadataUtil.getSPTypeFromMetadata(eIDASNodeEntityDesc); - if (MiscUtil.isEmpty(spType)) + if (MiscUtil.isNotEmpty(spType)) Logger.debug("eIDAS request has SPType:" + spType); else Logger.info("eIDAS request and eIDAS metadata contains NO 'SPType' element."); @@ -367,7 +392,7 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { String token = EidasStringUtil.encodeToBase64(eIDASRespMsg.getMessageBytes()); VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); - Template template = velocityEngine.getTemplate("/resources/templates/stork2_postbinding_template.html"); + Template template = velocityEngine.getTemplate("/resources/templates/eidas_postbinding_template.vm"); VelocityContext context = new VelocityContext(); context.put("RelayState", eidasReq.getRemoteRelayState()); @@ -387,7 +412,7 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { Logger.trace("Sending html content : " + new String(writer.getBuffer())); byte[] content = writer.getBuffer().toString().getBytes("UTF-8"); - response.setContentType(MediaType.TEXT_HTML.getType()); + response.setContentType(MOAIDConstants.DEFAULT_CONTENT_TYPE_HTML_UTF8); response.setContentLength(content.length); response.getOutputStream().write(content); 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 174fa2c17..df96bef12 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 @@ -72,13 +72,19 @@ public class EidasMetaDataRequest implements IAction { String metadata_url = pubURLPrefix + Constants.eIDAS_HTTP_ENDPOINT_METADATA; String sp_return_url = pubURLPrefix + Constants.eIDAS_HTTP_ENDPOINT_SP_POST; + //generate eIDAS metadata String metaData = generateMetadata(req, metadata_url, sp_return_url); - + + //write content to response + byte[] content = metaData.getBytes("UTF-8"); + httpResp.setStatus(HttpServletResponse.SC_OK); + httpResp.setContentType(MediaType.APPLICATION_XML.toString()); + httpResp.setContentLength(content.length); + httpResp.getOutputStream().write(content); + + //write log if required Logger.trace(metaData); - - httpResp.setContentType(MediaType.APPLICATION_XML.getType()); - httpResp.getWriter().print(metaData); - httpResp.flushBuffer(); + } catch (Exception e) { Logger.error("eIDAS Metadata generation FAILED.", e); throw new MOAIDException("eIDAS.05", new Object[]{e.getMessage()}, e); 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 22ac37604..2fe52bb4f 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 @@ -34,7 +34,6 @@ import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.opensaml.saml2.core.StatusCode; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import com.google.common.collect.ImmutableSet; @@ -44,11 +43,14 @@ 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.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.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; @@ -121,12 +123,28 @@ public class eIDASAuthenticationRequest implements IAction { newValue = authData.getBPK(); isUniqueID = true; + //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: @@ -145,8 +163,14 @@ public class eIDASAuthenticationRequest implements IAction { } - if(MiscUtil.isEmpty(newValue)) { - Logger.info("eIDAS Attr:" + attr.getNameUri() + " is not available."); + if(MiscUtil.isEmpty(newValue)) { + 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 @@ -228,12 +252,13 @@ public class eIDASAuthenticationRequest implements IAction { } - revisionsLogger.logEvent(req, Constants.eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST); + revisionsLogger.logEvent(req, Constants.eIDAS_REVERSIONSLOG_IDP_AUTHRESPONSE, + eIDASRespMsg.getResponse().getId()); // send the response try { VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); - Template template = velocityEngine.getTemplate("/resources/templates/stork2_postbinding_template.html"); + Template template = velocityEngine.getTemplate("/resources/templates/eidas_postbinding_template.vm"); VelocityContext context = new VelocityContext(); context.put("RelayState", eidasRequest.getRemoteRelayState()); @@ -253,7 +278,7 @@ public class eIDASAuthenticationRequest implements IAction { Logger.trace("Sending html content : " + new String(writer.getBuffer())); byte[] content = writer.getBuffer().toString().getBytes("UTF-8"); - httpResp.setContentType(MediaType.TEXT_HTML.getType()); + httpResp.setContentType(MOAIDConstants.DEFAULT_CONTENT_TYPE_HTML_UTF8); httpResp.setContentLength(content.length); httpResp.getOutputStream().write(content); @@ -295,12 +320,20 @@ public class eIDASAuthenticationRequest implements IAction { private String generateTransientNameID(String nameID) { - String random = Random.nextLongRandom(); + //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((nameID + random).getBytes("ISO-8859-1")); - return Base64Utils.encode(hash); + 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); diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java new file mode 100644 index 000000000..f0527bc5e --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java @@ -0,0 +1,130 @@ +/* + * 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.validator; + +import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils; +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.Trible; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.commons.protocol.IAuthenticationResponse; +import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance; + +/** + * @author tlenz + * + */ +public class eIDASResponseValidator { + + + public static void validateResponse(IRequest pendingReq, IAuthenticationResponse samlResp, String spCountry) throws MOAIDException { + + /*-----------------------------------------------------| + * validate received LoA against minimum required LoA | + *_____________________________________________________| + */ + LevelOfAssurance reqLoA = LevelOfAssurance.fromString(pendingReq.getOnlineApplicationConfiguration().getQaaLevel()); + LevelOfAssurance respLoA = LevelOfAssurance.fromString(samlResp.getLevelOfAssurance()); + if (respLoA.numericValue() < reqLoA.numericValue()) { + Logger.error("eIDAS Response LevelOfAssurance is lower than the required! " + + "(Resp-LoA:" + respLoA.getValue() + " Req-LoA:" + reqLoA.getValue() + ")"); + throw new MOAIDException("eIDAS.14", new Object[]{respLoA.getValue()}); + + } + + /*-----------------------------------------------------| + * validate 'PersonalIdentifier' attribute | + *_____________________________________________________| + */ + String respCC = samlResp.getCountry(); + Object personalIdObj = samlResp.getAttributes().getFirstValue( + SAMLEngineUtils.getMapOfAllAvailableAttributes().get( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER)); + + //check attribute type + if (personalIdObj == null || !(personalIdObj instanceof String)) + Logger.warn("eIDAS Response include NO 'PersonalIdentifier' attriubte " + + ".... That can be a BIG problem in further processing steps"); + + else { + //validate attribute value format + Trible<String, String, String> split = + eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier((String)personalIdObj); + if (split == null) { + throw new MOAIDException("eIDAS.16", + new Object[]{ + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "Wrong identifier format"}); + + } else { + //validation according to eIDAS SAML Attribute Profile, Section 2.2.3 + if (MiscUtil.isEmpty(split.getSecond())) { + Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + + " includes NO destination country. Value:" + ((String)personalIdObj)); + throw new MOAIDException("eIDAS.16", + new Object[]{ + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "No or empty destination country"}); + + } + if (!split.getSecond().equalsIgnoreCase(spCountry)) { + Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + + " includes wrong destination country. Value:" + ((String)personalIdObj) + + " SP-Country:" + spCountry); + throw new MOAIDException("eIDAS.16", + new Object[]{ + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "Destination country does not match to SP country"}); + + } + + if (MiscUtil.isEmpty(split.getFirst())) { + Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + + " includes NO citizen country. Value:" + ((String)personalIdObj)); + throw new MOAIDException("eIDAS.16", + new Object[]{ + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "No or empty citizen country"}); + + } + if (!split.getFirst().equalsIgnoreCase(respCC)) { + Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + + " includes a citizen country that does not match to eIDAS Response node. " + + " Value:" + ((String)personalIdObj) + + " Response-Node Country:" + respCC); + throw new MOAIDException("eIDAS.16", + new Object[]{ + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "Citizen country does not match to eIDAS-node country that generates the response"}); + + } + } + } + + + + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/resources/resources/templates/eidas_postbinding_template.vm b/id/server/modules/moa-id-module-eIDAS/src/main/resources/resources/templates/eidas_postbinding_template.vm index 3bd225b00..0535d48b6 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/resources/resources/templates/eidas_postbinding_template.vm +++ b/id/server/modules/moa-id-module-eIDAS/src/main/resources/resources/templates/eidas_postbinding_template.vm @@ -7,7 +7,7 @@ ## SAMLRequest - String - the Base64 encoded SAML Request ## SAMLResponse - String - the Base64 encoded SAML Response ## Contains target attribute to delegate PEPS authentication out of iFrame - +<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> diff --git a/repository/eu/eidas/eidas-commons/1.2.0/eidas-commons-1.2.0.jar b/repository/eu/eidas/eidas-commons/1.2.0/eidas-commons-1.2.0.jar Binary files differnew file mode 100644 index 000000000..b4a614f7f --- /dev/null +++ b/repository/eu/eidas/eidas-commons/1.2.0/eidas-commons-1.2.0.jar diff --git a/repository/eu/eidas/eidas-configmodule/1.2.0/eidas-configmodule-1.2.0.jar b/repository/eu/eidas/eidas-configmodule/1.2.0/eidas-configmodule-1.2.0.jar Binary files differnew file mode 100644 index 000000000..201b7ddfd --- /dev/null +++ b/repository/eu/eidas/eidas-configmodule/1.2.0/eidas-configmodule-1.2.0.jar diff --git a/repository/eu/eidas/eidas-encryption/1.2.0/eidas-encryption-1.2.0.jar b/repository/eu/eidas/eidas-encryption/1.2.0/eidas-encryption-1.2.0.jar Binary files differnew file mode 100644 index 000000000..aa9ac228a --- /dev/null +++ b/repository/eu/eidas/eidas-encryption/1.2.0/eidas-encryption-1.2.0.jar diff --git a/repository/eu/eidas/eidas-light-commons/1.2.0/eidas-light-commons-1.2.0.jar b/repository/eu/eidas/eidas-light-commons/1.2.0/eidas-light-commons-1.2.0.jar Binary files differnew file mode 100644 index 000000000..c6d4ecdbb --- /dev/null +++ b/repository/eu/eidas/eidas-light-commons/1.2.0/eidas-light-commons-1.2.0.jar diff --git a/repository/eu/eidas/eidas-saml-engine/1.2.0/eidas-saml-engine-1.2.0.jar b/repository/eu/eidas/eidas-saml-engine/1.2.0/eidas-saml-engine-1.2.0.jar Binary files differnew file mode 100644 index 000000000..3a973e72b --- /dev/null +++ b/repository/eu/eidas/eidas-saml-engine/1.2.0/eidas-saml-engine-1.2.0.jar diff --git a/repository/eu/eidas/eidas-specific-communication-definition/1.2.0/eidas-specific-communication-definition-1.2.0.jar b/repository/eu/eidas/eidas-specific-communication-definition/1.2.0/eidas-specific-communication-definition-1.2.0.jar Binary files differnew file mode 100644 index 000000000..411e4cbe3 --- /dev/null +++ b/repository/eu/eidas/eidas-specific-communication-definition/1.2.0/eidas-specific-communication-definition-1.2.0.jar diff --git a/repository/eu/eidas/eidas-specific/1.2.0/eidas-specific-1.2.0.jar b/repository/eu/eidas/eidas-specific/1.2.0/eidas-specific-1.2.0.jar Binary files differnew file mode 100644 index 000000000..a924833ac --- /dev/null +++ b/repository/eu/eidas/eidas-specific/1.2.0/eidas-specific-1.2.0.jar |