diff options
Diffstat (limited to 'id/server')
57 files changed, 1882 insertions, 876 deletions
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/data/deploy/conf/moa-id/htmlTemplates/javascript_tempalte.js b/id/server/data/deploy/conf/moa-id/htmlTemplates/javascript_tempalte.js index a463bae65..daa60ac11 100644 --- a/id/server/data/deploy/conf/moa-id/htmlTemplates/javascript_tempalte.js +++ b/id/server/data/deploy/conf/moa-id/htmlTemplates/javascript_tempalte.js @@ -129,12 +129,14 @@ function isIE() { console.log("Browser is Chrome: "+checkIfBrowserIsChrome()); console.log("Browser is Safari: "+checkIfBrowserIsSafari()); console.log("Browser is Edge: "+checkIfBrowserIsEdge()); + console.log("Browser is Firefox(>51): " +checkIfBrowserIsFirefox()) var cnt = 0; if(checkIfBrowserIsChrome())cnt++; if(checkIfBrowserIsEdge())cnt++; if(checkIfBrowserIsSafari())cnt++; + if(checkIfBrowserIsFirefox())cnt++; if(cnt==0 || cnt>1)//cnt>1 means perhaps wrong detection return true; @@ -149,11 +151,25 @@ function isIE() { var button = document.getElementsByName("bkuButtonOnline")[0]; button.setAttribute("class","browserInfoButton"); button.setAttribute("title","Java wird nicht unterstützt, klicken für mehr Informationen."); - button.setAttribute("onClick","alert('Java wird von Ihrem Browser nicht unterstützt, ist jedoch für den Betrieb der Online Bürgerkartenumgebung notwendig.\\nWollen Sie dennoch die Online Bürgerkartenumgebung verwenden, wird zur Zeit Java noch von Firefox und MS Internet Explorer unterstützt. \\nAlternativ koennen Sie auch eine lokale Bürgerkartenumgebung verwenden, verfügbar unter www.buergerkarte.at.');"); + button.setAttribute("onClick","alert('Java wird von Ihrem Browser nicht unterstützt, ist jedoch für den Betrieb der Online Bürgerkartenumgebung notwendig.\\nWollen Sie dennoch die Online Bürgerkartenumgebung verwenden, wird zur Zeit Java noch von MS Internet Explorer unterstützt. \\nAlternativ koennen Sie auch eine lokale Bürgerkartenumgebung verwenden, verfügbar unter www.buergerkarte.at.');"); return false; } + function checkIfBrowserIsFirefox() { + var firefoxMarkerPos = navigator.userAgent.toLowerCase().indexOf('firefox'); + if (firefoxMarkerPos > -1) { + if (navigator.userAgent.toLowerCase().length >= (firefoxMarkerPos + 'firefox/'.length)) { + var ffversion = navigator.userAgent.toLowerCase().substring(firefoxMarkerPos + 8); + if (ffversion > 51) { + return true; + } + } else { + console.log("Browser looks like Firefox but has suspect userAgent string: " + navigator.userAgent.toLowerCase()); + } + } + return false; + } function checkIfBrowserIsChrome(){ var chrome_defined = !!window.chrome;//chrome object defined var webstore_defined = false; @@ -173,7 +189,30 @@ function isIE() { function checkIfBrowserIsSafari(){ var cond1 = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0; return cond1; - } + } + function setBKUAvailable(available) { + login = document.getElementById("localBKU"); + //active = (login.className.indexOf("lokalebkuaktiv") != -1); + try { + if (available) { + console.log("Local BKU available") + //login.className = login.className.replace("lokalebkuinaktiv", "lokalebkuaktiv"); + var localBKUForm = document.getElementById("moaidform"); + var button = localBKUForm.getElementsByTagName("input")[5]; + button.removeAttribute("class");; + button.setAttribute("title","Bürgerkarte mit localer Bürgerkartenumgebung."); + } else if (!available) { + //login.className = login.className.replace("lokalebkuaktiv", "lokalebkuinaktiv"); + var localBKUForm = document.getElementById("moaidform"); + var button = localBKUForm.getElementsByTagName("input")[5]; + button.setAttribute("class","browserInfoButton"); + button.setAttribute("title","Es wurde keine Bürgerkartenumgebung gefunden. Sollte es sich hierbei um einen Fehler handeln können Sie den Prozess durch einen Klick auf den Button denoch fortsetzen."); + console.log("Local BKU NOT available") + } + } catch(e) {console.log("Local BKU detection is not possible! Msg: "+e);} + + } + /* function setSSOSelection() { document.getElementById("useSSO").value = "false"; var checkbox = document.getElementById("SSOCheckBox"); diff --git a/id/server/data/deploy/conf/moa-id/htmlTemplates/loginFormFull.html b/id/server/data/deploy/conf/moa-id/htmlTemplates/loginFormFull.html index 32f0a7d4d..794145a2d 100644 --- a/id/server/data/deploy/conf/moa-id/htmlTemplates/loginFormFull.html +++ b/id/server/data/deploy/conf/moa-id/htmlTemplates/loginFormFull.html @@ -60,6 +60,7 @@ <input type="submit" value=" Lokale Bürgerkartenumgebung " tabindex="4" role="button" onclick="setMandateSelection();"> </form> + <iframe name="bkudetect" width="0" height="0" scrolling="no" marginheight="0" marginwidth="0" frameborder="0" src="$contextPath/iframeLBKUdetect.html"><\/iframe> </div> <!-- Single Sign-On Session transfer functionality --> 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/builder/attributes/IAttributeGenerator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/builder/attributes/IAttributeGenerator.java index 0d51818f8..ecd67db64 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/builder/attributes/IAttributeGenerator.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/builder/attributes/IAttributeGenerator.java @@ -23,6 +23,13 @@ package at.gv.egovernment.moa.id.protocols.builder.attributes; public interface IAttributeGenerator<ATT> { + /** + * + * @param friendlyName FriendlyName + * @param name Name + * @param value value + * @return + */ public abstract ATT buildStringAttribute(final String friendlyName, final String name, final String value); public abstract ATT buildIntegerAttribute(final String friendlyName, final String name, final int value); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java index df4866c30..af9ba0180 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java @@ -200,7 +200,7 @@ public abstract class AbstractCredentialProvider { signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); } else if (privatekey instanceof ECPrivateKey) { - signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA1); + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256); } else { Logger.warn("Could NOT evaluate the Private-Key type from " + credentials.getEntityId() + " credential."); 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-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetect.html b/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetect.html new file mode 100644 index 000000000..54dc9d910 --- /dev/null +++ b/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetect.html @@ -0,0 +1,32 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html lang="de"> +<head> +<title>BKU-Erkennung</title> +<script type="text/javascript"> +<!-- + bkuprot = location.protocol; + bkuhost = "localhost"; + bkuport = (bkuprot == "https:" ? 3496 : 3495); + bkupath = "https-security-layer-request"; + bkuurl = bkuprot + "//" + bkuhost + ":" + bkuport + "/" + bkupath; + baseurl = location.href.substr(0, location.href.lastIndexOf("/")); +//--> +</script> +</head> +<body style="background-color:transparent"> +<script type="text/javascript"> +<!-- + if (bkuprot == "https:" || bkuprot == "http:") { + parent.setBKUAvailable(false); + document.write('<form name="bkudetectform" method="POST" target="bkudetect" action="' + bkuurl + '" enctype="application/x-www-form-urlencoded">'); + document.write('<input type="hidden" name="XMLRequest" value="<?xml version="1.0" encoding="UTF-8"?><NullOperationRequest xmlns="http://www.buergerkarte.at/namespaces/securitylayer/1.2#"/>" />'); + document.write('<input type="hidden" name="RedirectURL" value="' + baseurl + '/iframeLBKUdetected.html"/>'); + document.write('</form>'); + try { + document.bkudetectform.submit(); + } catch(e) {} + } +//--> +</script> +</body> +</html> diff --git a/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetected.html b/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetected.html new file mode 100644 index 000000000..8769c38ad --- /dev/null +++ b/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetected.html @@ -0,0 +1,14 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html lang="de"> +<head> +<title>BKU-Erkennung</title> +<script type="text/javascript"> + parent.setBKUAvailable(true); +</script> +</head> +<body style="background-color:transparent"> +<script type="text/javascript"> + parent.setBKUAvailable(true); +</script> +</body> +</html> 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..36323f3a5 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,12 +22,9 @@ */ package at.gv.egovernment.moa.id.auth.modules.eidas; +import org.apache.xml.security.signature.XMLSignature; import org.opensaml.xml.encryption.EncryptionConstants; import org.opensaml.xml.signature.SignatureConstants; -//import eu.eidas.auth.engine.core.validator.eidas.EIDASAttributes; - -import eu.eidas.auth.commons.attribute.AttributeRegistries; -import eu.eidas.auth.commons.attribute.AttributeRegistry; /** * @author tlenz @@ -45,7 +42,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 @@ -59,12 +57,16 @@ public class Constants { public static final String CONIG_PROPS_EIDAS_SAMLENGINE_SIGN_CONFIGFILE = CONIG_PROPS_EIDAS_SAMLENGINE_PREFIX + "." + CONIG_PROPS_EIDAS_SAMLENGINE_SIGN + ".config.file"; public static final String CONIG_PROPS_EIDAS_SAMLENGINE_ENC_CONFIGFILE = CONIG_PROPS_EIDAS_SAMLENGINE_PREFIX + "." - + CONIG_PROPS_EIDAS_SAMLENGINE_ENCRYPT + ".config.file"; + + CONIG_PROPS_EIDAS_SAMLENGINE_ENCRYPT + ".config.file"; + public static final String CONIG_PROPS_EIDAS_SAMLENGINE_ATTIONAL_ATTRIBUTE_DEFINITIONS = + CONIG_PROPS_EIDAS_SAMLENGINE_PREFIX + ".attributes.addition.config"; public static final String CONIG_PROPS_EIDAS_METADATA_VALIDATION_TRUSTSTORE = CONIG_PROPS_EIDAS_PREFIX + ".metadata.validation.truststore"; + public static final String CONIG_PROPS_EIDAS_NODE_COUNTRYCODE = CONIG_PROPS_EIDAS_NODE + ".countrycode"; public static final String CONIG_PROPS_EIDAS_NODE_COUNTRY = CONIG_PROPS_EIDAS_NODE + ".country"; - public static final String CONIG_PROPS_EIDAS_NODE_LoA = CONIG_PROPS_EIDAS_NODE + ".LoA"; + public static final String CONIG_PROPS_EIDAS_NODE_LoA = CONIG_PROPS_EIDAS_NODE + ".LoA"; + //timeouts and clock skews @@ -86,8 +88,6 @@ public class Constants { //http endpoint descriptions public static final String eIDAS_HTTP_ENDPOINT_SP_POST = "/eidas/sp/post"; public static final String eIDAS_HTTP_ENDPOINT_SP_REDIRECT = "/eidas/sp/redirect"; - //public static final String eIDAS_HTTP_ENDPOINT_IDP_POST = "/eidas/idp/post"; - //public static final String eIDAS_HTTP_ENDPOINT_IDP_REDIRECT = "/eidas/idp/redirect"; public static final String eIDAS_HTTP_ENDPOINT_IDP_COLLEAGUEREQUEST = "/eidas/ColleagueRequest"; public static final String eIDAS_HTTP_ENDPOINT_METADATA = "/eidas/metadata"; @@ -96,53 +96,23 @@ 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( -// new HashMap<String, EidasAttributesTypes>(){ -// private static final long serialVersionUID = 1L; -// { -// put(EIDASAttributes.ATTRIBUTE_GIVENNAME, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// put(EIDASAttributes.ATTRIBUTE_FIRSTNAME, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// put(EIDASAttributes.ATTRIBUTE_DATEOFBIRTH, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// put(EIDASAttributes.ATTRIBUTE_PERSONIDENTIFIER, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// -// //TODO: add additional attributes for eIDAS with mandates -// //put(EIDASAttributes.ATTRIBUTE_LEGALIDENTIFIER, EidasAttributesTypes.LEGAL_PERSON_MANDATORY); -// //put(EIDASAttributes.ATTRIBUTE_LEGALNAME, EidasAttributesTypes.LEGAL_PERSON_MANDATORY); -// } -// } -// ); - - public static final AttributeRegistry NAT_ATTR = - AttributeRegistries.of( eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER, - eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_FAMILY_NAME, - eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_GIVEN_NAME, - eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.DATE_OF_BIRTH - ); - - public static final AttributeRegistry LEGAL_ATTR = - AttributeRegistries.of( eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_PERSON_IDENTIFIER, - eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_NAME - ); - - public static final AttributeRegistry MOA_IDP_ATTR_REGISTRY = - AttributeRegistries.copyOf(NAT_ATTR, LEGAL_ATTR); - public static final String METADATA_ALLOWED_ALG_DIGIST = - SignatureConstants.ALGO_ID_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..c872bcfb6 --- /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.trace("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/MOAEidasProtocolProcesser.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java index c24c5efca..8abf29703 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java @@ -22,7 +22,9 @@ */ package at.gv.egovernment.moa.id.auth.modules.eidas.engine; +import eu.eidas.auth.commons.attribute.AttributeRegistry; import eu.eidas.auth.engine.core.eidas.EidasProtocolProcessor; +import eu.eidas.auth.engine.core.eidas.spec.EidasSpec; import eu.eidas.auth.engine.metadata.MetadataFetcherI; import eu.eidas.auth.engine.metadata.MetadataSignerI; @@ -38,11 +40,14 @@ public class MOAEidasProtocolProcesser extends EidasProtocolProcessor { private final MetadataSignerI metadataSigner; /** - * @param metadataFetcher - * @param metadataSigner + * Build a MOA specific eIDAS-engine protocol processor + * + * @param metadataFetcher eIDAS-engine Metadata fetcher implementation + * @param metadataSigner eIDAS-engine Signer implementation + * @param addAttrDefinitions additinal eIDAS attributes */ - public MOAEidasProtocolProcesser(MetadataFetcherI metadataFetcher, MetadataSignerI metadataSigner) { - super(metadataFetcher, metadataSigner); + public MOAEidasProtocolProcesser(MetadataFetcherI metadataFetcher, MetadataSignerI metadataSigner, AttributeRegistry addAttrDefinitions) { + super(EidasSpec.REGISTRY, addAttrDefinitions, metadataFetcher, metadataSigner); this.metadataFetcher = metadataFetcher; this.metadataSigner = metadataSigner; 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..7b159c73d 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 @@ -77,7 +77,6 @@ import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Ordering; -import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import eu.eidas.auth.commons.EIDASUtil; import eu.eidas.auth.commons.EidasStringUtil; @@ -209,16 +208,26 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { if (!StringUtils.isEmpty(params.getAssertionConsumerUrl())) { addAssertionConsumerService(); } - fillNameIDFormat(spSSODescriptor); - if (params.getSpEngine() != null) { - ProtocolEngineI spEngine = params.getSpEngine(); - ((MetadataSignerI) spEngine.getSigner()).signMetadata(spSSODescriptor); - } + + //FIX: Austrian eIDAS node SP only needs persistent identifiers + NameIDFormat persistentFormat = + (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); + persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); + spSSODescriptor.getNameIDFormats().add(persistentFormat); + + /**FIXME: + * Double signing of SPSSODescribtor is not required + */ +// if (params.getSpEngine() != null) { +// ProtocolEngineI spEngine = params.getSpEngine(); +// ((MetadataSignerI) spEngine.getSigner()).signMetadata(spSSODescriptor); +// } + entityDescriptor.getRoleDescriptors().add(spSSODescriptor); } - - private void fillNameIDFormat(SSODescriptor ssoDescriptor) throws EIDASSAMLEngineException { + + private void fillIDPNameIDFormat(SSODescriptor ssoDescriptor) throws EIDASSAMLEngineException { NameIDFormat persistentFormat = (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); @@ -265,7 +274,11 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getEncryptionCredential(), UsageType.ENCRYPTION)); } idpSSODescriptor.addSupportedProtocol(params.getIdpSamlProtocol()); - fillNameIDFormat(idpSSODescriptor); + + //Austrian eIDAS node IDP can provided persistent, transient, and unspecified identifiers + fillIDPNameIDFormat(idpSSODescriptor); + + if (params.getIdpEngine() != null) { if (params.getIdpEngine().getProtocolProcessor() != null && params.getIdpEngine().getProtocolProcessor().getFormat() == SAMLExtensionFormat.EIDAS10) { @@ -277,8 +290,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()); @@ -287,13 +305,18 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { } - /*TODO: Only a work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata + /* FIX: Work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. */ public ImmutableSortedSet<AttributeDefinition<?>> getAllSupportedAttributes() { ImmutableSortedSet.Builder<AttributeDefinition<?>> builder = new ImmutableSortedSet.Builder<>(Ordering.<AttributeDefinition<?>>natural()); - builder.addAll(Constants.MOA_IDP_ATTR_REGISTRY.getAttributes()); + + for (String attr : eIDASAttributeBuilder.getAllProvideableeIDASAttributes()) { + AttributeDefinition<?> supAttr = params.getIdpEngine().getProtocolProcessor().getAttributeDefinitionNullable(attr); + builder.add(supAttr); + } + return builder.build(); } @@ -465,7 +488,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 +553,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 +595,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..edbecc4a0 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java @@ -23,6 +23,8 @@ package at.gv.egovernment.moa.id.auth.modules.eidas.utils; import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashMap; import java.util.Map; @@ -30,14 +32,19 @@ 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; import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASEngineException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.FileUtils; +import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeRegistries; +import eu.eidas.auth.commons.attribute.AttributeRegistry; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.SamlEngineSystemClock; import eu.eidas.auth.engine.metadata.MetadataFetcherI; @@ -62,6 +69,7 @@ public class SAMLEngineUtils { if (eIDASEngine == null) { try { + //get eIDAS SAMLengine configuration from MOA-ID configuration CertificateConfigurationManager configManager = new MOAIDCertificateManagerConfigurationImpl(); @@ -69,13 +77,26 @@ public class SAMLEngineUtils { metadataFetcher = new MOAeIDASMetadataProviderDecorator(moaeIDASMetadataProvider); //set metadata signer - metadataSigner = new MOASWSigner(configManager); + metadataSigner = new MOAExtendedSWSigner(configManager); + + //load additional eIDAS attribute definitions + String additionalAttributeConfigFile = + AuthConfigurationProviderFactory.getInstance().getBasicMOAIDConfiguration( + Constants.CONIG_PROPS_EIDAS_SAMLENGINE_ATTIONAL_ATTRIBUTE_DEFINITIONS); + AttributeRegistry addAttrDefinitions = AttributeRegistries.empty(); + if (MiscUtil.isNotEmpty(additionalAttributeConfigFile)) { + URL addAttrConfigUrl = new URL(FileUtils.makeAbsoluteURL( + additionalAttributeConfigFile, + AuthConfigurationProviderFactory.getInstance().getRootConfigFileDir())); + addAttrDefinitions = AttributeRegistries.fromFile(addAttrConfigUrl.getPath()); + + } //build eIDAS SAML eninge ProtocolEngineI engine = MOAProtocolEngineFactory.createProtocolEngine( Constants.eIDAS_SAML_ENGINE_NAME, configManager, - new MOAEidasProtocolProcesser(metadataFetcher, metadataSigner), + new MOAEidasProtocolProcesser(metadataFetcher, metadataSigner, addAttrDefinitions), new SamlEngineSystemClock()); //build a map with all actually supported attributes @@ -93,6 +114,14 @@ public class SAMLEngineUtils { Logger.error("eIDAS SAMLengine initialization FAILED!", e); throw new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e); + } catch (at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException e) { + Logger.error("eIDAS SAMLengine initialization FAILED!", e); + throw new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e); + + } catch (MalformedURLException e) { + Logger.error("eIDAS SAMLengine initialization FAILED!", e); + throw new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e); + } } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeBuilder.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeBuilder.java new file mode 100644 index 000000000..22b94178e --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeBuilder.java @@ -0,0 +1,174 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.eidas.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceLoader; + +import com.google.common.collect.ImmutableSet; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.Pair; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.IeIDASAttribute; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAttributeBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeDefinition.Builder; +import eu.eidas.auth.commons.attribute.AttributeValue; +import eu.eidas.auth.commons.attribute.AttributeValueMarshaller; +import eu.eidas.auth.commons.attribute.AttributeValueMarshallingException; + +/** + * @author tlenz + * + */ +public class eIDASAttributeBuilder extends PVPAttributeBuilder { + private static IAttributeGenerator<String> generator = new SimpleEidasAttributeGenerator(); + + private static List<String> listOfSupportedeIDASAttributes; + private static ServiceLoader<IeIDASAttribute> eIDASAttributLoader = + ServiceLoader.load(IeIDASAttribute.class); + + static { + List<String> supportAttrList = new ArrayList<String>(); + + Logger.info("Select eIDAS attributes that are corrently providable:"); + if (eIDASAttributLoader != null ) { + Iterator<IeIDASAttribute> moduleLoaderInterator = eIDASAttributLoader.iterator(); + while (moduleLoaderInterator.hasNext()) { + try { + IeIDASAttribute modul = moduleLoaderInterator.next(); + Logger.info("Loading eIDAS attribut-builder Modul Information: " + modul.getName()); + supportAttrList.add(modul.getName()); + + } catch(Throwable e) { + Logger.error("Check configuration! " + "Some attribute-builder modul" + + " is not a valid IAttributeBuilder", e); + } + } + } + + listOfSupportedeIDASAttributes = Collections.unmodifiableList(supportAttrList); + Logger.info("Selection of providable eIDAS attributes done"); + + } + + /** + * Get all eIDAS attribute names that can be generated by the Austrian eIDAS node. + * This list is dynamically generated from loaded eIDAS attribute builders that are found in Java Classpath + * + * @return {@link List} of {@link String} of eIDAS attribute names + */ + public static List<String> getAllProvideableeIDASAttributes() { + return listOfSupportedeIDASAttributes; + } + + /** + * This method build an eIDAS response attribute, by using a loaded eIDAS attribute builder. + * + * @param attr eIDAS attribute that should be generated + * @param onlineApplicationConfiguration SP configuration + * @param authData Authentication data that contains user information for attribute generation + * @return eIDAS attribute response {@link Pair} or null if the attribute generation FAILES + */ + public static Pair<AttributeDefinition<?>,ImmutableSet<AttributeValue<?>>> buildAttribute(AttributeDefinition<?> attr, IOAAuthParameters onlineApplicationConfiguration, + IAuthData authData) { + + String attrName = attr.getNameUri().toString(); + Logger.trace("Build eIDAS attribute: "+ attrName); + + + IAttributeBuilder attrBuilder = getAttributeBuilder(attrName); + if (attrBuilder != null) { + try { + String attrValue = attrBuilder.build(onlineApplicationConfiguration, authData, generator); + if (MiscUtil.isNotEmpty(attrValue)) { + //set uniqueIdentifier attribute, because eIDAS SAMLEngine use this flag to select the + // Subject->NameID value from this attribute + Builder<?> eIDASAttrBuilder = AttributeDefinition.builder(attr); + eIDASAttrBuilder.uniqueIdentifier(evaluateUniqueID(attrName, authData.isUseMandate())); + AttributeDefinition<?> returnAttr = eIDASAttrBuilder.build(); + + //unmarshal attribute value into eIDAS attribute + AttributeValueMarshaller<?> attributeValueMarshaller = returnAttr.getAttributeValueMarshaller(); + ImmutableSet.Builder<AttributeValue<?>> builder = ImmutableSet.builder(); + + AttributeValue<?> attributeValue = null; + try { + attributeValue = attributeValueMarshaller.unmarshal(attrValue, false); + builder.add(attributeValue); + + } catch (AttributeValueMarshallingException e) { + throw new IllegalStateException(e); + + } + + return Pair.newInstance(returnAttr, builder.build()); + + } + + } catch (AttributeException e) { + Logger.debug("Attribute can not generate requested attribute:" + attr.getNameUri().toString() + " Reason:" + e.getMessage()); + + } + + } else + Logger.warn("NO attribute builder FOUND for eIDAS attr: " + attrName); + + return null; + } + + /** + * This method use the information from authenticated session and + * evaluate the uniqueID flag according to eIDAS specification + * + * @param attrName eIDAS attribute name that is evaluated + * @param useMandate flag that indicates if the current authenticated session includes a mandate + * @return true if eIDAS attribute holds the unique ID, otherwise false + */ + private static boolean evaluateUniqueID(String attrName, boolean useMandate) { + //if no mandate is used the natural person identifier is the unique ID + if (!useMandate && + attrName.equals(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER.getNameUri().toString())) + return true; + + //if mandates are used the the legal person identifier or the natural person identifier of the mandator is the unique ID + else if (useMandate && + attrName.equals(eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_PERSON_IDENTIFIER.getNameUri().toString())) + return true; + + //TODO: implement flag selector for mandates and natural persons + + + return false; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/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/EIDASData.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java index 7647b4cab..694efab80 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java @@ -15,6 +15,8 @@ import eu.eidas.auth.commons.protocol.IAuthenticationRequest; @Scope(value = BeanDefinition.SCOPE_PROTOTYPE) public class EIDASData extends RequestImpl { + public static final String REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID = "transiendIDRequested"; + /** The Constant serialVersionUID. */ private static final long serialVersionUID = 8765755670214923910L; @@ -28,7 +30,7 @@ public class EIDASData extends RequestImpl { private String remoteIPAddress; private String remoteRelayState; - + @Override public Collection<String> getRequestedAttributes(MetadataProvider metadataProvider) { // TODO Auto-generated method stub diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java index 13e64cdd0..5d13e26e2 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; @@ -65,6 +67,7 @@ import eu.eidas.auth.commons.protocol.eidas.IEidasAuthenticationRequest; import eu.eidas.auth.commons.protocol.eidas.impl.EidasAuthenticationRequest; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse.Builder; +import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.metadata.MetadataUtil; import eu.eidas.engine.exceptions.EIDASSAMLEngineException; @@ -149,7 +152,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 +217,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 +267,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,15 +303,18 @@ 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, eIDASSamlReq.getEidasLevelOfAssurance().stringValue()); + //set flag if transiend identifier is requested + if (MiscUtil.isNotEmpty(eIDASSamlReq.getNameIdFormat()) + && eIDASSamlReq.getNameIdFormat().equals(SamlNameIdFormat.TRANSIENT.getNameIdFormat())) + pendingReq.setGenericDataToSession(EIDASData.REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID, true); + else + pendingReq.setGenericDataToSession(EIDASData.REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID, false); + // - memorize requested attributes pendingReq.setEidasRequestedAttributes(eIDASSamlReq.getRequestedAttributes()); @@ -288,10 +325,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 +335,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 +400,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 +420,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/attributes/builder/IeIDASAttribute.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/IeIDASAttribute.java new file mode 100644 index 000000000..15060fb52 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/IeIDASAttribute.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder; + +/** + * @author tlenz + * + */ +public interface IeIDASAttribute extends IAttributeBuilder{ + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrDateOfBirth.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrDateOfBirth.java new file mode 100644 index 000000000..64e5ae770 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrDateOfBirth.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.BirthdateAttributeBuilder; + +/** + * @author tlenz + * + */ +public class eIDASAttrDateOfBirth extends BirthdateAttributeBuilder implements IeIDASAttribute { + + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.DATE_OF_BIRTH.getNameUri().toString(); + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrFamilyName.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrFamilyName.java new file mode 100644 index 000000000..4195eeeef --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrFamilyName.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; + +/** + * @author tlenz + * + */ +public class eIDASAttrFamilyName implements IeIDASAttribute{ + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#getName() + */ + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_FAMILY_NAME.getNameUri().toString(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#build(at.gv.egovernment.moa.id.commons.api.IOAAuthParameters, at.gv.egovernment.moa.id.data.IAuthData, at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT build(IOAAuthParameters oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeException { + return g.buildStringAttribute(null, getName(), authData.getFamilyName()); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#buildEmpty(at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return null; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrGivenName.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrGivenName.java new file mode 100644 index 000000000..2a654ac44 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrGivenName.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; + +/** + * @author tlenz + * + */ +public class eIDASAttrGivenName implements IeIDASAttribute{ + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#getName() + */ + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_GIVEN_NAME.getNameUri().toString(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#build(at.gv.egovernment.moa.id.commons.api.IOAAuthParameters, at.gv.egovernment.moa.id.data.IAuthData, at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT build(IOAAuthParameters oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeException { + return g.buildStringAttribute(null, getName(), authData.getGivenName()); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#buildEmpty(at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return null; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalName.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalName.java new file mode 100644 index 000000000..51a2bd69b --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalName.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonFullNameAttributeBuilder; + +/** + * @author tlenz + * + */ +public class eIDASAttrLegalName extends MandateLegalPersonFullNameAttributeBuilder implements IeIDASAttribute { + + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_NAME.getNameUri().toString(); + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalPersonIdentifier.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalPersonIdentifier.java new file mode 100644 index 000000000..c008048cb --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalPersonIdentifier.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonSourcePinAttributeBuilder; + +/** + * @author tlenz + * + */ +public class eIDASAttrLegalPersonIdentifier extends MandateLegalPersonSourcePinAttributeBuilder implements IeIDASAttribute { + + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_PERSON_IDENTIFIER.getNameUri().toString(); + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrNaturalPersonalIdentifier.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrNaturalPersonalIdentifier.java new file mode 100644 index 000000000..cb659c2b1 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrNaturalPersonalIdentifier.java @@ -0,0 +1,116 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import java.security.MessageDigest; + +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils; +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.Trible; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.eidas.EIDASData; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; +import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +public class eIDASAttrNaturalPersonalIdentifier implements IeIDASAttribute{ + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#getName() + */ + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER.getNameUri().toString(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#build(at.gv.egovernment.moa.id.commons.api.IOAAuthParameters, at.gv.egovernment.moa.id.data.IAuthData, at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT build(IOAAuthParameters oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeException { + String personalID = authData.getBPK(); + + //generate eIDAS conform 'PersonalIdentifier' attribute + if (!eIDASAttributeProcessingUtils.validateEidasPersonalIdentifier(personalID)) { + Logger.debug("preCalculated PersonalIdentifier does not include eIDAS conform prefixes ... add prefix now"); + if (MiscUtil.isEmpty(authData.getBPKType()) + || !authData.getBPKType().startsWith(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS)) { + Logger.error("BPKType is empty or does not start with eIDAS bPKType prefix! bPKType:" + authData.getBPKType()); + throw new AttributeException("Suspect bPKType for eIDAS identifier generation"); + + } + + String prefix = authData.getBPKType().substring(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS.length() + 1); + personalID = prefix.replaceAll("\\+", "/") + "/" + personalID; + + } + + //generate a transient unique identifier if it is requested + Boolean isTransiendIDRequested = + authData.getGenericData(EIDASData.REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID, Boolean.class); + if (isTransiendIDRequested != null && isTransiendIDRequested) + personalID = generateTransientNameID(personalID); + + return g.buildStringAttribute(null, getName(), personalID); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#buildEmpty(at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return null; + } + + private String generateTransientNameID(String nameID) { + //extract source-country and destination country from persistent identifier + Trible<String, String, String> split = eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier(nameID); + if (split == null) { + Logger.error("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); + throw new IllegalStateException("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); + + } + + //build correct formated transient identifier + String random = Random.nextLongRandom(); + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] hash = md.digest((split.getThird() + random).getBytes("ISO-8859-1")); + return split.getFirst() + "/" + split.getSecond() + "/" + Base64Utils.encode(hash); + + } catch (Exception e) { + Logger.error("Can not generate transient personal identifier!", e); + return null; + + } + + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java index 22ac37604..d0cda38c7 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java @@ -23,8 +23,6 @@ package at.gv.egovernment.moa.id.protocols.eidas; import java.io.StringWriter; -import java.security.MessageDigest; -import java.text.SimpleDateFormat; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -34,7 +32,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,30 +41,23 @@ import at.gv.egovernment.moa.id.auth.frontend.velocity.VelocityProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SimpleEidasAttributeGenerator; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeBuilder; +import at.gv.egovernment.moa.id.commons.MOAIDConstants; import at.gv.egovernment.moa.id.commons.api.IRequest; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.Pair; import at.gv.egovernment.moa.id.data.SLOInformationImpl; import at.gv.egovernment.moa.id.data.SLOInformationInterface; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; -import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonFullNameAttributeBuilder; -import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonSourcePinAttributeBuilder; -import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; -import at.gv.egovernment.moa.id.util.Random; import at.gv.egovernment.moa.logging.Logger; -import at.gv.egovernment.moa.util.Base64Utils; -import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.commons.EidasStringUtil; import eu.eidas.auth.commons.attribute.AttributeDefinition; -import eu.eidas.auth.commons.attribute.AttributeDefinition.Builder; import eu.eidas.auth.commons.attribute.AttributeValue; -import eu.eidas.auth.commons.attribute.AttributeValueMarshaller; -import eu.eidas.auth.commons.attribute.AttributeValueMarshallingException; import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; import eu.eidas.auth.commons.protocol.IResponseMessage; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; -import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.xml.opensaml.SAMLEngineUtils; @@ -95,82 +85,31 @@ public class eIDASAuthenticationRequest implements IAction { else throw new MOAIDException("got wrong IRequest type. is: {}, should be: {}", new String[] {req.getClass().toString(), EIDASData.class.toString()}); - + String subjectNameID = null; - + //gather attributes ImmutableAttributeMap reqAttributeList = (ImmutableAttributeMap) eidasRequest.getEidasRequestedAttributes(); ImmutableAttributeMap.Builder attrMapBuilder = ImmutableAttributeMap.builder(); - - //TODO: if we support more then this minimum required attributes -> redesign to a smoother attribute builder selector + + //generate eIDAS attributes for(AttributeDefinition<?> attr : reqAttributeList.getDefinitions()) { - String newValue = ""; - boolean isUniqueID = false; - try { - switch(attr.getFriendlyName()) { - case Constants.eIDAS_ATTR_DATEOFBIRTH: - newValue = new SimpleDateFormat("YYYY-MM-dd").format(authData.getDateOfBirth()); - break; - case Constants.eIDAS_ATTR_CURRENTFAMILYNAME: - newValue = authData.getFamilyName(); - break; - case Constants.eIDAS_ATTR_CURRENTGIVENNAME: - newValue = authData.getGivenName(); - break; - case Constants.eIDAS_ATTR_PERSONALIDENTIFIER: - newValue = authData.getBPK(); - isUniqueID = true; + Pair<AttributeDefinition<?>, ImmutableSet<AttributeValue<?>>> eIDASAttr = eIDASAttributeBuilder.buildAttribute( + attr, req.getOnlineApplicationConfiguration(), authData); - //generate a transient unique identifier if it is requested - String reqNameIDFormat = eidasRequest.getEidasRequest().getNameIdFormat(); - if (MiscUtil.isNotEmpty(reqNameIDFormat) - && reqNameIDFormat.equals(SamlNameIdFormat.TRANSIENT.getNameIdFormat())) - newValue = generateTransientNameID(newValue); - - subjectNameID = newValue; - break; - case Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER: - newValue = new MandateLegalPersonSourcePinAttributeBuilder().build( - req.getOnlineApplicationConfiguration(), authData, generator); - break; - case Constants.eIDAS_ATTR_LEGALNAME: - newValue = new MandateLegalPersonFullNameAttributeBuilder().build( - req.getOnlineApplicationConfiguration(), authData, generator); - break; - - } - - } catch (AttributeException e) { - Logger.debug("Attribute can not generate requested attribute:" + attr.getFriendlyName() + " Reason:" + e.getMessage()); - - } - - if(MiscUtil.isEmpty(newValue)) { - Logger.info("eIDAS Attr:" + attr.getNameUri() + " is not available."); + if(eIDASAttr == null) { + if (attr.isRequired()) { + Logger.info("eIDAS Attr:" + attr.getNameUri() + " is marked as 'Required' but not available."); + throw new MOAIDException("eIDAS.15", new Object[]{attr.getFriendlyName()}); + + } else + Logger.info("eIDAS Attr:" + attr.getNameUri() + " is not available."); } else { - //set uniqueIdentifier attribute, because eIDAS SAMLEngine use this flag to select the - // Subject->NameID value from this attribute - Builder<?> attrBuilder = AttributeDefinition.builder(attr); - attrBuilder.uniqueIdentifier(isUniqueID); - AttributeDefinition<?> returnAttr = attrBuilder.build(); - - //unmarshal attribute value into eIDAS attribute - AttributeValueMarshaller<?> attributeValueMarshaller = returnAttr.getAttributeValueMarshaller(); - ImmutableSet.Builder<AttributeValue<?>> builder = ImmutableSet.builder(); - - AttributeValue<?> attributeValue = null; - try { - attributeValue = attributeValueMarshaller.unmarshal(newValue, false); - builder.add(attributeValue); - - } catch (AttributeValueMarshallingException e) { - throw new IllegalStateException(e); - - } - - //add attribute to Map - attrMapBuilder.put((AttributeDefinition)returnAttr, (ImmutableSet) builder.build()); + //add attribute to Map + attrMapBuilder.put( + (AttributeDefinition)eIDASAttr.getFirst(), + (ImmutableSet)eIDASAttr.getSecond()); } } @@ -207,19 +146,7 @@ public class eIDASAuthenticationRequest implements IAction { eIDASRespMsg = engine.generateResponseMessage(eidasRequest.getEidasRequest(), response, true, eidasRequest.getRemoteAddress()); - -// if(null == eidasRequest.getEidasRequest().getAssertionConsumerServiceURL()) { -// String assertionConsumerUrl = MetadataUtil.getAssertionUrlFromMetadata( -// new MOAeIDASMetadataProviderDecorator(eIDASMetadataProvider), -// engine, -// eidasRequest.getEidasRequest()); -// eidasRequest.getEidasRequest().setAssertionConsumerServiceURL(assertionConsumerUrl); -// -// } - -// response = engine.generateEIDASAuthnResponse(eidasRequest.getEidasRequest(), response, eidasRequest.getRemoteAddress(), true); - - + token = EidasStringUtil.encodeToBase64(eIDASRespMsg.getMessageBytes()); } catch(Exception e) { @@ -228,12 +155,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 +181,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); @@ -294,20 +222,6 @@ public class eIDASAuthenticationRequest implements IAction { } - private String generateTransientNameID(String nameID) { - 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); - - } catch (Exception e) { - Logger.error("Can not generate transient personal identifier!", e); - return null; - - } - - } + } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/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/META-INF/services/at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder b/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder new file mode 100644 index 000000000..62e7c20ab --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder @@ -0,0 +1,6 @@ +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrDateOfBirth +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrFamilyName +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrGivenName +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrNaturalPersonalIdentifier +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrLegalPersonIdentifier +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrLegalName diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.IeIDASAttribute b/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.IeIDASAttribute new file mode 100644 index 000000000..62e7c20ab --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.IeIDASAttribute @@ -0,0 +1,6 @@ +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrDateOfBirth +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrFamilyName +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrGivenName +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrNaturalPersonalIdentifier +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrLegalPersonIdentifier +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrLegalName 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"/> |