diff options
Diffstat (limited to 'id/server')
11 files changed, 367 insertions, 81 deletions
diff --git a/id/server/doc/handbook/protocol/protocol.html b/id/server/doc/handbook/protocol/protocol.html index 5a578a5aa..7d3f8d627 100644 --- a/id/server/doc/handbook/protocol/protocol.html +++ b/id/server/doc/handbook/protocol/protocol.html @@ -1295,8 +1295,8 @@ https://<host>:<port>/moa-id-auth/pvp2/metadata <p>Dieser Abschnitt beschreibt die einzelnen OpenID Connect spezifischen Nachrichten, welche zwischen der Online-Applikation und dem Modul MOA-ID-Auth während eines Authentifizierungsvorgangs ausgetauscht werden. Hierbei wird auch auf das Sequenzdiagramm aus <a href="#openid_sequenzdiagramm">Abschnitt 3.1</a> Bezug genommen.</p> <h4><a name="openid_req_authnreq"></a>3.2.1 AuthCode Request</h4> -<p>Der AuthCode Request ist die Authentifizierungsanfrage einer Online-Applikation für eine Benutzerin oder einen Benutzer. -Folgende Parameter müssen mit dem AuthCode-Request mitgesendet werden, wobei für die Ãœbertragung der Parameter sowohl http GET als auch http POST verwendet werden kann.</p> +<p>Der AuthCode Request ist die Authentifizierungsanfrage einer Online-Applikation für eine Benutzerin oder einen Benutzer. +Folgende Parameter müssen mit dem AuthCode-Request mitgesendet werden, wobei für die Übertragung der Parameter sowohl http GET als auch http POST verwendet werden kann.</p> <table class="configtable"> <tr> <th>Name</th> @@ -1498,6 +1498,12 @@ Folgende Parameter müssen mit dem AuthCode-Request mitgesendet werden, wobei fà <td>https://demo.egiz.gv.at/demoportal_moaid-2.0/moa_errorcodes.html#1000</td> <td>URL auf eine Seite mit zusätzlicher Fehlerbeschreibung</td> </tr> + <tr> + <td>state</td> + <td>1425782214234</td> + <td><p>Der von der Online-Applikation generierte und im AuthCode Request übergebene CSRF Token.</p> + <p><strong>Hinweis:</strong> Dieser Parameter wird nur dann returniert wenn dieser auch im vorrangegangenen Request (z.B. AuthCode Request) angegeben wurde.</p></td> + </tr> </table> <p> </p> <h2><a name="saml1"></a>3 SAML 1</h2> 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 77cc7228b..df4866c30 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 @@ -41,7 +41,7 @@ import at.gv.egovernment.moa.util.MiscUtil; public abstract class AbstractCredentialProvider { - private static KeyStore keyStore = null; + private KeyStore keyStore = null; /** * Get a friendlyName for this keyStore implementation diff --git a/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/velocity/VelocityProvider.java b/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/velocity/VelocityProvider.java index 022c144f0..21fe110ca 100644 --- a/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/velocity/VelocityProvider.java +++ b/id/server/moa-id-frontend-resources/src/main/java/at/gv/egovernment/moa/id/auth/frontend/velocity/VelocityProvider.java @@ -50,6 +50,7 @@ */
package at.gv.egovernment.moa.id.auth.frontend.velocity;
+import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
@@ -104,8 +105,9 @@ public class VelocityProvider { VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.setProperty(RuntimeConstants.INPUT_ENCODING, "UTF-8");
velocityEngine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
- velocityEngine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
- "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
+// velocityEngine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+// "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
+ velocityEngine.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, new VelocityLogAdapter() );
return velocityEngine;
}
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 f45b6ffa5..02c9a8f5d 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 @@ -45,7 +45,7 @@ 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 = "eu.eidas.auth.engine.core.impl.SignSW"; + public static final String SAML_SIGNING_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.MOASWSigner"; public static final String SAML_ENCRYPTION_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.ModifiedEncryptionSW"; //configuration property keys diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java index 302c12aaa..5cf5e83ec 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java @@ -22,12 +22,22 @@ */ package at.gv.egovernment.moa.id.auth.modules.eidas.config; +import java.util.Locale; import java.util.Map; +import org.apache.commons.lang.StringUtils; +import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.xml.signature.SignatureConstants; + +import com.google.common.collect.ImmutableSet; + 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.moaspss.logging.Logger; 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.core.impl.KeyStoreProtocolSigner; import eu.eidas.samlengineconfig.CertificateConfigurationManager; @@ -37,20 +47,71 @@ import eu.eidas.samlengineconfig.CertificateConfigurationManager; */ public class MOASWSigner extends KeyStoreProtocolSigner { + private static Map<String, String> props; + private ImmutableSet<String> sigAlgWhiteList = null; + + private static final ImmutableSet<String> ALLOWED_ALGORITHMS_FOR_VERIFYING = + ImmutableSet.of(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA384, + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512, + // RIPEMD is allowed to verify + SignatureConstants.ALGO_ID_SIGNATURE_RSA_RIPEMD160, + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256, + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA384, + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA512, + + //Set other algorithms which are not supported by openSAML in default + StringUtils.lowerCase(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1_MGF1, Locale.ENGLISH), + StringUtils.lowerCase(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA224_MGF1, Locale.ENGLISH), + StringUtils.lowerCase(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, Locale.ENGLISH), + StringUtils.lowerCase(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384_MGF1, Locale.ENGLISH), + StringUtils.lowerCase(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1, Locale.ENGLISH)); + + private static final ImmutableSet<String> DEFAULT_ALGORITHM_WHITE_LIST = + ImmutableSet.of(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA384, + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512, + // RIPEMD is not allowed to sign + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256, + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA384, + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA512, + + //Set other algorithms which are not supported by openSAML in default + StringUtils.lowerCase(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, Locale.ENGLISH)); + public MOASWSigner(Map<String, String> properties) throws SamlEngineConfigurationException { super(properties); - + props = properties; + } /** * @param configManager * @throws SamlEngineConfigurationException */ - public MOASWSigner(CertificateConfigurationManager configManager) throws SamlEngineConfigurationException { - super(ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters()); + public MOASWSigner(CertificateConfigurationManager configManager) throws SamlEngineConfigurationException { + super(props = ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters()); } + @Override + protected ImmutableSet<String> getSignatureAlgorithmWhiteList() { + try { + if (sigAlgWhiteList == null) { + sigAlgWhiteList = MOAWhiteListConfigurator.getAllowedAlgorithms(DEFAULT_ALGORITHM_WHITE_LIST, + ALLOWED_ALGORITHMS_FOR_VERIFYING, + (new KeyStoreSignatureConfigurator().getSignatureConfiguration(props)).getSignatureAlgorithmWhiteList()); + + } + + return sigAlgWhiteList; + + } catch (SamlEngineConfigurationException e) { + Logger.warn("Can not parse eIDAS signing configuration." , e); + return DEFAULT_ALGORITHM_WHITE_LIST; + + } + } } 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 3522a16fd..a9c4d5d3a 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,10 +22,13 @@ */ 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; @@ -39,6 +42,7 @@ 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; @@ -55,10 +59,12 @@ import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASEngineExcepti import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils; import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.commons.api.IRequest; import at.gv.egovernment.moa.id.commons.api.data.CPEPS; import at.gv.egovernment.moa.id.commons.api.data.StorkAttribute; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.commons.EidasStringUtil; @@ -111,15 +117,15 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { // select SingleSignOnService Endpoint from eIDAS-node metadata - String destination = null; + SingleSignOnService authnReqEndpoint = null; String metadataUrl = cpeps.getPepsURL().toString().split(";")[0].trim(); try { EntityDescriptor eIDASNodeMetadata = eIDASMetadataProvider.getEntityDescriptor(metadataUrl); if (eIDASNodeMetadata != null) { SingleSignOnService ssoDescr = selectSingleSignOnServiceFromMetadata(eIDASNodeMetadata); if (ssoDescr != null) { - destination = ssoDescr.getLocation(); - Logger.debug("Use destination URL:" + destination + " from eIDAS metadata:" + metadataUrl); + authnReqEndpoint = ssoDescr; + Logger.debug("Use destination URL:" + authnReqEndpoint.getLocation() + " from eIDAS metadata:" + metadataUrl); } else Logger.warn("eIDAS metadata for node:" + metadataUrl + " has no IDPSSODescriptor or no SingleSignOnService information."); @@ -134,13 +140,21 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { // load SingleSignOnService Endpoint from configuration, if Metadata contains no information // FIXME convenience function for not standard conform metadata - if (MiscUtil.isEmpty(destination)) { + if (authnReqEndpoint == null) { + String destination = null; String[] splitString = cpeps.getPepsURL().toString().split(";"); if (splitString.length > 1) destination = cpeps.getPepsURL().toString().split(";")[1].trim(); - if (MiscUtil.isNotEmpty(destination)) + if (MiscUtil.isNotEmpty(destination)) { Logger.debug("Use eIDAS node destination URL:" + destination + " from configuration"); + + //set POST binding as default binding, if Authn. request endpoint from config is used + authnReqEndpoint = SAML2Utils.createSAMLObject(SingleSignOnService.class); + authnReqEndpoint.setLocation(destination); + authnReqEndpoint.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + + } else { Logger.error("No eIDAS-node destination URL FOUND. Request eIDAS node not possible."); @@ -193,7 +207,7 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { authnRequestBuilder.providerName(pendingReq.getAuthURL()); String issur = pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_METADATA; authnRequestBuilder.issuer(issur); - authnRequestBuilder.destination(destination); + authnRequestBuilder.destination(authnReqEndpoint.getLocation()); authnRequestBuilder.nameIdFormat(Constants.eIDAS_REQ_NAMEID_FORMAT); @@ -226,45 +240,21 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { String SAMLRequest = EidasStringUtil.encodeToBase64(token); - //send - try { - VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); - Template template = velocityEngine.getTemplate("/resources/templates/eidas_postbinding_template.vm"); - VelocityContext context = new VelocityContext(); - - String actionType = "SAMLRequest"; - context.put(actionType, SAMLRequest); - Logger.debug("Encoded " + actionType + " original: " + SAMLRequest); - - context.put("RelayState", pendingReq.getRequestID()); - - Logger.debug("Using assertion consumer url as action: " + destination); - context.put("action", destination); - - Logger.debug("Starting template merge"); - StringWriter writer = new StringWriter(); - - Logger.debug("Doing template merge"); - template.merge(context, writer); - Logger.debug("Template merge done"); - - Logger.debug("Sending html content: " + writer.getBuffer().toString()); - - - byte[] content = writer.getBuffer().toString().getBytes("UTF-8"); - response.setContentType(MediaType.HTML_UTF_8.toString()); - response.setContentLength(content.length); - response.getOutputStream().write(content); + if (SAMLConstants.SAML2_POST_BINDING_URI.equals(authnReqEndpoint.getBinding())) + buildPostBindingRequest(pendingReq, authnReqEndpoint, SAMLRequest, authnRequest, response); + + //TODO: redirect Binding is not completely implemented + //else if (SAMLConstants.SAML2_REDIRECT_BINDING_URI.equals(authnReqEndpoint.getBinding())) + //buildRedirecttBindingRequest(pendingReq, authnReqEndpoint, token, authnRequest, response); + + else { + Logger.error("eIDAS-node use an unsupported binding (" + + authnReqEndpoint.getBinding() + "). Request eIDAS node not possible."); + throw new MOAIDException("eIDAS.02", new Object[]{"eIDAS-node use an unsupported binding"}); + + } + - revisionsLogger.logEvent(oaConfig, pendingReq, - MOAIDEventConstants.AUTHPROCESS_PEPS_REQUESTED, - authnRequest.getRequest().getId()); - - } catch (Exception e) { - Logger.error("Velocity general error: " + e.getMessage()); - throw new MOAIDException("eIDAS.02", new Object[]{e.getMessage()}, e); - - } }catch (EIDASSAMLEngineException e){ throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.", @@ -280,6 +270,102 @@ 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 + * + * @param pendingReq + * @param authnReqEndpoint + * @param SAMLRequest + * @param authnRequest + * @param response + * @throws MOAIDException + */ + private void buildPostBindingRequest(IRequest pendingReq, SingleSignOnService authnReqEndpoint, + String SAMLRequest, IRequestMessage authnRequest, HttpServletResponse response) + throws MOAIDException { + //send + try { + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/eidas_postbinding_template.vm"); + VelocityContext context = new VelocityContext(); + + String actionType = "SAMLRequest"; + context.put(actionType, SAMLRequest); + Logger.debug("Encoded " + actionType + " original: " + SAMLRequest); + + context.put("RelayState", pendingReq.getRequestID()); + + Logger.debug("Using assertion consumer url as action: " + authnReqEndpoint.getLocation()); + context.put("action", authnReqEndpoint.getLocation()); + + Logger.debug("Starting template merge"); + StringWriter writer = new StringWriter(); + + Logger.debug("Doing template merge"); + template.merge(context, writer); + Logger.debug("Template merge done"); + + Logger.debug("Sending html content: " + writer.getBuffer().toString()); + + + byte[] content = writer.getBuffer().toString().getBytes("UTF-8"); + response.setContentType(MediaType.HTML_UTF_8.toString()); + response.setContentLength(content.length); + response.getOutputStream().write(content); + + revisionsLogger.logEvent(pendingReq.getOnlineApplicationConfiguration(), pendingReq, + MOAIDEventConstants.AUTHPROCESS_PEPS_REQUESTED, + authnRequest.getRequest().getId()); + + } catch (Exception e) { + Logger.error("Velocity general error: " + e.getMessage()); + throw new MOAIDException("eIDAS.02", new Object[]{e.getMessage()}, e); + + } + + } + + /** + * Select a SingleSignOnService endPoint from eIDAS node metadata. + * This endPoint receives the Authn. request + * + * @param idpEntity + * @return + */ private SingleSignOnService selectSingleSignOnServiceFromMetadata(EntityDescriptor idpEntity) { //select SingleSignOn Service endpoint from IDP metadata SingleSignOnService endpoint = null; @@ -294,7 +380,9 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { // use POST binding as default if it exists if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) endpoint = sss; - + + //TODO: redirect Binding is not completely implemented + // use Redirect binding as backup // else if ( sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) // && endpoint == null ) // endpoint = sss; 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 new file mode 100644 index 000000000..7d647ff15 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java @@ -0,0 +1,96 @@ +/* + * 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.Locale; +import java.util.regex.Pattern; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; + +import com.google.common.collect.ImmutableSet; + +import at.gv.egovernment.moa.id.commons.utils.KeyValueUtils; + +/** + * @author tlenz + * + */ +public class MOAWhiteListConfigurator { + private static final Pattern WHITE_LIST_SPLITTER = Pattern.compile("[;,]"); + + + public static ImmutableSet<String> getAllowedAlgorithms( ImmutableSet<String> defaultWhiteList, + ImmutableSet<String> allowedValues, + String algorithmWhiteListValue) { + if (StringUtils.isBlank(algorithmWhiteListValue)) { + return defaultWhiteList; + } + ImmutableSet.Builder<String> allowed = ImmutableSet.builder(); + String[] wlAlgorithms = WHITE_LIST_SPLITTER.split(algorithmWhiteListValue); + if (null != wlAlgorithms && wlAlgorithms.length > 0) { + return getAllowedAlgorithms(defaultWhiteList, allowedValues, ImmutableSet.<String>copyOf(wlAlgorithms)); + } + return defaultWhiteList; + } + + + public static ImmutableSet<String> getAllowedAlgorithms( ImmutableSet<String> defaultWhiteList, + ImmutableSet<String> allowedValues, + ImmutableSet<String> candidateValues) { + if (CollectionUtils.isEmpty(candidateValues)) { + return defaultWhiteList; + } + ImmutableSet.Builder<String> allowed = ImmutableSet.builder(); + boolean modified = false; + for (String candidateValue : candidateValues) { + + /**FIX: + * fix problem with lowerCase and MGF1 signature algorithms + * + */ + candidateValue = StringUtils.trimToNull( + KeyValueUtils.removeAllNewlineFromString(candidateValue)); + if (StringUtils.isNotBlank(candidateValue)) { + String candidateAlgorithm = StringUtils.lowerCase(candidateValue, Locale.ENGLISH); + if (allowedValues.contains(candidateAlgorithm)) { + allowed.add(candidateValue); + if (!modified && !candidateAlgorithm.equals(candidateValue)) { + modified = true; + } + } else { + modified = true; + } + } + } + if (!modified) { + return candidateValues; + } + ImmutableSet<String> set = allowed.build(); + if (set.isEmpty()) { + return defaultWhiteList; + } + return set; + } + +} 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 09c3dff38..dd14972e3 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 @@ -35,6 +35,7 @@ import org.joda.time.DurationFieldType; import org.opensaml.Configuration; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.common.Extensions; +import org.opensaml.saml2.common.impl.ExtensionsBuilder; import org.opensaml.saml2.core.Attribute; import org.opensaml.saml2.core.AttributeValue; import org.opensaml.saml2.metadata.AssertionConsumerService; @@ -52,6 +53,7 @@ import org.opensaml.saml2.metadata.LocalizedString; import org.opensaml.saml2.metadata.NameIDFormat; import org.opensaml.saml2.metadata.Organization; import org.opensaml.saml2.metadata.OrganizationDisplayName; +import org.opensaml.saml2.metadata.OrganizationName; import org.opensaml.saml2.metadata.OrganizationURL; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml2.metadata.SSODescriptor; @@ -76,6 +78,7 @@ import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Ordering; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import eu.eidas.auth.commons.EIDASUtil; import eu.eidas.auth.commons.EidasStringUtil; import eu.eidas.auth.commons.attribute.AttributeDefinition; @@ -126,8 +129,17 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { entityDescriptor.setEntityID(params.getEntityID()); entityDescriptor.setOrganization(buildOrganization()); - entityDescriptor.getContactPersons().add(buildContact(ContactPersonTypeEnumeration.SUPPORT)); - entityDescriptor.getContactPersons().add(buildContact(ContactPersonTypeEnumeration.TECHNICAL)); + + /**FIXME: + * HOTFIX: do not add empty contactPerson elements + */ + ContactPerson contactSupport = buildContact(ContactPersonTypeEnumeration.SUPPORT); + if (contactSupport != null) + entityDescriptor.getContactPersons().add(contactSupport); + ContactPerson contactTech = buildContact(ContactPersonTypeEnumeration.TECHNICAL); + if (contactTech != null) + entityDescriptor.getContactPersons().add(contactTech); + entityDescriptor.setValidUntil(getExpireDate()); X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory(); @@ -164,8 +176,15 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { //the node has SP role spSSODescriptor.setWantAssertionsSigned(params.isWantAssertionsSigned()); spSSODescriptor.setAuthnRequestsSigned(true); - spSSODescriptor.setID(idpSSODescriptor == null ? params.getEntityID() - : ("SP" + params.getEntityID())); + + + /**FIXME: + * "SP" + params.getEntityID()) is not a valid XML ID attribute value + */ + //spSSODescriptor.setID(idpSSODescriptor == null ? params.getEntityID() : ("SP" + params.getEntityID())); + spSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); + + if (params.getSPSignature() != null) { spSSODescriptor.setSignature(params.getSPSignature()); } @@ -220,8 +239,13 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { SAMLEngineException, EIDASSAMLEngineException { //the node has IDP role idpSSODescriptor.setWantAuthnRequestsSigned(true); - idpSSODescriptor.setID(spSSODescriptor == null ? params.getEntityID() - : ("IDP" + params.getEntityID())); + + /**FIXME: + * "IDP" + params.getEntityID()) is not a valid XML ID attribute value + */ + //idpSSODescriptor.setID(spSSODescriptor == null ? params.getEntityID() : ("IDP" + params.getEntityID())); + idpSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); + if (params.getIDPSignature() != null) { idpSSODescriptor.setSignature(params.getIDPSignature()); } @@ -341,8 +365,16 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { private Organization buildOrganization() { Organization organization = null; - try { + try { organization = BuilderFactoryUtil.buildXmlObject(Organization.class); + + /**FIXME: + * set correct OrganizationName value if it is not fixed in next eIDAS node version + */ + OrganizationName orgName = BuilderFactoryUtil.buildXmlObject(OrganizationName.class); + orgName.setName(new LocalizedString(params.getNodeUrl(), "en")); + organization.getOrganizationNames().add(orgName); + OrganizationDisplayName odn = BuilderFactoryUtil.buildXmlObject(OrganizationDisplayName.class); odn.setName(new LocalizedString(params.getCountryName(), "en")); organization.getDisplayNames().add(odn); @@ -373,7 +405,7 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { contact = BuilderFactoryUtil.buildXmlObject(ContactPerson.class); if (currentContact == null) { LOGGER.error("ERROR: cannot retrieve contact from the configuration"); - return contact; + return null; } EmailAddress emailAddressObj = BuilderFactoryUtil.buildXmlObject(EmailAddress.class); @@ -514,7 +546,14 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator { } private Extensions generateExtensions() throws EIDASSAMLEngineException { - Extensions eidasExtensions = BuilderFactoryUtil.generateExtension(); + /**FIXME: BuilderFactoryUtil.generateExtension() generates extensions from SAML2 request namespace + * but SAML2 metadata namespace is required + **/ + //Extensions eidasExtensions = BuilderFactoryUtil.generateExtension(); + + ExtensionsBuilder extensionsBuilder = new ExtensionsBuilder(); + Extensions eidasExtensions = extensionsBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:metadata", "Extensions", "md"); + if (params.getAssuranceLevel() != null) { generateLoA(eidasExtensions); } diff --git a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/ELGAMandatesAuthModuleImpl.java b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/ELGAMandatesAuthModuleImpl.java index c2efe5bfc..f14ffb111 100644 --- a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/ELGAMandatesAuthModuleImpl.java +++ b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/ELGAMandatesAuthModuleImpl.java @@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired; import at.gv.egovernment.moa.id.auth.modules.internal.DefaultCitizenCardAuthModuleImpl; import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; +import at.gv.egovernment.moa.id.commons.config.MOAIDConfigurationConstants; import at.gv.egovernment.moa.id.process.api.ExecutionContext; import at.gv.egovernment.moa.util.MiscUtil; @@ -56,8 +57,9 @@ public class ELGAMandatesAuthModuleImpl extends DefaultCitizenCardAuthModuleImpl //check if BKU authentication is selected and ELGA-MandateService is configurated if (MiscUtil.isNotEmpty(selectedProcessID)) { - if (MiscUtil.isNotEmpty(authConfig.getBasicMOAIDConfiguration( - ELGAMandatesAuthConstants.CONFIG_PROPS_ENTITYID))) + if (MiscUtil.isNotEmpty(authConfig.getConfigurationWithKey( + MOAIDConfigurationConstants.PREFIX_MOAID_GENERAL + "." + + ELGAMandatesAuthConstants.CONFIG_PROPS_ENTITYID))) return "DefaultAuthenticationWithELGAMandates"; } diff --git a/id/server/modules/moa-id-module-openID/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/protocol/OAuth20Protocol.java b/id/server/modules/moa-id-module-openID/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/protocol/OAuth20Protocol.java index 118c53f6b..75ea41449 100644 --- a/id/server/modules/moa-id-module-openID/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/protocol/OAuth20Protocol.java +++ b/id/server/modules/moa-id-module-openID/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/protocol/OAuth20Protocol.java @@ -204,9 +204,11 @@ public class OAuth20Protocol extends AbstractAuthProtocolModulController { OAuth20Util.addParameterToURL(url, OAuth20Constants.PARAM_ERROR, errorCode); OAuth20Util.addParameterToURL(url, OAuth20Constants.PARAM_ERROR_DESCRIPTION, errorDescription); - if (MiscUtil.isNotEmpty(moaError)) - OAuth20Util.addParameterToURL(url, OAuth20Constants.PARAM_ERROR_URI, errorUri + "#" + moaError); OAuth20Util.addParameterToURL(url, OAuth20Constants.PARAM_STATE, state); + if (MiscUtil.isNotEmpty(moaError)) + OAuth20Util.addParameterToURL(url, OAuth20Constants.PARAM_ERROR_URI, + URLEncoder.encode(errorUri + "#" + moaError, "UTF-8")); + response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_FOUND); @@ -220,7 +222,8 @@ public class OAuth20Protocol extends AbstractAuthProtocolModulController { Map<String, Object> params = new HashMap<String, Object>(); params.put(OAuth20Constants.PARAM_ERROR, errorCode); params.put(OAuth20Constants.PARAM_ERROR_DESCRIPTION, errorDescription); - params.put(OAuth20Constants.PARAM_ERROR_URI, errorUri + "#" + moaError); + params.put(OAuth20Constants.PARAM_ERROR_URI, + URLEncoder.encode(errorUri + "#" + moaError, "UTF-8")); // create response JsonObject jsonObject = new JsonObject(); diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/RestoreSSOSessionTask.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/RestoreSSOSessionTask.java index cf4590fc1..1a216f0df 100644 --- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/RestoreSSOSessionTask.java +++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/RestoreSSOSessionTask.java @@ -184,20 +184,9 @@ public class RestoreSSOSessionTask extends AbstractAuthServletTask { //TODO: implement Signature validation Logger.debug("MobileDevice is valid. --> Starting session reconstruction ..."); - - - //session is valid --> load MOASession object - try { - defaultTaskInitialization(request, executionContext); - - } catch (MOAIDException | MOADatabaseException e1) { - Logger.error("Database Error! MOASession is not stored!"); - throw new TaskExecutionException(pendingReq, "Load MOASession FAILED.", e1); - - } - + //transfer SSO Assertion into MOA-Session - ssoTransferUtils.parseSSOContainerToMOASessionDataObject(pendingReq, moasession, attributeExtractor); + ssoTransferUtils.parseSSOContainerToMOASessionDataObject(pendingReq, pendingReq.getMOASession(), attributeExtractor); // store MOASession into database requestStoreage.storePendingRequest(pendingReq); |