diff options
86 files changed, 4753 insertions, 1231 deletions
diff --git a/eaaf_core_api/pom.xml b/eaaf_core_api/pom.xml index c16bf39c..d26e3483 100644 --- a/eaaf_core_api/pom.xml +++ b/eaaf_core_api/pom.xml @@ -41,6 +41,10 @@ <artifactId>slf4j-api</artifactId> </dependency> <dependency> + <groupId>javax.annotation</groupId> + <artifactId>javax.annotation-api</artifactId> + </dependency> + <dependency> <groupId>com.google.code.findbugs</groupId> <artifactId>jsr305</artifactId> </dependency> diff --git a/eaaf_modules/eaaf_module_pvp2_core/pom.xml b/eaaf_modules/eaaf_module_pvp2_core/pom.xml index 62973ac5..ef56624b 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/pom.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/pom.xml @@ -71,6 +71,11 @@ <scope>test</scope> <type>test-jar</type> </dependency> + <dependency> + <groupId>com.squareup.okhttp3</groupId> + <artifactId>mockwebserver</artifactId> + <scope>test</scope> + </dependency> </dependencies> @@ -86,15 +91,34 @@ <source>1.8</source> <target>1.8</target> </configuration> + <executions> + <execution> + <goals> + <goal>compile</goal> + <goal>testCompile</goal> + </goals> + </execution> + </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>3.1.0</version> + <executions> + <execution> + <goals> + <goal>test-jar</goal> + </goals> + </execution> + </executions> + </plugin> - <!-- enable co-existence of testng and junit --> + <!-- enable co-existence of testng and junit --> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>${surefire.version}</version> <configuration> - <threadCount>1</threadCount> - <argLine>--add-modules java.xml.bind</argLine> + <threadCount>1</threadCount> </configuration> <dependencies> <dependency> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/Pvp2SProfileCoreSpringResourceProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/Pvp2SProfileCoreSpringResourceProvider.java index 2779ee1d..232e4ae9 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/Pvp2SProfileCoreSpringResourceProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/Pvp2SProfileCoreSpringResourceProvider.java @@ -19,11 +19,11 @@ package at.gv.egiz.eaaf.modules.pvp2; +import at.gv.egiz.components.spring.api.SpringResourceProvider; + import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; -import at.gv.egiz.components.spring.api.SpringResourceProvider; - public class Pvp2SProfileCoreSpringResourceProvider implements SpringResourceProvider { @Override diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java index b1ac8e75..69b94255 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java @@ -36,11 +36,15 @@ import org.opensaml.xmlsec.signature.support.SignatureConstants; import com.google.common.collect.ImmutableMap; public interface PvpConstants extends PvpAttributeDefinitions { - //module configuration parameters + // module configuration parameters String CONFIG_PROP_SEC_SIGNING_RSA_ALG = "pvp2.security.alg.signing.rsa"; String CONFIG_PROP_SEC_SIGNING_EC_ALG = "pvp2.security.alg.signing.ec"; + String CONFIG_PROP_SEC_ENCRYPTION_DATA = "pvp2.security.alg.enc.data"; + String CONFIG_PROP_SEC_ENCRYPTION_KEY_RSA_ALG = "pvp2.security.alg.enc.key.rsa"; + String CONFIG_PROP_SEC_ENCRYPTION_KEY_EC_ALG = "pvp2.security.alg.enc.key.ec"; + String CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION = "pvp2.assertion.encryption.active"; - //Default values + // Default values String DEFAULT_SIGNING_METHODE_RSA = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256; String DEFAULT_SIGNING_METHODE_EC = @@ -49,12 +53,13 @@ public interface PvpConstants extends PvpAttributeDefinitions { String DEFAULT_DIGESTMETHODE = SignatureConstants.ALGO_ID_DIGEST_SHA256; String DEFAULT_SYM_ENCRYPTION_METHODE = - EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256; - String DEFAULT_ASYM_ENCRYPTION_METHODE = + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM; + String DEFAULT_ASYM_ENCRYPTION_METHODE_RSA = EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP; + String DEFAULT_ASYM_ENCRYPTION_METHODE_EC = + EncryptionConstants.ALGO_ID_KEYAGREEMENT_DH; - - //PVP entity categories + // PVP entity categories String ENTITY_CATEGORY_ATTRIBITE = "http://macedir.org/entity-category"; String EGOVTOKEN = "http://www.ref.gv.at/ns/names/agiz/pvp/egovtoken"; String CITIZENTOKEN = "http://www.ref.gv.at/ns/names/agiz/pvp/citizentoken"; @@ -152,19 +157,22 @@ public interface PvpConstants extends PvpAttributeDefinitions { ImmutableMap<String, String> SIGNATURE_TO_DIGEST_ALGORITHM_MAP = ImmutableMap.<String, String>builder() - .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, SignatureConstants.ALGO_ID_DIGEST_SHA256) - .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA384, SignatureConstants.ALGO_ID_DIGEST_SHA384) - .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512, SignatureConstants.ALGO_ID_DIGEST_SHA512) - .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256, SignatureConstants.ALGO_ID_DIGEST_SHA256) - .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA384, SignatureConstants.ALGO_ID_DIGEST_SHA384) - .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA512, SignatureConstants.ALGO_ID_DIGEST_SHA512) - .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA256) - .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA384) - .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA512) - .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_256_MGF1, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_256) - .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_384_MGF1, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_384) - .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_512_MGF1, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_512) - - .build(); + .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, SignatureConstants.ALGO_ID_DIGEST_SHA256) + .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA384, SignatureConstants.ALGO_ID_DIGEST_SHA384) + .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512, SignatureConstants.ALGO_ID_DIGEST_SHA512) + .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256, SignatureConstants.ALGO_ID_DIGEST_SHA256) + .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA384, SignatureConstants.ALGO_ID_DIGEST_SHA384) + .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA512, SignatureConstants.ALGO_ID_DIGEST_SHA512) + .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA256) + .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA384) + .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA512) + .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_256_MGF1, + MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_256) + .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_384_MGF1, + MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_384) + .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_512_MGF1, + MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_512) + + .build(); } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java index e8da499c..83bfee84 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java @@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.api.binding; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface; import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; @@ -30,7 +31,7 @@ import net.shibboleth.utilities.java.support.net.URIComparator; public interface IDecoder { InboundMessageInterface decode(HttpServletRequest req, HttpServletResponse resp, - IPvp2MetadataProvider metadataProvider, boolean isSpEndPoint, URIComparator comparator) + IPvp2MetadataProvider metadataProvider, QName peerEntityRole, URIComparator comparator) throws Pvp2Exception; boolean handleDecode(String action, HttpServletRequest req); diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java index 691d6574..5a8bc4fb 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java @@ -60,7 +60,7 @@ public interface IEncoder { * @param credentials Credential to sign the response object * @param pendingReq Internal MOA-ID request object that contains * session-state informations but never null - * @throws SecurityException In case of an error + * @throws SecurityException In case of an error */ void encodeResponse(HttpServletRequest req, HttpServletResponse resp, StatusResponseType response, String targetLocation, String relayState, EaafX509Credential credentials, diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java index 568b617d..ce6451c0 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java @@ -4,7 +4,6 @@ import javax.annotation.Nonnull; import org.opensaml.security.x509.X509Credential; - public interface EaafX509Credential extends X509Credential { /** diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java index 128d4c2f..3d9125fe 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java @@ -22,15 +22,15 @@ package at.gv.egiz.eaaf.modules.pvp2.api.metadata; import java.util.Collection; import java.util.List; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; + import org.opensaml.saml.saml2.core.Attribute; import org.opensaml.saml.saml2.metadata.ContactPerson; import org.opensaml.saml.saml2.metadata.Organization; import org.opensaml.saml.saml2.metadata.RequestedAttribute; import org.opensaml.security.credential.Credential; -import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; -import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; - /** * PVP Metadata builder configuration. * diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java index 39536771..cc492345 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java @@ -27,7 +27,7 @@ import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver; * @author tlenz * */ -public interface IRefreshableMetadataProvider extends RefreshableMetadataResolver{ +public interface IRefreshableMetadataProvider extends RefreshableMetadataResolver { /** * Refresh a entity or load a entity in a metadata provider. diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/IAuthnRequestPostProcessor.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/IAuthnRequestPostProcessor.java index 2e84413e..9f7a5980 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/IAuthnRequestPostProcessor.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/IAuthnRequestPostProcessor.java @@ -31,7 +31,8 @@ import org.opensaml.saml.saml2.metadata.SPSSODescriptor; * SAML2 Authn. request post-processor. * * <p> - * Implementations of this interface are executed before user authentication starts. + * Implementations of this interface are executed before user authentication + * starts. * </p> * * @author tlenz @@ -42,12 +43,13 @@ public interface IAuthnRequestPostProcessor { /** * Authn. request post-processor * - * @param httpReq http request - * @param pendingReq current pending request - * @param authReq received SAML2 authentication request + * @param httpReq http request + * @param pendingReq current pending request + * @param authReq received SAML2 authentication request * @param spSsoDescriptor Metadata descriptor of the requested SP - * @throws AuthnRequestValidatorException In case of a validation error, - * if post processor implements additional validation + * @throws AuthnRequestValidatorException In case of a validation error, if post + * processor implements additional + * validation */ void process(HttpServletRequest httpReq, IRequest pendingReq, AuthnRequest authReq, SPSSODescriptor spSsoDescriptor) throws AuthnRequestValidatorException; diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/Pvp2InternalErrorException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/Pvp2InternalErrorException.java new file mode 100644 index 00000000..0b69897b --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/Pvp2InternalErrorException.java @@ -0,0 +1,12 @@ +package at.gv.egiz.eaaf.modules.pvp2.exception; + +public class Pvp2InternalErrorException extends Pvp2Exception { + + private static final long serialVersionUID = 496637421176810375L; + + public Pvp2InternalErrorException(Throwable wrapped) { + super("internal.pvp.98", new Object[] { wrapped.getMessage() }, wrapped); + + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java new file mode 100644 index 00000000..774d0927 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java @@ -0,0 +1,12 @@ +package at.gv.egiz.eaaf.modules.pvp2.exception; + +public class SamlMessageValidationException extends Pvp2Exception { + + private static final long serialVersionUID = 2545822499416501014L; + + public SamlMessageValidationException(String messageId, Object[] parameters, Throwable wrapped) { + super(messageId, parameters, wrapped); + + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMetadataSignatureException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMetadataSignatureException.java index 711fa41f..9ef3a673 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMetadataSignatureException.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMetadataSignatureException.java @@ -21,17 +21,33 @@ package at.gv.egiz.eaaf.modules.pvp2.exception; import org.opensaml.saml.saml2.core.StatusCode; -public class SamlMetadataSignatureException extends Pvp2Exception { +public class SamlMetadataSignatureException extends Pvp2MetadataException { private static final long serialVersionUID = 1L; - public SamlMetadataSignatureException() { - super("pvp2.25", null); + /** + * In case of a SAML2 metadata-signature verification error. + * + * @param metadataUrl Path metadata that should be loaded + * @param reason Details on error + * + */ + public SamlMetadataSignatureException(String metadataUrl, String reason) { + super("internal.pvp.07", new Object[] { metadataUrl, reason }); this.statusCodeValue = StatusCode.REQUESTER; + } - public SamlMetadataSignatureException(final Throwable e) { - super("pvp2.25", null, e); + /** + * In case of a SAML2 metadata-signature verification error. + * + * @param metadataUrl Path metadata that should be loaded + * @param reason Details on error + * @param e Error + */ + public SamlMetadataSignatureException(String metadataUrl, String reason, final Throwable e) { + super("internal.pvp.07", new Object[] { metadataUrl, reason }, e); this.statusCodeValue = StatusCode.REQUESTER; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java index ae108c35..3543d85a 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java @@ -1,15 +1,29 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.binding; +import javax.xml.namespace.QName; + import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface; import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlMessageValidationException; import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain; import org.opensaml.core.config.ConfigurationService; import org.opensaml.messaging.context.BaseContext; import org.opensaml.messaging.context.MessageContext; +import org.opensaml.messaging.decoder.MessageDecodingException; +import org.opensaml.messaging.decoder.servlet.HttpServletRequestMessageDecoder; +import org.opensaml.messaging.handler.MessageHandlerException; import org.opensaml.saml.common.SAMLObject; import org.opensaml.saml.common.SignableSAMLObject; import org.opensaml.saml.common.binding.SAMLBindingSupport; @@ -19,6 +33,8 @@ import org.opensaml.saml.common.messaging.context.SAMLMessageInfoContext; import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext; import org.opensaml.saml.common.messaging.context.SAMLProtocolContext; import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.RequestAbstractType; +import org.opensaml.saml.saml2.core.StatusResponseType; import org.opensaml.saml.saml2.metadata.SingleSignOnService; import org.opensaml.saml.saml2.metadata.impl.SingleSignOnServiceBuilder; import org.opensaml.xmlsec.SignatureSigningParameters; @@ -28,21 +44,62 @@ import org.opensaml.xmlsec.context.SecurityParametersContext; import org.opensaml.xmlsec.signature.support.SignatureConstants; import org.springframework.beans.factory.annotation.Autowired; +import com.google.common.base.Optional; +import com.google.common.base.Predicates; +import com.google.common.base.Throwables; +import com.google.common.collect.FluentIterable; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; + /** * Abstract Binding implements common code for SAML2 binding implementations. * * @author tlenz * */ +@Slf4j public abstract class AbstractBinding { - @Autowired protected IConfiguration basicConfig; + @Autowired + protected IConfiguration basicConfig; public abstract String getSaml2BindingName(); + protected MessageContext<SAMLObject> internalMessageDecode( + HttpServletRequestMessageDecoder<SAMLObject> decoder, + String binding) throws Pvp2Exception { + try { + decoder.initialize(); + decoder.decode(); + + } catch (final ComponentInitializationException e) { + log.warn("Internal initialization error. Reason: {}", e.getMessage()); + throw new Pvp2InternalErrorException(e); + + } catch (final MessageDecodingException e) { + final Optional<Throwable> pvpException = FluentIterable.from( + Throwables.getCausalChain(e)).filter( + Predicates.instanceOf(Pvp2Exception.class)).first(); + + if (pvpException.isPresent()) { + throw (Pvp2Exception) pvpException.get(); + + } else { + throw new SamlBindingException("internal.pvp.95", + new Object[] { binding, "decoding", e.getMessage() }, + e); + + } + + } + + return decoder.getMessageContext(); + + } + protected MessageContext<SAMLObject> buildBasicMessageContext( SAMLMessageEncoder encoder, SignableSAMLObject response) { - final MessageContext<SAMLObject> messageContext = new MessageContext<SAMLObject>(); + final MessageContext<SAMLObject> messageContext = new MessageContext<>(); messageContext.setMessage(response); encoder.setMessageContext(messageContext); return messageContext; @@ -63,7 +120,7 @@ public abstract class AbstractBinding { signingParams.setSignatureReferenceDigestMethod( Saml2Utils.getDigestAlgorithm(signingParams.getSignatureAlgorithm())); - signingParams.setKeyInfoGenerator(Saml2Utils.getKeyInfoGenerator(credentials, false)); + signingParams.setKeyInfoGenerator(Saml2Utils.getKeyInfoGenerator(credentials, true)); return securityParamContext; @@ -83,16 +140,16 @@ public abstract class AbstractBinding { } protected void injectInboundMessageContexts(MessageContext<SAMLObject> messageContext, - IPvp2MetadataProvider metadataProvider) { - messageContext.addSubcontext(new SAMLPeerEntityContext()); + IPvp2MetadataProvider metadataProvider, QName peerEntityRole) throws Pvp2InternalErrorException { + final SAMLPeerEntityContext peerEntityContext = new SAMLPeerEntityContext(); + peerEntityContext.setRole(peerEntityRole); + messageContext.addSubcontext(peerEntityContext); messageContext.addSubcontext(new SAMLMessageInfoContext()); - final SAMLProtocolContext protocolContext = new SAMLProtocolContext(); protocolContext.setProtocol(SAMLConstants.SAML20P_NS); messageContext.addSubcontext(protocolContext); - final SecurityParametersContext securityParameterContext = new SecurityParametersContext(); final SignatureValidationParameters sigValParameters = new SignatureValidationParameters(); securityParameterContext.setSignatureValidationParameters(sigValParameters); @@ -100,9 +157,63 @@ public abstract class AbstractBinding { sigValParameters.setBlacklistedAlgorithms( ConfigurationService.get(SignatureValidationConfiguration.class) - .getBlacklistedAlgorithms()); + .getBlacklistedAlgorithms()); sigValParameters.setSignatureTrustEngine( TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); } + + protected void performMessageValidation(PvpSamlMessageHandlerChain messageValidatorChain, + MessageContext<SAMLObject> messageContext) throws Pvp2Exception { + try { + messageValidatorChain.initialize(); + messageValidatorChain.invoke(messageContext); + + } catch (final ComponentInitializationException e) { + log.warn("Internal initialization error. Reason: {}", e.getMessage()); + throw new Pvp2InternalErrorException(e); + + } catch (final MessageHandlerException e) { + log.info("SAML message validation error. Reason: {}", e.getMessage()); + final Optional<Throwable> pvpException = FluentIterable.from( + Throwables.getCausalChain(e)).filter( + Predicates.instanceOf(Pvp2Exception.class)).first(); + + if (pvpException.isPresent()) { + throw (Pvp2Exception) pvpException.get(); + + } else { + throw new SamlMessageValidationException("internal.pvp.11", + new Object[] { e.getMessage() }, e); + + } + } + } + + protected InboundMessageInterface performMessageDecodePostProcessing( + MessageContext<SAMLObject> messageContext, boolean isVerified) { + InboundMessage msg = null; + if (messageContext.getMessage() instanceof RequestAbstractType) { + final RequestAbstractType inboundMessage = + (RequestAbstractType) messageContext.getMessage(); + msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName()); + msg.setEntityID(inboundMessage.getIssuer().getValue()); + + } else if (messageContext.getMessage() instanceof StatusResponseType) { + final StatusResponseType inboundMessage = + (StatusResponseType) messageContext.getMessage(); + msg = new PvpSProfileResponse(inboundMessage); + msg.setEntityID(inboundMessage.getIssuer().getValue()); + + } else { + // create empty container if request type is unknown + msg = new InboundMessage(); + + } + + msg.setVerified(isVerified); + msg.setRelayState(SAMLBindingSupport.getRelayState(messageContext)); + + return msg; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java index 6f39392d..c679de20 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java @@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.binding; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfigurationFactory; @@ -36,16 +37,17 @@ import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.EaafHttpPostDecoder; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.HttpPostEncoderWithOwnTemplate; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafSamlProtocolMessageXmlSignatureSecurityHandler; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain; import org.opensaml.messaging.context.MessageContext; -import org.opensaml.messaging.decoder.MessageDecodingException; import org.opensaml.saml.common.SAMLObject; import org.opensaml.saml.common.binding.SAMLBindingSupport; +import org.opensaml.saml.common.binding.impl.CheckMessageVersionHandler; +import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHandler; +import org.opensaml.saml.common.binding.security.impl.ReceivedEndpointSecurityHandler; import org.opensaml.saml.common.messaging.SAMLMessageSecuritySupport; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.saml2.core.RequestAbstractType; @@ -53,7 +55,6 @@ import org.opensaml.saml.saml2.core.StatusResponseType; import org.springframework.beans.factory.annotation.Autowired; import lombok.extern.slf4j.Slf4j; -import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.net.URIComparator; @Slf4j @@ -78,35 +79,34 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder { guiConfigFactory.getSpSpecificSaml2PostConfiguration(pendingReq, "pvp_postbinding_template.html", authConfig.getConfigurationRootDirectory()); - final HttpPostEncoderWithOwnTemplate encoder - = new HttpPostEncoderWithOwnTemplate(guiConfig, guiBuilder); + final HttpPostEncoderWithOwnTemplate encoder = new HttpPostEncoderWithOwnTemplate(guiConfig, + guiBuilder); encoder.setHttpServletResponse(httpResp); - //inject message context + // inject message context final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, request); - //inject signing context + // inject signing context messageContext.addSubcontext(injectSigningInfos(credentials)); - //set endpoint url + // set endpoint url messageContext.addSubcontext(injectEndpointInfos(request, targetLocation)); - - //set relayState of exists + // set relayState of exists SAMLBindingSupport.setRelayState(messageContext, relayState); - //sign SAML2 message + // sign SAML2 message SAMLMessageSecuritySupport.signMessage(messageContext); - //encode message + // encode message encoder.initialize(); encoder.encode(); } catch (final Exception e) { log.warn("Can not encode SAML2 Post-Binding request", e); throw new SamlBindingException("internal.pvp.95", - new Object[] {PvpConstants.POST, "encoding", e.getMessage()}, + new Object[] { PvpConstants.POST, "encoding", e.getMessage() }, e); } @@ -116,7 +116,7 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder { public void encodeResponse(final HttpServletRequest httpReq, final HttpServletResponse httpResp, final StatusResponseType response, final String targetLocation, final String relayState, final EaafX509Credential credentials, final IRequest pendingReq) - throws Pvp2Exception { + throws Pvp2Exception { try { log.debug("create SAML POSTBinding response"); @@ -130,99 +130,62 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder { encoder.setHttpServletResponse(httpResp); - //inject message context + // inject message context final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, response); - //inject signing context + // inject signing context messageContext.addSubcontext(injectSigningInfos(credentials)); - //set endpoint url + // set endpoint url messageContext.addSubcontext(injectEndpointInfos(response, targetLocation)); - //set relayState of exists + // set relayState of exists SAMLBindingSupport.setRelayState(messageContext, relayState); - //sign SAML2 message + // sign SAML2 message SAMLMessageSecuritySupport.signMessage(messageContext); - //encode message + // encode message encoder.initialize(); encoder.encode(); } catch (final Exception e) { log.warn("Can not encode SAML2 Post-Binding response", e); throw new SamlBindingException("internal.pvp.95", - new Object[] {PvpConstants.POST, "encoding", e.getMessage()}, + new Object[] { PvpConstants.POST, "encoding", e.getMessage() }, e); } } - - - - @Override public InboundMessageInterface decode(final HttpServletRequest req, final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider, - final boolean isSpEndPoint, final URIComparator comparator) + QName peerEntityRole, final URIComparator comparator) throws Pvp2Exception { - //TODO: check, if we should re-implement HTTPPostDecoder to collect the last http parameter!!! - final EaafHttpPostDecoder decode = new EaafHttpPostDecoder(); - decode.setHttpServletRequest(req); - - //decode request - try { - decode.initialize(); - decode.decode(); - - } catch (MessageDecodingException | ComponentInitializationException e) { - throw new SamlBindingException("internal.pvp.95", - new Object[] {PvpConstants.POST, "decoding", e.getMessage()}, - e); - } - - final MessageContext<SAMLObject> messageContext = decode.getMessageContext(); + final EaafHttpPostDecoder decode = new EaafHttpPostDecoder(req); + final MessageContext<SAMLObject> messageContext = internalMessageDecode(decode, PvpConstants.POST); - if (SAMLBindingSupport.isSigningCapableBinding(messageContext)) { + // check if PVP2 AuthnRequest is signed + if (!SAMLBindingSupport.isMessageSigned(messageContext)) { log.info("SAML Post-Binding message contains no signature. Message will be rejected"); throw new InvalidPvpRequestException("internal.pvp.02", null); } - //inject informations into message context that are required for further processing - injectInboundMessageContexts(messageContext, metadataProvider); + // inject informations into message context that are required for further + // processing + injectInboundMessageContexts(messageContext, metadataProvider, peerEntityRole); + final PvpSamlMessageHandlerChain messageValidatorChain = + buildMessageValidationChain(req, comparator, metadataProvider); + log.trace("Message validation (Signature, ...) on binding-level starts ... "); + performMessageValidation(messageValidatorChain, messageContext); - //TODO: add sig validation!!! + log.trace("Message validation successful"); + return performMessageDecodePostProcessing(messageContext, true); - - - InboundMessage msg = null; - - if (messageContext.getMessage() instanceof RequestAbstractType) { - final RequestAbstractType inboundMessage = - (RequestAbstractType) messageContext.getMessage(); - msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName()); - msg.setEntityID(inboundMessage.getIssuer().getValue()); - - } else if (messageContext.getMessage() instanceof StatusResponseType) { - final StatusResponseType inboundMessage = - (StatusResponseType) messageContext.getMessage(); - msg = new PvpSProfileResponse(inboundMessage); - msg.setEntityID(inboundMessage.getIssuer().getValue()); - - } else { - // create empty container if request type is unknown - msg = new InboundMessage(); - - } - - msg.setVerified(false); - msg.setRelayState(SAMLBindingSupport.getRelayState(messageContext)); - - return msg; } @Override @@ -234,5 +197,41 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder { @Override public String getSaml2BindingName() { return SAMLConstants.SAML2_POST_BINDING_URI; + + } + + private PvpSamlMessageHandlerChain buildMessageValidationChain(HttpServletRequest req, + URIComparator comparator, IPvp2MetadataProvider metadataProvider) { + final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain(); + + final ReceivedEndpointSecurityHandler endpointSecurityHandler = new ReceivedEndpointSecurityHandler(); + endpointSecurityHandler.setHttpServletRequest(req); + endpointSecurityHandler.setURIComparator(comparator); + + messageValidatorChain.addHandler(new CheckMessageVersionHandler()); + messageValidatorChain.addHandler(endpointSecurityHandler); + messageValidatorChain.addHandler( + new EaafSamlProtocolMessageXmlSignatureSecurityHandler(metadataProvider)); + messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler()); + + /* + * TODO: maybe we add it in a later version Because: - AuthnRequest replay + * should not be a problem on IDP side - Response replay will be not possible, + * because EAAF PVP implements countermeasure based on one-time tokens for each + * request + * + */ + // final MessageReplaySecurityHandler replaySecurityHandler = new + // MessageReplaySecurityHandler(); + // final StorageService replayCacheStorage = null; + // final ReplayCache replayCache = new ReplayCache(); + // replayCache.setId("Message replay cache"); + // replayCache.setStrict(true); + // replayCache.setStorage(replayCacheStorage); + // replaySecurityHandler.setReplayCache(replayCache ); + // messageValidatorChain.addHandler(replaySecurityHandler); + + return messageValidatorChain; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java index 5f74053d..f62f8a11 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java @@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.binding; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; @@ -32,15 +33,11 @@ import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.EaafHttpRedirectDeflateDecoder; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafSaml2HttpRedirectDeflateSignatureSecurityHandler; import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain; import org.opensaml.messaging.context.MessageContext; -import org.opensaml.messaging.decoder.MessageDecodingException; -import org.opensaml.messaging.handler.MessageHandlerException; import org.opensaml.saml.common.SAMLObject; import org.opensaml.saml.common.binding.SAMLBindingSupport; import org.opensaml.saml.common.binding.impl.CheckMessageVersionHandler; @@ -48,13 +45,11 @@ import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHan import org.opensaml.saml.common.messaging.context.SAMLBindingContext; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.saml2.binding.encoding.impl.HTTPRedirectDeflateEncoder; -import org.opensaml.saml.saml2.binding.security.impl.SAML2HTTPRedirectDeflateSignatureSecurityHandler; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.StatusResponseType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.net.URIComparator; public class RedirectBinding extends AbstractBinding implements IDecoder, IEncoder { @@ -137,26 +132,11 @@ public class RedirectBinding extends AbstractBinding implements IDecoder, IEncod @Override public InboundMessageInterface decode(final HttpServletRequest req, final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider, - final boolean isSpEndPoint, final URIComparator comparator) + QName peerEntityRole, final URIComparator comparator) throws Pvp2Exception { - // TODO: implement one flat decoder to get SAML2 request/response parametes as - // same as in SAML2HTTPRedirectDeflateSignatureSecurityHandler - final EaafHttpRedirectDeflateDecoder decode = new EaafHttpRedirectDeflateDecoder(); - decode.setHttpServletRequest(req); - - // decode request - try { - decode.initialize(); - decode.decode(); - - } catch (MessageDecodingException | ComponentInitializationException e) { - throw new SamlBindingException("internal.pvp.95", - new Object[] { PvpConstants.REDIRECT, "decoding", e.getMessage() }, - e); - } - - final MessageContext<SAMLObject> messageContext = decode.getMessageContext(); + final EaafHttpRedirectDeflateDecoder decode = new EaafHttpRedirectDeflateDecoder(req); + final MessageContext<SAMLObject> messageContext = internalMessageDecode(decode, PvpConstants.REDIRECT); final SAMLBindingContext bindingContext = messageContext.getSubcontext(SAMLBindingContext.class, true); if (!bindingContext.hasBindingSignature()) { @@ -165,171 +145,18 @@ public class RedirectBinding extends AbstractBinding implements IDecoder, IEncod } - //inject informations into message context that are required for further processing - injectInboundMessageContexts(messageContext, metadataProvider); + // inject informations into message context that are required for further + // processing + injectInboundMessageContexts(messageContext, metadataProvider, peerEntityRole); + final PvpSamlMessageHandlerChain messageValidatorChain = + buildMessageValidationChain(req, metadataProvider); - log.trace("Signature validation on binding-level starts ... "); - final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain(); - final SAML2HTTPRedirectDeflateSignatureSecurityHandler redirectBindingSignaturHandler = - new SAML2HTTPRedirectDeflateSignatureSecurityHandler(); - redirectBindingSignaturHandler.setHttpServletRequest(req); - - messageValidatorChain.addHandler(new CheckMessageVersionHandler()); - messageValidatorChain.addHandler(redirectBindingSignaturHandler); - messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler()); - - - /*TODO: maybe we add it in a later version - * Because: - * - AuthnRequest replay should not be a problem on IDP side - * - Response replay will be not possible, because EAAF PVP implements - * countermeasure based on one-time tokens for each request - * - */ - //final MessageReplaySecurityHandler replaySecurityHandler = new MessageReplaySecurityHandler(); - //final StorageService replayCacheStorage = null; - //final ReplayCache replayCache = new ReplayCache(); - //replayCache.setId("Message replay cache"); - //replayCache.setStrict(true); - //replayCache.setStorage(replayCacheStorage); - //replaySecurityHandler.setReplayCache(replayCache ); - //messageValidatorChain.addHandler(replaySecurityHandler); + log.trace("Message validation (Signature, ...) on binding-level starts ... "); + performMessageValidation(messageValidatorChain, messageContext); + log.trace("Message validation successful"); + return performMessageDecodePostProcessing(messageContext, true); - try { - messageValidatorChain.initialize(); - messageValidatorChain.invoke(messageContext); - - } catch (final ComponentInitializationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - - } catch (final MessageHandlerException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - InboundMessage msg = null; - - if (messageContext.getMessage() instanceof RequestAbstractType) { - final RequestAbstractType inboundMessage = - (RequestAbstractType) messageContext.getMessage(); - msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName()); - msg.setEntityID(inboundMessage.getIssuer().getValue()); - - } else if (messageContext.getMessage() instanceof StatusResponseType) { - final StatusResponseType inboundMessage = - (StatusResponseType) messageContext.getMessage(); - msg = new PvpSProfileResponse(inboundMessage); - msg.setEntityID(inboundMessage.getIssuer().getValue()); - - } else { - // create empty container if request type is unknown - msg = new InboundMessage(); - - } - - msg.setVerified(false); - msg.setRelayState(SAMLBindingSupport.getRelayState(messageContext)); - - return msg; - -// final BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = -// new BasicSAMLMessageContext<>(); -// messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(req)); -// -// // set metadata descriptor type -// if (isSpEndPoint) { -// messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); -// decode.setURIComparator(comparator); -// -// } else { -// messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); -// decode.setURIComparator(comparator); -// } -// -// messageContext.setMetadataProvider(metadataProvider); -// -// final SAML2HTTPRedirectDeflateSignatureRule signatureRule = -// new SAML2HTTPRedirectDeflateSignatureRule( -// TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); -// final PvpAuthRequestSignedRole signedRole = new PvpAuthRequestSignedRole(); -// final BasicSecurityPolicy policy = new BasicSecurityPolicy(); -// policy.getPolicyRules().add(signedRole); -// policy.getPolicyRules().add(signatureRule); -// final SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver(policy); -// messageContext.setSecurityPolicyResolver(resolver); -// -// // set metadata descriptor type -// if (isSpEndPoint) { -// messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); -// } else { -// messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); -// } -// -// SAML2AuthnRequestsSignedSecurityHandler -// -// try { -// decode.decode(messageContext); -// -// // check signature -// signatureRule.evaluate(messageContext); -// -// } catch (final SecurityException e) { -// if (StringUtils.isEmpty(messageContext.getInboundMessageIssuer())) { -// throw e; -// -// } -// -// if (metadataProvider instanceof IRefreshableMetadataProvider) { -// log.debug("PVP2X message validation FAILED. Reload metadata for entityID: " -// + messageContext.getInboundMessageIssuer()); -// if (!((IRefreshableMetadataProvider) metadataProvider) -// .refreshMetadataProvider(messageContext.getInboundMessageIssuer())) { -// throw e; -// } else { -// log.trace("PVP2X metadata reload finished. Check validate message again."); -// decode.decode(messageContext); -// -// // check signature -// signatureRule.evaluate(messageContext); -// -// } -// log.trace("Second PVP2X message validation finished"); -// -// } else { -// throw e; -// -// } -// } -// -// InboundMessage msg = null; -// if (messageContext.getInboundMessage() instanceof RequestAbstractType) { -// final RequestAbstractType inboundMessage = -// (RequestAbstractType) messageContext.getInboundMessage(); -// msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName()); -// -// } else if (messageContext.getInboundMessage() instanceof StatusResponseType) { -// final StatusResponseType inboundMessage = -// (StatusResponseType) messageContext.getInboundMessage(); -// msg = new PvpSProfileResponse(inboundMessage); -// -// } else { -// // create empty container if request type is unknown -// msg = new InboundMessage(); -// } -// -// if (messageContext.getPeerEntityMetadata() != null) { -// msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID()); -// } else { -// log.info( -// "No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer()); -// } -// -// msg.setVerified(true); -// msg.setRelayState(messageContext.getRelayState()); -// -// return msg; } @Override @@ -341,5 +168,38 @@ public class RedirectBinding extends AbstractBinding implements IDecoder, IEncod @Override public String getSaml2BindingName() { return SAMLConstants.SAML2_REDIRECT_BINDING_URI; + + } + + private PvpSamlMessageHandlerChain buildMessageValidationChain(HttpServletRequest req, + IPvp2MetadataProvider metadataProvider) { + final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain(); + final EaafSaml2HttpRedirectDeflateSignatureSecurityHandler redirectBindingSignaturHandler = + new EaafSaml2HttpRedirectDeflateSignatureSecurityHandler(metadataProvider); + redirectBindingSignaturHandler.setHttpServletRequest(req); + + messageValidatorChain.addHandler(new CheckMessageVersionHandler()); + messageValidatorChain.addHandler(redirectBindingSignaturHandler); + messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler()); + + /* + * TODO: maybe we add it in a later version Because: - AuthnRequest replay + * should not be a problem on IDP side - Response replay will be not possible, + * because EAAF PVP implements countermeasure based on one-time tokens for each + * request + * + */ + // final MessageReplaySecurityHandler replaySecurityHandler = new + // MessageReplaySecurityHandler(); + // final StorageService replayCacheStorage = null; + // final ReplayCache replayCache = new ReplayCache(); + // replayCache.setId("Message replay cache"); + // replayCache.setStrict(true); + // replayCache.setStorage(replayCacheStorage); + // replaySecurityHandler.setReplayCache(replayCache ); + // messageValidatorChain.addHandler(replaySecurityHandler); + + return messageValidatorChain; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java index e0df2d2a..49e93f0a 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java @@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.binding; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; @@ -29,27 +30,29 @@ import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface; import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.exception.AttributQueryException; +import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException; import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafMessageContextInitializationHandler; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafSamlProtocolMessageXmlSignatureSecurityHandler; import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain; import org.opensaml.messaging.context.MessageContext; -import org.opensaml.messaging.decoder.MessageDecodingException; import org.opensaml.saml.common.SAMLObject; import org.opensaml.saml.common.binding.SAMLBindingSupport; import org.opensaml.saml.common.binding.impl.CheckMessageVersionHandler; import org.opensaml.saml.common.binding.impl.SAMLProtocolAndRoleHandler; import org.opensaml.saml.common.binding.impl.SAMLSOAPDecoderBodyHandler; import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHandler; -import org.opensaml.saml.common.binding.security.impl.SAMLProtocolMessageXMLSignatureSecurityHandler; import org.opensaml.saml.common.messaging.SAMLMessageSecuritySupport; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.saml2.binding.decoding.impl.HTTPSOAP11Decoder; import org.opensaml.saml.saml2.binding.encoding.impl.HTTPSOAP11Encoder; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.StatusResponseType; +import org.opensaml.soap.messaging.context.SOAP11Context; import lombok.extern.slf4j.Slf4j; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; @@ -61,72 +64,55 @@ public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder { @Override public InboundMessageInterface decode(final HttpServletRequest req, final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider, - final boolean isSpEndPoint, final URIComparator comparator) + QName peerEntityRole, final URIComparator comparator) throws Pvp2Exception { - try { - final HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder(); + final HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder(); + soapDecoder.setHttpServletRequest(req); + + injectMessageHandlerChain(soapDecoder, metadataProvider, peerEntityRole); + + final MessageContext<SAMLObject> messageContext = + internalMessageDecode(soapDecoder, PvpConstants.SOAP); + + // check if PVP2 AuthnRequest is signed + if (!SAMLBindingSupport.isMessageSigned(messageContext)) { + log.info("SAML Post-Binding message contains no signature. Message will be rejected"); + throw new InvalidPvpRequestException("internal.pvp.02", null); + + } + + return performMessageDecodePostProcessing(messageContext, true); + } + private void injectMessageHandlerChain(HTTPSOAP11Decoder soapDecoder, + IPvp2MetadataProvider metadataProvider, QName peerEntityRole) throws Pvp2InternalErrorException { + try { final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain(); - soapDecoder.setBodyHandler(messageValidatorChain); + messageValidatorChain.addHandler(new EaafMessageContextInitializationHandler(metadataProvider)); + messageValidatorChain.addHandler(new SAMLSOAPDecoderBodyHandler()); - final SAMLProtocolMessageXMLSignatureSecurityHandler msgSignatureValidationHandler = - new SAMLProtocolMessageXMLSignatureSecurityHandler(); + final SAMLProtocolAndRoleHandler samlProtocolHandler = new SAMLProtocolAndRoleHandler(); + samlProtocolHandler.setProtocol(SAMLConstants.SAML20P_NS); + samlProtocolHandler.setRole(peerEntityRole); + messageValidatorChain.addHandler(samlProtocolHandler); - messageValidatorChain.addHandler(new EaafMessageContextInitializationHandler()); messageValidatorChain.addHandler(new CheckMessageVersionHandler()); - messageValidatorChain.addHandler(new SAMLProtocolAndRoleHandler()); - messageValidatorChain.addHandler(msgSignatureValidationHandler); + messageValidatorChain.addHandler( + new EaafSamlProtocolMessageXmlSignatureSecurityHandler(metadataProvider)); messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler()); - messageValidatorChain.addHandler(new SAMLSOAPDecoderBodyHandler()); - // decode message - soapDecoder.initialize(); - soapDecoder.decode(); + messageValidatorChain.initialize(); - final MessageContext<SAMLObject> messageContext = soapDecoder.getMessageContext(); - messageContext.getMessage(); + soapDecoder.setBodyHandler(messageValidatorChain); + + } catch (final ComponentInitializationException e) { + log.warn("Internal initialization error. Reason: {}", e.getMessage()); + throw new Pvp2InternalErrorException(e); - } catch (MessageDecodingException | ComponentInitializationException e) { - throw new SamlBindingException("internal.pvp.95", - new Object[] { PvpConstants.POST, "decoding", e.getMessage() }, - e); } -// final Envelope inboundMessage = (Envelope) messageContext.getMessage(); -// -// if (inboundMessage.getBody() != null) { -// final List<XMLObject> xmlElemList = inboundMessage.getBody().getUnknownXMLObjects(); -// -// if (!xmlElemList.isEmpty()) { -// final SignableXMLObject attrReq = (SignableXMLObject) xmlElemList.get(0); -// final PvpSProfileRequest request = new PvpSProfileRequest(attrReq, getSaml2BindingName()); -// -// if (messageContext.getPeerEntityMetadata() != null) { -// request.setEntityID(messageContext.getPeerEntityMetadata().getEntityID()); -// -// } else if (attrReq instanceof RequestAbstractType) { -// final RequestAbstractType attributeRequest = (RequestAbstractType) attrReq; -// try { -// if (StringUtils.isNotEmpty(attributeRequest.getIssuer().getValue()) -// && metadataProvider.getRole(attributeRequest.getIssuer().getValue(), -// SPSSODescriptor.DEFAULT_ELEMENT_NAME) != null) { -// request.setEntityID(attributeRequest.getIssuer().getValue()); -// } -// -// } catch (final Exception e) { -// log.warn("No Metadata found with EntityID " + attributeRequest.getIssuer().getValue()); -// } -// } -// -// request.setVerified(false); -// return request; -// -// } -// } - - log.error("Receive empty PVP 2.1 attributequery request."); - throw new AttributQueryException("Receive empty PVP 2.1 attributequery request.", null); + } @Override @@ -157,6 +143,11 @@ public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder { // inject message context final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, response); + //inject SOAP enveloped + final SOAP11Context soap11Context = new SOAP11Context(); + soap11Context.setEnvelope(Saml2Utils.buildSoap11Envelope(response)); + messageContext.addSubcontext(soap11Context); + // inject signing context messageContext.addSubcontext(injectSigningInfos(credentials)); @@ -172,6 +163,7 @@ public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder { // encode message encoder.initialize(); encoder.encode(); + } catch (final Exception e) { log.warn("Can not encode SAML2 SOAP-Binding response", e); throw new SamlBindingException("internal.pvp.95", diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java index 1667a07d..bf201803 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java @@ -61,7 +61,8 @@ public class CitizenTokenBuilder { */ public static XMLObject buildAttributeIntegerValue(final int value) { final XSIntegerBuilder integerBuilder = - (XSIntegerBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(XSInteger.TYPE_NAME); + (XSIntegerBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder( + XSInteger.TYPE_NAME); final XSInteger integerValue = integerBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSInteger.TYPE_NAME); integerValue.setValue(value); diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java index d5893d4a..92922e09 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java @@ -20,6 +20,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder; import java.io.IOException; +import java.text.MessageFormat; import java.util.Collection; import java.util.List; @@ -28,6 +29,13 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactoryConfigurationError; +import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; + import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.opensaml.core.xml.io.MarshallingException; @@ -57,14 +65,8 @@ import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory; import org.opensaml.xmlsec.signature.support.SignatureException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; import org.w3c.dom.Element; -import at.gv.egiz.eaaf.core.exceptions.EaafException; -import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; -import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import net.shibboleth.utilities.java.support.xml.SerializeSupport; /** @@ -74,9 +76,10 @@ import net.shibboleth.utilities.java.support.xml.SerializeSupport; * */ -@Service("PVPMetadataBuilder") public class PvpMetadataBuilder { + private static final String ERROR_ROLE_DESCR = "Can not build {0}"; + private static final Logger log = LoggerFactory.getLogger(PvpMetadataBuilder.class); X509KeyInfoGeneratorFactory keyInfoFactory = null; @@ -133,6 +136,12 @@ public class PvpMetadataBuilder { final RoleDescriptor idpSsoDesc = generateIdpMetadata(config); if (idpSsoDesc != null) { entityDescriptor.getRoleDescriptors().add(idpSsoDesc); + + } else { + final String msg = MessageFormat.format(ERROR_ROLE_DESCR, + IDPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME); + throw new EaafBuilderException("internal.pvp.13", new Object[] { msg }, msg); + } } @@ -142,12 +151,17 @@ public class PvpMetadataBuilder { final RoleDescriptor spSsoDesc = generateSpMetadata(config); if (spSsoDesc != null) { entityDescriptor.getRoleDescriptors().add(spSsoDesc); + + } else { + final String msg = MessageFormat.format(ERROR_ROLE_DESCR, SPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME); + throw new EaafBuilderException("internal.pvp.13", new Object[] { msg }, msg); + } } - + SignableSAMLObject metadataToSign; - + // build entities descriptor if (config.buildEntitiesDescriptorAsRootElement()) { final EntitiesDescriptor entitiesDescriptor = @@ -157,24 +171,24 @@ public class PvpMetadataBuilder { entitiesDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil())); entitiesDescriptor.getEntityDescriptors().add(entityDescriptor); metadataToSign = entitiesDescriptor; - + } else { entityDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil())); entityDescriptor.setID(Saml2Utils.getSecureIdentifier()); metadataToSign = entityDescriptor; - + } // sign metadata final EaafX509Credential metadataSignCred = config.getMetadataSigningCredentials(); - SignableSAMLObject signedMetadata = Saml2Utils.signSamlObject(metadataToSign, metadataSignCred, true); - - + final SignableSAMLObject signedMetadata = Saml2Utils.signSamlObject(metadataToSign, metadataSignCred, + true); + // Serialize metadata - final Element document =XMLObjectSupport.marshall(signedMetadata); - String serializedMetadata = SerializeSupport.nodeToString(document); + final Element document = XMLObjectSupport.marshall(signedMetadata); + final String serializedMetadata = SerializeSupport.nodeToString(document); return serializedMetadata; - + } private RoleDescriptor generateSpMetadata(final IPvpMetadataBuilderConfiguration config) @@ -402,7 +416,10 @@ public class PvpMetadataBuilder { idpSsoDescriptor.getKeyDescriptors().add(signKeyDescriptor); // set IDP attribute set - idpSsoDescriptor.getAttributes().addAll(config.getIdpPossibleAttributes()); + if (config.getIdpPossibleAttributes() != null) { + idpSsoDescriptor.getAttributes().addAll(config.getIdpPossibleAttributes()); + + } // set providable nameID formats for (final String format : config.getIdpPossibleNameIdTypes()) { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java index d37d6724..5c44af24 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java @@ -44,7 +44,8 @@ public class SamlAttributeGenerator implements IAttributeGenerator<Attribute> { private XMLObject buildAttributeIntegerValue(final int value) { final XSIntegerBuilder integerBuilder = - (XSIntegerBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(XSInteger.TYPE_NAME); + (XSIntegerBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder( + XSInteger.TYPE_NAME); final XSInteger integerValue = integerBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSInteger.TYPE_NAME); integerValue.setValue(value); diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java index 961f29cb..227ff30e 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java @@ -5,7 +5,6 @@ import java.util.List; import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation; - public class PvpModuleMessageSource implements IMessageSourceLocation { @Override diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java index da958d5b..0ffa3789 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java @@ -25,16 +25,17 @@ import java.io.Serializable; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; + import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import at.gv.egiz.eaaf.core.impl.utils.DomUtils; -import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; import net.shibboleth.utilities.java.support.resolver.ResolverException; public class InboundMessage implements InboundMessageInterface, Serializable { @@ -68,7 +69,7 @@ public class InboundMessage implements InboundMessageInterface, Serializable { } catch (final ResolverException e) { log.warn("No Metadata for EntitiyID " + entityID); throw new NoMetadataInformationException(); - + } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java index 3fc675e9..8a20b932 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java @@ -27,12 +27,17 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.naming.ConfigurationException; +import at.gv.egiz.components.spring.api.IDestroyableObject; +import at.gv.egiz.eaaf.core.api.IGarbageCollectorProcessing; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; + import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.opensaml.core.criterion.EntityIdCriterion; @@ -43,11 +48,6 @@ import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; import org.opensaml.saml.metadata.resolver.impl.AbstractMetadataResolver; import org.opensaml.saml.saml2.metadata.EntityDescriptor; -import at.gv.egiz.components.spring.api.IDestroyableObject; -import at.gv.egiz.eaaf.core.api.IGarbageCollectorProcessing; -import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; import lombok.extern.slf4j.Slf4j; import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements; import net.shibboleth.utilities.java.support.component.IdentifiedComponent; @@ -55,10 +55,13 @@ import net.shibboleth.utilities.java.support.resolver.CriteriaSet; import net.shibboleth.utilities.java.support.resolver.ResolverException; @Slf4j -public abstract class AbstractChainingMetadataProvider implements IGarbageCollectorProcessing, IRefreshableMetadataProvider, +public abstract class AbstractChainingMetadataProvider implements IGarbageCollectorProcessing, + IRefreshableMetadataProvider, IDestroyableObject, IPvp2MetadataProvider, ClearableMetadataResolver { - - @Nonnull @NonnullElements private final List<MetadataResolver> internalResolvers; + + @Nonnull + @NonnullElements + private final List<MetadataResolver> internalResolvers; private DateTime lastRefeshTimestamp; private boolean lastRefeshSuccessful; private static Object mutex = new Object(); @@ -72,7 +75,6 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec } - /* * (non-Javadoc) * @@ -104,8 +106,6 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec } - - @Override public synchronized boolean refreshMetadataProvider(final String entityId) { try { @@ -130,7 +130,7 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec // check if MetadataProvider is actually loaded final MetadataResolver loadedResover = actuallyLoadedResolver.get(metadataUrl); if (loadedResover instanceof RefreshableMetadataResolver) { - ((RefreshableMetadataResolver)loadedResover).refresh(); + ((RefreshableMetadataResolver) loadedResover).refresh(); log.info("SAML2 metadata for service provider: " + entityId + " is refreshed."); return true; @@ -162,30 +162,29 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec * */ public void internalDestroy() { - log.info("Destroying chained metadata resolvers ..."); + log.info("Destroying chained metadata resolvers ..."); - for (final MetadataResolver resolver : internalResolvers) { - destroyMetadataResolver(resolver); - } + for (final MetadataResolver resolver : internalResolvers) { + destroyMetadataResolver(resolver); + } - internalResolvers.clear(); + internalResolvers.clear(); } - /** {@inheritDoc} */ - @Override + @Override public final MetadataFilter getMetadataFilter() { - log.warn("{} does NOT support {}", AbstractChainingMetadataProvider.class.getName(), - MetadataFilter.class.getName()); - return null; + log.warn("{} does NOT support {}", AbstractChainingMetadataProvider.class.getName(), + MetadataFilter.class.getName()); + return null; } - /** {@inheritDoc} */ - @Override + @Override public final void setMetadataFilter(final MetadataFilter newFilter) { log.warn("{} does NOT support {}", AbstractChainingMetadataProvider.class.getName(), MetadataFilter.class.getName()); - throw new UnsupportedOperationException("Metadata filters are not supported on AbstractChainingMetadataProvider"); + throw new UnsupportedOperationException( + "Metadata filters are not supported on AbstractChainingMetadataProvider"); } /* @@ -221,17 +220,17 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec } @Override - @Nullable + @Nullable public final EntityDescriptor resolveSingle(@Nullable final CriteriaSet criteria) throws ResolverException { for (final MetadataResolver resolver : internalResolvers) { try { - final EntityDescriptor descriptors = resolver.resolveSingle(criteria); - if (descriptors != null) { - return descriptors; - } + final EntityDescriptor descriptors = resolver.resolveSingle(criteria); + if (descriptors != null) { + return descriptors; + } } catch (final ResolverException e) { - continue; + continue; } @@ -242,87 +241,90 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec } @Override - @Nonnull - public final Iterable<EntityDescriptor> resolve(@Nullable final CriteriaSet criteria) throws ResolverException { - for (final MetadataResolver resolver : internalResolvers) { - try { - final Iterable<EntityDescriptor> descriptors = resolver.resolve(criteria); - if (descriptors != null && descriptors.iterator().hasNext()) { - return descriptors; - - } - - } catch (final ResolverException e) { - continue; - - } + @Nonnull + public final Iterable<EntityDescriptor> resolve(@Nullable final CriteriaSet criteria) + throws ResolverException { + for (final MetadataResolver resolver : internalResolvers) { + try { + final Iterable<EntityDescriptor> descriptors = resolver.resolve(criteria); + if (descriptors != null && descriptors.iterator().hasNext()) { + return descriptors; + + } + + } catch (final ResolverException e) { + continue; + } + } - return Collections.emptyList(); + return Collections.emptyList(); } - + @Override public final void clear() throws ResolverException { - for (final MetadataResolver resolver : internalResolvers) { - if (resolver instanceof ClearableMetadataResolver) { - ((ClearableMetadataResolver) resolver).clear(); - } + for (final MetadataResolver resolver : internalResolvers) { + if (resolver instanceof ClearableMetadataResolver) { + ((ClearableMetadataResolver) resolver).clear(); } + } } @Override public final void clear(String entityID) throws ResolverException { - for (final MetadataResolver resolver : internalResolvers) { - if (resolver instanceof ClearableMetadataResolver) { - ((ClearableMetadataResolver) resolver).clear(entityID); - } + for (final MetadataResolver resolver : internalResolvers) { + if (resolver instanceof ClearableMetadataResolver) { + ((ClearableMetadataResolver) resolver).clear(entityID); } + } } - @Override final public void refresh() throws ResolverException { - this.lastRefeshSuccessful = false; - for (final MetadataResolver resolver : internalResolvers) { - if (resolver instanceof RefreshableMetadataResolver) { - ((RefreshableMetadataResolver) resolver).refresh(); - - } + @Override + public final void refresh() throws ResolverException { + this.lastRefeshSuccessful = false; + for (final MetadataResolver resolver : internalResolvers) { + if (resolver instanceof RefreshableMetadataResolver) { + ((RefreshableMetadataResolver) resolver).refresh(); + } - - this.lastRefeshTimestamp = DateTime.now(); - this.lastRefeshSuccessful = true; + } + + this.lastRefeshTimestamp = DateTime.now(); + this.lastRefeshSuccessful = true; } @Override - @Nullable public DateTime getLastUpdate() { - DateTime ret = null; - for (final MetadataResolver resolver : internalResolvers) { - if (resolver instanceof RefreshableMetadataResolver) { - final DateTime lastUpdate = ((RefreshableMetadataResolver) resolver).getLastUpdate(); - if (ret == null || ret.isBefore(lastUpdate)) { - ret = lastUpdate; - } - } + @Nullable + public DateTime getLastUpdate() { + DateTime ret = null; + for (final MetadataResolver resolver : internalResolvers) { + if (resolver instanceof RefreshableMetadataResolver) { + final DateTime lastUpdate = ((RefreshableMetadataResolver) resolver).getLastUpdate(); + if (ret == null || ret.isBefore(lastUpdate)) { + ret = lastUpdate; + } } - - return ret; + } + + return ret; } @Override - @Nullable final public DateTime getLastRefresh() { - DateTime ret = null; - for (final MetadataResolver resolver : internalResolvers) { - if (resolver instanceof RefreshableMetadataResolver) { - final DateTime lastRefresh = ((RefreshableMetadataResolver) resolver).getLastRefresh(); - if (ret == null || ret.isBefore(lastRefresh)) { - ret = lastRefresh; - } - } + @Nullable + public final DateTime getLastRefresh() { + DateTime ret = null; + for (final MetadataResolver resolver : internalResolvers) { + if (resolver instanceof RefreshableMetadataResolver) { + final DateTime lastRefresh = ((RefreshableMetadataResolver) resolver).getLastRefresh(); + if (ret == null || ret.isBefore(lastRefresh)) { + ret = lastRefresh; + } } - - return ret; + } + + return ret; } - - + /** * Get the URL to metadata for a specific entityID. * @@ -354,103 +356,92 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec protected abstract List<String> getAllMetadataUrlsFromConfiguration() throws EaafConfigurationException; - /** * Get a Id for this metadata provider. - * + * * @return */ @Nonnull protected abstract String getMetadataProviderId(); - + protected final MetadataResolver getMetadataResolver() { log.warn("{} does NOT support 'getMetadataResolver'", AbstractChainingMetadataProvider.class.getName()); return null; - + } - + private Map<String, MetadataResolver> getAllActuallyLoadedResolvers() { final Map<String, MetadataResolver> loadedproviders = new HashMap<>(); // make a Map of all actually loaded HTTPMetadataProvider for (final MetadataResolver resolver : internalResolvers) { - if (resolver instanceof IdentifiedComponent) { - loadedproviders.put(((IdentifiedComponent) resolver).getId(), resolver); - - } else { - final String uuid = UUID.randomUUID().toString(); - loadedproviders.put(uuid, resolver); - log.debug("MetadatenResolver is not of type: {}. Mark it with id: {}", - IdentifiedComponent.class.getSimpleName(), uuid); + loadedproviders.put(((IdentifiedComponent) resolver).getId(), resolver); - } } return loadedproviders; } private void addAndRemoveMetadataProvider() throws EaafConfigurationException { - log.info("EAAF chaining metadata resolver starting internal managment task .... "); + log.info("EAAF chaining metadata resolver starting internal managment task .... "); + + /* + * OpenSAML ChainingMetadataProvider can not remove a MetadataProvider + * (UnsupportedOperationException) The ChainingMetadataProvider use internal a + * unmodifiableList to hold all registrated MetadataProviders. + */ + final Map<String, MetadataResolver> providersinuse = new HashMap<>(); + + // get all actually loaded metadata providers + final Map<String, MetadataResolver> loadedproviders = getAllActuallyLoadedResolvers(); + + /* + * TODO: maybe add metadata provider destroy after timeout. But could be a + * problem if one Metadataprovider load an EntitiesDescriptor with more the + * multiple EntityDescriptors. If one of this EntityDesciptors are expired the + * full EntitiesDescriptor is removed. + * + * Timeout requires a better solution in this case! + */ + + // load all SAML2 SPs form configuration and + // compare actually loaded Providers with configured SAML2 SPs + final List<String> allMetadataUrls = getAllMetadataUrlsFromConfiguration(); + + final Iterator<String> metadataUrlInterator = allMetadataUrls.iterator(); + while (metadataUrlInterator.hasNext()) { + final String metadataurl = metadataUrlInterator.next(); + try { + if (StringUtils.isNotEmpty(metadataurl) + && loadedproviders.containsKey(metadataurl)) { + // SAML2 SP is actually loaded, to nothing + providersinuse.put(metadataurl, loadedproviders.get(metadataurl)); + loadedproviders.remove(metadataurl); + + } + } catch (final Throwable e) { + log.error("Failed to add Metadata (unhandled reason: " + e.getMessage(), e); + + } + } + + // remove all actually loaded MetadataProviders with are not in ConfigurationDB + // any more + final Collection<MetadataResolver> notusedproviders = loadedproviders.values(); + for (final MetadataResolver resolver : notusedproviders) { + log.info("Remove not used MetadataProvider with MetadataURL " + resolver.getId()); + destroyMetadataResolver(resolver); + internalResolvers.remove(resolver); /* * OpenSAML ChainingMetadataProvider can not remove a MetadataProvider * (UnsupportedOperationException) The ChainingMetadataProvider use internal a * unmodifiableList to hold all registrated MetadataProviders. */ - final Map<String, MetadataResolver> providersinuse = new HashMap<>(); + // chainProvider.removeMetadataProvider(provider); - // get all actually loaded metadata providers - final Map<String, MetadataResolver> loadedproviders = getAllActuallyLoadedResolvers(); - - /* - * TODO: maybe add metadata provider destroy after timeout. But could be a - * problem if one Metadataprovider load an EntitiesDescriptor with more the - * multiple EntityDescriptors. If one of this EntityDesciptors are expired the - * full EntitiesDescriptor is removed. - * - * Timeout requires a better solution in this case! - */ - - // load all SAML2 SPs form configuration and - // compare actually loaded Providers with configured SAML2 SPs - final List<String> allMetadataUrls = getAllMetadataUrlsFromConfiguration(); - - final Iterator<String> metadataUrlInterator = allMetadataUrls.iterator(); - while (metadataUrlInterator.hasNext()) { - final String metadataurl = metadataUrlInterator.next(); - try { - if (StringUtils.isNotEmpty(metadataurl) - && loadedproviders.containsKey(metadataurl)) { - // SAML2 SP is actually loaded, to nothing - providersinuse.put(metadataurl, loadedproviders.get(metadataurl)); - loadedproviders.remove(metadataurl); - - } - } catch (final Throwable e) { - log.error("Failed to add Metadata (unhandled reason: " + e.getMessage(), e); - - } - } - - - // remove all actually loaded MetadataProviders with are not in ConfigurationDB - // any more - final Collection<MetadataResolver> notusedproviders = loadedproviders.values(); - for (final MetadataResolver resolver : notusedproviders) { - log.info("Remove not used MetadataProvider with MetadataURL " + resolver.getId()); - destroyMetadataResolver(resolver); - internalResolvers.remove(resolver); - - /* - * OpenSAML ChainingMetadataProvider can not remove a MetadataProvider - * (UnsupportedOperationException) The ChainingMetadataProvider use internal a - * unmodifiableList to hold all registrated MetadataProviders. - */ - // chainProvider.removeMetadataProvider(provider); - - - } + } } @@ -474,39 +465,34 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec } } - - @Override public DateTime getLastSuccessfulRefresh() { return this.lastRefeshTimestamp; - - } + } @Override public Boolean wasLastRefreshSuccess() { return this.lastRefeshSuccessful; - - } - - - /** {@inheritDoc} */ - @Override public boolean isRequireValidMetadata() { - log.warn("Attempt to access unsupported requireValidMetadata property on ChainingMetadataResolver"); - return false; } - /** {@inheritDoc} */ - @Override public void setRequireValidMetadata(final boolean requireValidMetadata) { - throw new UnsupportedOperationException("Setting requireValidMetadata is not supported on chaining resolver"); + @Override + public boolean isRequireValidMetadata() { + log.warn("Attempt to access unsupported requireValidMetadata property on ChainingMetadataResolver"); + return false; } + @Override + public void setRequireValidMetadata(final boolean requireValidMetadata) { + throw new UnsupportedOperationException( + "Setting requireValidMetadata is not supported on chaining resolver"); + } @Override public String getId() { return getMetadataProviderId(); - + } - + } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java index bd2b79cb..d2b861dc 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java @@ -1,18 +1,22 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.metadata; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; + import org.joda.time.DateTime; import org.opensaml.core.criterion.EntityIdCriterion; import org.opensaml.saml.metadata.resolver.ExtendedRefreshableMetadataResolver; import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; import org.opensaml.saml.saml2.metadata.EntityDescriptor; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import lombok.extern.slf4j.Slf4j; import net.shibboleth.utilities.java.support.resolver.CriteriaSet; import net.shibboleth.utilities.java.support.resolver.ResolverException; -public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider { - - private ExtendedRefreshableMetadataResolver internalProvider; +@Slf4j +public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider, IRefreshableMetadataProvider { + + private final ExtendedRefreshableMetadataResolver internalProvider; public PvpMetadataResolverAdapter(ExtendedRefreshableMetadataResolver provider) { this.internalProvider = provider; @@ -27,7 +31,7 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider { @Override public DateTime getLastRefresh() { return internalProvider.getLastRefresh(); - + } @Override @@ -38,7 +42,7 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider { @Override public boolean isRequireValidMetadata() { return internalProvider.isRequireValidMetadata(); - + } @Override @@ -50,12 +54,12 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider { @Override public MetadataFilter getMetadataFilter() { return internalProvider.getMetadataFilter(); - + } @Override public void setMetadataFilter(MetadataFilter newFilter) { - internalProvider.setMetadataFilter(newFilter); + internalProvider.setMetadataFilter(newFilter); } @@ -67,7 +71,7 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider { @Override public EntityDescriptor resolveSingle(CriteriaSet criteria) throws ResolverException { return internalProvider.resolveSingle(criteria); - + } @Override @@ -80,7 +84,7 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider { final CriteriaSet criteria = new CriteriaSet(); criteria.add(new EntityIdCriterion(entityId)); return internalProvider.resolveSingle(criteria); - + } @Override @@ -93,4 +97,19 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider { return internalProvider.wasLastRefreshSuccess(); } + @Override + public boolean refreshMetadataProvider(String entityID) { + try { + log.trace("Refeshing metadata-provider: {} ... ", getId()); + internalProvider.refresh(); + return true; + + } catch (final ResolverException e) { + log.warn("Refreshing of metadata-provider: {} failed. Reason: {}", + getId(), e.getMessage()); + return false; + + } + } + } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java index f548bc7b..0b505e56 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java @@ -8,23 +8,31 @@ import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.net.ssl.SSLHandshakeException; +import at.gv.egiz.components.spring.api.IDestroyableObject; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.impl.utils.FileUtils; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SignatureValidationException; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.OpenSaml3ResourceAdapter; + import org.apache.http.client.HttpClient; import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.saml.metadata.resolver.ExtendedRefreshableMetadataResolver; import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; +import org.opensaml.saml.metadata.resolver.impl.AbstractReloadingMetadataResolver; import org.opensaml.saml.metadata.resolver.impl.HTTPMetadataResolver; import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ResourceLoader; -import at.gv.egiz.components.spring.api.IDestroyableObject; -import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.impl.utils.FileUtils; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; -import at.gv.egiz.eaaf.modules.pvp2.exception.SignatureValidationException; -import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.OpenSaml3ResourceAdapter; +import com.google.common.base.Predicates; +import com.google.common.base.Throwables; +import com.google.common.collect.FluentIterable; import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; +import net.shibboleth.utilities.java.support.resolver.ResolverException; import net.shibboleth.utilities.java.support.resource.Resource; import net.shibboleth.utilities.java.support.xml.ParserPool; @@ -34,13 +42,18 @@ public class PvpMetadataResolverFactory implements IDestroyableObject { private static final String URI_PREFIX_HTTP = "http:"; private static final String URI_PREFIX_HTTPS = "https:"; + private static final String NOT_SUCCESS = "Maybe metadata was expired"; + private Timer timer = null; - - @Autowired private IConfiguration authConfig; - @Autowired private ResourceLoader resourceLoader; - + + @Autowired + private IConfiguration authConfig; + @Autowired + private ResourceLoader resourceLoader; + /** - * Create a single SAML2 metadata provider by using the default OpenSAML3 parser-pool. + * Create a single SAML2 metadata provider by using the default OpenSAML3 + * parser-pool. * * @param metadataLocation where the metadata should be loaded, but never null. * If the location starts with http(s):, than a http @@ -54,17 +67,18 @@ public class PvpMetadataResolverFactory implements IDestroyableObject { * * @return SAML2 Metadata Provider, or null if the metadata provider can not * initialized + * @throws Pvp2MetadataException In case of an initialization error */ - @Nullable + @Nullable public IPvp2MetadataProvider createMetadataProvider(@Nonnull final String metadataLocation, @Nullable final MetadataFilter filter, @Nonnull final String idForLogging, - @Nullable final HttpClient httpClient) { - return createMetadataProvider(metadataLocation, filter, idForLogging, - XMLObjectProviderRegistrySupport.getParserPool(), - httpClient); - + @Nullable final HttpClient httpClient) throws Pvp2MetadataException { + return createMetadataProvider(metadataLocation, filter, idForLogging, + XMLObjectProviderRegistrySupport.getParserPool(), + httpClient); + } - + /** * Create a single SAML2 metadata provider. * @@ -80,57 +94,74 @@ public class PvpMetadataResolverFactory implements IDestroyableObject { * * @return SAML2 Metadata Provider, or null if the metadata provider can not * initialized + * @throws Pvp2MetadataException In case of an initialization error */ - @Nullable + @Nullable public IPvp2MetadataProvider createMetadataProvider(@Nonnull final String metadataLocation, @Nullable final MetadataFilter filter, @Nonnull final String idForLogging, - @Nullable final ParserPool pool, @Nullable final HttpClient httpClient) { - + @Nullable final ParserPool pool, @Nullable final HttpClient httpClient) throws Pvp2MetadataException { + ExtendedRefreshableMetadataResolver internalProvider = null; - - if (metadataLocation.startsWith(URI_PREFIX_HTTP) - || metadataLocation.startsWith(URI_PREFIX_HTTPS)) { - if (httpClient != null) { - internalProvider = createNewHttpMetaDataProvider(metadataLocation, filter, idForLogging, timer, pool, - httpClient); + + try { + if (metadataLocation.startsWith(URI_PREFIX_HTTP) + || metadataLocation.startsWith(URI_PREFIX_HTTPS)) { + internalProvider = createNewHttpMetaDataProvider(metadataLocation, filter, + idForLogging, timer, pool, httpClient); + } else { - log.warn("Can not load http(s) based SAML2 metadata without a HTTP client"); - + final String absoluteMetadataLocation = + FileUtils.makeAbsoluteUrl(metadataLocation, authConfig.getConfigurationRootDirectory()); + final org.springframework.core.io.Resource resource = + resourceLoader.getResource(absoluteMetadataLocation); + + if (resource.exists()) { + internalProvider = createNewFileSystemMetaDataProvider( + new OpenSaml3ResourceAdapter(resource), + filter, idForLogging, timer, + pool); + + } else { + log.warn( + "SAML2 metadata file: {} not found or not exist", absoluteMetadataLocation); + throw new Pvp2MetadataException("internal.pvp.05", + new Object[] { absoluteMetadataLocation, "File NOT found or exist." }); + + } } - } else { - String absoluteMetadataLocation; - try { - absoluteMetadataLocation = - FileUtils.makeAbsoluteUrl(metadataLocation, authConfig.getConfigurationRootDirectory()); + } catch (final ComponentInitializationException e) { + log.warn("Failed to load Metadata file for {} [ {} ]", + idForLogging, e.getMessage()); + checkResolverInitializationError(e, metadataLocation); - org.springframework.core.io.Resource resource = resourceLoader.getResource(absoluteMetadataLocation); - if (resource.exists()) { - internalProvider = createNewFileSystemMetaDataProvider( - new OpenSaml3ResourceAdapter(resource), - filter, idForLogging, timer, - pool); - } else { - log.warn( - "SAML2 metadata file: " + absoluteMetadataLocation + " not found or not exist"); - - } + } catch (final Exception e) { + throw new Pvp2MetadataException("internal.pvp.09", new Object[] { metadataLocation, e.getMessage() }); + } - } catch (final IOException e) { - log.warn("SAML2 metadata URL is invalid: " + metadataLocation, e); + if (!internalProvider.wasLastRefreshSuccess()) { + log.info("Metadata loading from source: {} failed. {}", metadataLocation, NOT_SUCCESS); + throw new Pvp2MetadataException("internal.pvp.09", new Object[] { metadataLocation, NOT_SUCCESS }); - } } - if (internalProvider != null) { - return new PvpMetadataResolverAdapter(internalProvider); - - } else { - log.warn("SAML2 metadata has an unsupported metadata location prefix: " + metadataLocation); - return null; - + return new PvpMetadataResolverAdapter(internalProvider); + + } + + @Override + public void fullyDestroy() { + if (timer != null) { + log.info("Stopping timer-thread for PVP metadata resolver ... "); + timer.cancel(); } + } + + @PostConstruct + private void initialize() { + log.info("Initializing timer-thread for PVP metadata resolver ... "); + timer = new Timer("PVP metadata-resolver refresh"); } @@ -142,55 +173,26 @@ public class PvpMetadataResolverFactory implements IDestroyableObject { * @param idForLogging Id, which is used for Logging * @param timer {@link Timer} which is used to schedule metadata refresh * operations - * @param pool + * @param pool SAML2 parser pool that should be used * * @return SAML2 Metadata Provider - * @throws IOException + * @throws IOException In case of a metadata resource error + * @throws ComponentInitializationException In case of a metadata resolver + * initialization error */ private ExtendedRefreshableMetadataResolver createNewFileSystemMetaDataProvider(final Resource metadataFile, final MetadataFilter filter, final String idForLogging, final Timer timer, - final ParserPool pool) throws IOException { + final ParserPool pool) throws IOException, ComponentInitializationException { ResourceBackedMetadataResolver fileSystemResolver = null; - try { - //fileSystemResolver = new FilesystemMetadataResolver(timer, metadataFile); - - fileSystemResolver = new ResourceBackedMetadataResolver(timer, metadataFile); - - if (pool != null) { - fileSystemResolver.setParserPool(pool); - - } else { - fileSystemResolver.setParserPool( - XMLObjectProviderRegistrySupport.getParserPool()); - - } - fileSystemResolver.setRequireValidMetadata(true); - fileSystemResolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes - fileSystemResolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours - - fileSystemResolver.setMetadataFilter(filter); - fileSystemResolver.initialize(); - fileSystemResolver.setId(metadataFile.getURI().toASCIIString()); - - fileSystemResolver.setRequireValidMetadata(true); - - return fileSystemResolver; - - } catch (final Exception e) { - log.warn("Failed to load Metadata file for " + idForLogging + "[ " + "File: " - + metadataFile.getURI().toASCIIString() + " Msg: " + e.getMessage() + " ]", e); - - log.warn("Can not initialize SAML2 metadata provider from filesystem: " - + metadataFile.getURI().toASCIIString() + " Reason: " + e.getMessage(), e); + fileSystemResolver = new ResourceBackedMetadataResolver(timer, metadataFile); + injectMetadataResolverConfiguration(fileSystemResolver, filter, pool); + fileSystemResolver.setId(metadataFile.getURI().toASCIIString()); + fileSystemResolver.initialize(); - if (fileSystemResolver != null) { - fileSystemResolver.destroy(); + log.trace("Set-up metadata-resolver with ID: {} as: {}", + idForLogging, fileSystemResolver.getClass().getSimpleName()); - } - - } - - return null; + return fileSystemResolver; } @@ -202,70 +204,75 @@ public class PvpMetadataResolverFactory implements IDestroyableObject { * @param idForLogging Id, which is used for Logging * @param timer {@link Timer} which is used to schedule metadata refresh * operations - * @param pool - * + * @param pool SAML2 parser pool that should be used * @return SAML2 Metadata Provider + * @throws ComponentInitializationException In case of a metadata resolver + * initialization error + * @throws ResolverException In case of an internal OpenSAML + * resolver error */ private ExtendedRefreshableMetadataResolver createNewHttpMetaDataProvider(final String metadataUrl, final MetadataFilter filter, final String idForLogging, final Timer timer, - final ParserPool pool, final HttpClient httpClient) { + final ParserPool pool, final HttpClient httpClient) throws ComponentInitializationException, + ResolverException { HTTPMetadataResolver httpMetadataResolver = null; - try { - httpMetadataResolver = new HTTPMetadataResolver(timer, httpClient, metadataUrl); - httpMetadataResolver.setParserPool(pool); - httpMetadataResolver.setRequireValidMetadata(true); - httpMetadataResolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes - httpMetadataResolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours - // httpProvider.setRefreshDelayFactor(0.1F); + httpMetadataResolver = new HTTPMetadataResolver(timer, httpClient, metadataUrl); + injectMetadataResolverConfiguration(httpMetadataResolver, filter, pool); + httpMetadataResolver.setId(metadataUrl); + httpMetadataResolver.initialize(); - httpMetadataResolver.setMetadataFilter(filter); - httpMetadataResolver.setId(metadataUrl); - httpMetadataResolver.initialize(); + log.trace("Set-up metadata-resolver with ID: {} as: {}", + idForLogging, httpMetadataResolver.getClass().getSimpleName()); - httpMetadataResolver.setRequireValidMetadata(true); + return httpMetadataResolver; - return httpMetadataResolver; + } - } catch (final Throwable e) { - if (e.getCause() != null && e.getCause().getCause() instanceof SSLHandshakeException) { - log.warn("SSL-Server certificate for metadata " + metadataUrl + " not trusted.", e); + private void injectMetadataResolverConfiguration(AbstractReloadingMetadataResolver resolver, + final MetadataFilter filter, final ParserPool pool) { + if (pool != null) { + resolver.setParserPool(pool); - } - if (e.getCause() != null && e.getCause().getCause() instanceof SignatureValidationException) { - log.warn("Signature verification for metadata" + metadataUrl + " FAILED.", e); + } else { + resolver.setParserPool( + XMLObjectProviderRegistrySupport.getParserPool()); - } - if (e.getCause() != null && e.getCause().getCause() instanceof SchemaValidationException) { - log.warn("Schema validation for metadata " + metadataUrl + " FAILED.", e); - } + } + + resolver.setRequireValidMetadata(true); + resolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes + resolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours + resolver.setMetadataFilter(filter); + + } - log.warn("Failed to load Metadata file for " + idForLogging + "[ " + e.getMessage() + " ]", + private void checkResolverInitializationError(ComponentInitializationException e, String metadataLocation) + throws Pvp2MetadataException { + if (FluentIterable.from(Throwables.getCausalChain(e)).filter( + Predicates.instanceOf(SSLHandshakeException.class)).first().isPresent()) { + log.info("SSL-Server certificate for metadata: {} not trusted.", metadataLocation, null, e); + throw new Pvp2MetadataException("internal.pvp.06", new Object[] { metadataLocation, e.getMessage() }, e); - if (httpMetadataResolver != null) { - log.debug("Destroy failed Metadata provider"); - httpMetadataResolver.destroy(); + } else if (FluentIterable.from(Throwables.getCausalChain(e)).filter( + Predicates.instanceOf(SignatureValidationException.class)).first().isPresent()) { + log.info("Signature verification for metadata: {} FAILED.", metadataLocation, null, e); + throw new Pvp2MetadataException("internal.pvp.07", new Object[] { metadataLocation, e.getMessage() }, + e); - } + } else if (FluentIterable.from(Throwables.getCausalChain(e)).filter( + Predicates.instanceOf(SchemaValidationException.class)).first().isPresent()) { + log.info("Schema validation for metadata: {} FAILED.", metadataLocation, null, e); + throw new Pvp2MetadataException("internal.pvp.08", new Object[] { metadataLocation, e.getMessage() }, + e); + + } else { + log.info("Generic initialization error for metadata: {}", metadataLocation, null, e); + throw new Pvp2MetadataException("internal.pvp.09", new Object[] { metadataLocation, e.getMessage() }, + e); } - return null; } - @Override - public void fullyDestroy() { - if (timer != null) { - log.info("Stopping timer-thread for PVP metadata resolver ... "); - timer.cancel(); - } - } - - @PostConstruct - private void initialize() { - log.info("Initializing timer-thread for PVP metadata resolver ... "); - timer = new Timer("PVP metadata-resolver refresh"); - - } - } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java index d23affba..fdd44b9a 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java @@ -2,18 +2,18 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.io.UnsupportedEncodingException; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SamlHttpUtils; + import org.opensaml.core.xml.XMLObject; import org.opensaml.messaging.decoder.MessageDecodingException; import org.opensaml.saml.saml2.binding.decoding.impl.HTTPPostDecoder; import com.google.common.base.Strings; - -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import lombok.extern.slf4j.Slf4j; import net.shibboleth.utilities.java.support.codec.Base64Support; @@ -27,14 +27,22 @@ import net.shibboleth.utilities.java.support.codec.Base64Support; @Slf4j public class EaafHttpPostDecoder extends HTTPPostDecoder { + private static final String SAML_REQ_PARAM_NAME = "SAMLRequest"; + private static final String SAML_RESP_PARAM_NAME = "SAMLResponse"; + + public EaafHttpPostDecoder(HttpServletRequest req) { + setHttpServletRequest(req); + } + @Override protected InputStream getBase64DecodedMessage(final HttpServletRequest request) throws MessageDecodingException { log.debug("Getting Base64 encoded message from request"); - String encodedMessage = getLastParameterFromRequest(request, "SAMLRequest"); + String encodedMessage = SamlHttpUtils.getLastParameterFromRequest(request, SAML_REQ_PARAM_NAME); if (Strings.isNullOrEmpty(encodedMessage)) { - encodedMessage = getLastParameterFromRequest(request, "SAMLResponse"); + encodedMessage = SamlHttpUtils.getLastParameterFromRequest(request, SAML_RESP_PARAM_NAME); + } if (Strings.isNullOrEmpty(encodedMessage)) { @@ -43,14 +51,17 @@ public class EaafHttpPostDecoder extends HTTPPostDecoder { throw new MessageDecodingException("No SAML message present in request"); } - log.trace("Base64 decoding SAML message:\n{}", encodedMessage); + log.trace("Base64 decoding SAML message: {}", encodedMessage); final byte[] decodedBytes = Base64Support.decode(encodedMessage); - if (decodedBytes == null) { - log.info("Unable to Base64 decode SAML message"); - throw new MessageDecodingException("Unable to Base64 decode SAML message"); + + try { + log.trace("Decoded SAML message: {}", new String(decodedBytes, "UTF-8")); + + } catch (final UnsupportedEncodingException e) { + log.warn("Logging of incomming message failed", e); + } - log.trace("Decoded SAML message:\n{}", new String(decodedBytes)); return new ByteArrayInputStream(decodedBytes); } @@ -61,31 +72,8 @@ public class EaafHttpPostDecoder extends HTTPPostDecoder { */ @Override protected XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException { - return Saml2Utils.unmarshallMessage(messageStream); - - } - - /** - * Always read the last parameter with this name from request to get a strict - * deterministic behavior. <br> - * <br> - * <b><i>If more than one parameters with the same name exists, this method - * always select the last parameter value.</i></b> - * - * @param request Incoming http request - * @param paramName Name of the http parameter - * @return the last parameter value with this name, or <code>null</code> if the - * parameter not exists - */ - @Nullable - private String getLastParameterFromRequest(@Nonnull HttpServletRequest request, @Nonnull String paramName) { - final String[] values = request.getParameterValues(paramName); - if (values != null && values.length > 0) { - return values[values.length - 1]; - - } - - return null; + return Saml2Utils.unmarshallMessage(messageStream); } + } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java index 16d73296..c5174f02 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java @@ -4,6 +4,9 @@ import java.io.InputStream; import javax.servlet.http.HttpServletRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SamlHttpUtils; + import org.opensaml.core.xml.XMLObject; import org.opensaml.messaging.context.MessageContext; import org.opensaml.messaging.decoder.MessageDecodingException; @@ -13,10 +16,7 @@ import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.saml2.binding.decoding.impl.HTTPRedirectDeflateDecoder; import com.google.common.base.Strings; - -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import lombok.extern.slf4j.Slf4j; -import net.shibboleth.utilities.java.support.net.URISupport; import net.shibboleth.utilities.java.support.primitive.StringSupport; /** @@ -29,6 +29,14 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport; @Slf4j public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder { + private static final String SAML_REQ_PARAM_NAME = "SAMLRequest"; + private static final String SAML_RESP_PARAM_NAME = "SAMLResponse"; + + public EaafHttpRedirectDeflateDecoder(HttpServletRequest req) { + setHttpServletRequest(req); + + } + @Override protected void doDecode() throws MessageDecodingException { final MessageContext<SAMLObject> messageContext = new MessageContext<>(); @@ -52,16 +60,19 @@ public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder { // implement parameter extraction as same as in // SAML2HTTPRedirectDeflateSignatureSecurityHandler.java - final String queryString = getHttpServletRequest().getQueryString(); - if (!Strings.isNullOrEmpty(URISupport.getRawQueryStringParameter(queryString, "SAMLRequest"))) { - samlMessageIns = decodeMessage(URISupport.getRawQueryStringParameter(queryString, "SAMLRequest")); - } else if (!Strings.isNullOrEmpty(URISupport.getRawQueryStringParameter(queryString, "SAMLResponse"))) { - samlMessageIns = decodeMessage(URISupport.getRawQueryStringParameter(queryString, "SAMLResponse")); + final String samlReq = SamlHttpUtils.getLastParameterFromRequest(request, SAML_REQ_PARAM_NAME); + final String samlResp = SamlHttpUtils.getLastParameterFromRequest(request, SAML_RESP_PARAM_NAME); + if (!Strings.isNullOrEmpty(samlReq)) { + samlMessageIns = decodeMessage(samlReq); + + } else if (!Strings.isNullOrEmpty(samlResp)) { + samlMessageIns = decodeMessage(samlResp); + } else { throw new MessageDecodingException( "No SAMLRequest or SAMLResponse query path parameter, invalid SAML 2 HTTP Redirect message"); } - + final SAMLObject samlMessage = (SAMLObject) unmarshallMessage(samlMessageIns); messageContext.setMessage(samlMessage); log.debug("Decoded SAML message"); @@ -69,9 +80,9 @@ public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder { populateBindingContext(messageContext); setMessageContext(messageContext); - + } - + /** * EAAF specific unmarshaller perform XML schema validation before unmarshalling * the SAML message. @@ -79,8 +90,8 @@ public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder { */ @Override protected XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException { - return Saml2Utils.unmarshallMessage(messageStream); - + return Saml2Utils.unmarshallMessage(messageStream); + } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafKeyStoreX509CredentialAdapter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafKeyStoreX509CredentialAdapter.java index 7c433c1c..6d81700a 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafKeyStoreX509CredentialAdapter.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafKeyStoreX509CredentialAdapter.java @@ -50,21 +50,24 @@ public class EaafKeyStoreX509CredentialAdapter extends KeyStoreX509CredentialAda /** * Get an OpenSAML2 keystore. * - * @param store Java KeyStore - * @param alias Key alias - * @param password key Password - * @param keyStoreFriendlyName Friendlyname of this keystore for logging purposes - * @throws CredentialsNotAvailableException In case of an initialization exception + * @param store Java KeyStore + * @param alias Key alias + * @param password key Password + * @param keyStoreFriendlyName Friendlyname of this keystore for logging + * purposes + * @throws CredentialsNotAvailableException In case of an initialization + * exception */ public EaafKeyStoreX509CredentialAdapter(@Nonnull final KeyStore store, @Nonnull final String alias, - @Nullable final char[] password, @Nonnull String keyStoreFriendlyName) throws CredentialsNotAvailableException { + @Nullable final char[] password, @Nonnull String keyStoreFriendlyName) + throws CredentialsNotAvailableException { super(store, alias, password); if (getPrivateKey() == null && getSecretKey() == null) { log.error("KeyStore: {} Key with alias: {} not found or contains no PrivateKey.", keyStoreFriendlyName, alias); throw new CredentialsNotAvailableException("internal.pvp.00", - new Object[] { keyStoreFriendlyName, alias}); + new Object[] { keyStoreFriendlyName, alias }); } @@ -74,7 +77,8 @@ public class EaafKeyStoreX509CredentialAdapter extends KeyStoreX509CredentialAda PvpConstants.DEFAULT_SIGNING_METHODE_EC)); } catch (final SamlSigningException e) { - throw new CredentialsNotAvailableException("internal.pvp.01", new Object[] {keyStoreFriendlyName, alias}, e); + throw new CredentialsNotAvailableException("internal.pvp.01", new Object[] { keyStoreFriendlyName, + alias }, e); } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HttpPostEncoderWithOwnTemplate.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HttpPostEncoderWithOwnTemplate.java index 3650e617..fa77b73c 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HttpPostEncoderWithOwnTemplate.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HttpPostEncoderWithOwnTemplate.java @@ -19,7 +19,6 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java index 2e45aea2..f474267f 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java @@ -9,22 +9,23 @@ import java.net.URL; import net.shibboleth.utilities.java.support.resource.Resource; /** - * Adapter that connects a Spring {@link org.springframework.core.io.Resource} to a {@link Resource}. - * + * Adapter that connects a Spring {@link org.springframework.core.io.Resource} + * to a {@link Resource}. + * * @author tlenz * */ public class OpenSaml3ResourceAdapter implements Resource { - private org.springframework.core.io.Resource internalResource; + private final org.springframework.core.io.Resource internalResource; public OpenSaml3ResourceAdapter(org.springframework.core.io.Resource resource) { this.internalResource = resource; } - + @Override public boolean exists() { - return internalResource.exists(); + return internalResource.exists(); } @Override diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java index bd450518..38735fb8 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java @@ -23,8 +23,8 @@ import org.opensaml.messaging.context.MessageContext; import org.opensaml.messaging.encoder.MessageEncodingException; import org.opensaml.saml.common.SAMLObject; import org.opensaml.saml.saml2.binding.encoding.impl.HTTPRedirectDeflateEncoder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import lombok.extern.slf4j.Slf4j; /** * Create deflate encoded SAML2 redirect-binding informations. @@ -32,9 +32,9 @@ import org.slf4j.LoggerFactory; * @author tlenz * */ -public class StringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder { - private static final Logger log = LoggerFactory.getLogger(StringRedirectDeflateEncoder.class); +@Slf4j +public class StringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder { private String redirectUrl = null; @Override @@ -50,6 +50,8 @@ public class StringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder { redirectUrl = buildRedirectURL(messageContext, endpointUrl, encodedMessage); + log.trace("SAML2 redirect-binding URL was generated as: {}", redirectUrl); + } /** diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java index 42d4d736..5c6d861d 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java @@ -60,10 +60,12 @@ public class EaafOpenSaml3xInitializer extends InitializationService { /** * EAAF specific OpenSAML3.x initialization. * - * @throws InitializationException In case of an error - * @throws ComponentInitializationException + * @throws InitializationException In case of an error + * @throws ComponentInitializationException In case of an OpenSAML3 + * initialization error */ - public static synchronized void eaafInitialize() throws InitializationException, ComponentInitializationException { + public static synchronized void eaafInitialize() throws InitializationException, + ComponentInitializationException { log.debug("Initializing OpenSAML 3.x ... "); initialize(); diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QaaLevelVerifier.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QaaLevelVerifier.java index 31ffd5a7..ca6f29e4 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QaaLevelVerifier.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QaaLevelVerifier.java @@ -21,13 +21,13 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.utils; import java.util.List; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.modules.pvp2.exception.QaaNotAllowedException; + import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.eaaf.core.api.data.EaafConstants; -import at.gv.egiz.eaaf.modules.pvp2.exception.QaaNotAllowedException; - /** * EAAF LoA Level verifier checks if requested LoA matchs to LoA of * authentication. diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java index 763c07f6..dc7e9338 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java @@ -37,6 +37,14 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.Validator; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; + import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.opensaml.core.xml.XMLObject; @@ -82,13 +90,6 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import at.gv.egiz.eaaf.core.impl.utils.DomUtils; -import at.gv.egiz.eaaf.core.impl.utils.Random; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; -import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; -import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; -import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; import net.shibboleth.utilities.java.support.xml.QNameSupport; import net.shibboleth.utilities.java.support.xml.SerializeSupport; @@ -114,13 +115,14 @@ public class Saml2Utils { } /** - * Sign a OpenSAML 3.x object with a {@link X509Credential}. - * <br> - * <p>This method used {@link PvpConstants.DEFAULT_SIGNING_METHODE_RSA} - * or {@link PvpConstants.DEFAULT_SIGNING_METHODE_EC} as algorithm</p> + * Sign a OpenSAML 3.x object with a {@link X509Credential}. <br> + * <p> + * This method used {@link PvpConstants.DEFAULT_SIGNING_METHODE_RSA} or + * {@link PvpConstants.DEFAULT_SIGNING_METHODE_EC} as algorithm + * </p> * - * @param <T> {@link SignableXMLObject} - * @param toSign object that should be signed + * @param <T> {@link SignableXMLObject} + * @param toSign object that should be signed * @param signingCredential Credentials that should be used for signing * @param injectCertificate true, if certificate should be part of the signature * @return Signed object @@ -157,18 +159,20 @@ public class Saml2Utils { } catch (final SignatureException | MarshallingException | SecurityException e) { throw new SamlSigningException("internal.pvp.96", - new Object[] {signingCredential.getEntityId(), e.getMessage()}, e); + new Object[] { signingCredential.getEntityId(), e.getMessage() }, e); } } /** - * SAML2 message unmarshaller that performs schema validation before unmarshall the message. - * + * SAML2 message unmarshaller that performs schema validation before unmarshall + * the message. + * * @param messageStream SAML2 message that shoulld be unmarshalled * @return OpenSAML XML object - * @throws MessageDecodingException In case of a schema-validation or unmarshalling error + * @throws MessageDecodingException In case of a schema-validation or + * unmarshalling error */ public static XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException { try { @@ -201,22 +205,24 @@ public class Saml2Utils { } catch (ParserConfigurationException | SAXException e) { log.warn("Message schema-validation failed."); - throw new MessageDecodingException("Message schema-validation failed.", + throw new MessageDecodingException("Message schema-validation failed.", new SchemaValidationException("internal.pvp.03", new Object[] { e.getMessage() }, e)); } catch (final IOException e) { log.error("Error read message from input stream", e); throw new MessageDecodingException("Error read message from input stream", e); - + } } - + /** * Select signature algorithm for a given credential. * - * @param credentials {@link X509Credential} that will be used for signing - * @param rsaSigAlgorithm RSA based signing algorithm that should be used in case of RSA credential - * @param ecSigAlgorithm EC based signing algorithm that should be used in case of RSA credential + * @param credentials {@link X509Credential} that will be used for signing + * @param rsaSigAlgorithm RSA based signing algorithm that should be used in + * case of RSA credential + * @param ecSigAlgorithm EC based signing algorithm that should be used in case + * of RSA credential * @return either the rsaSigAlgorithm or the ecSigAlgorithm * @throws SamlSigningException In case of an unsupported credential */ @@ -233,7 +239,7 @@ public class Saml2Utils { log.warn("Could NOT evaluate the Private-Key type from " + credentials.getEntityId() + " credential."); throw new SamlSigningException("internal.pvp.97", - new Object[] {credentials.getEntityId(), privatekey.getClass().getName()}); + new Object[] { credentials.getEntityId(), privatekey.getClass().getName() }); } } @@ -263,14 +269,16 @@ public class Saml2Utils { } /** - * Get a {@link KeyInfoGenerator} that injects key information into XML signature. + * Get a {@link KeyInfoGenerator} that injects key information into XML + * signature. * - * @param credential @link X509Credential} that will be used for signing - * @param injectCertificate Set <code>true</code> if the certificate should be added to KeyInfo + * @param credential @link X509Credential} that will be used for signing + * @param injectCertificate Set <code>true</code> if the certificate should be + * added to KeyInfo * @return Generator for a XML signature key-information */ public static KeyInfoGenerator getKeyInfoGenerator(X509Credential credential, boolean injectCertificate) { - //OpenSAML3 only support RSA and DSA for direct key injection + // OpenSAML3 only support RSA and DSA for direct key injection KeyInfoGeneratorFactory keyInfoGenFac = null; if (injectCertificate || credential.getPublicKey() instanceof ECPublicKey) { final SignatureSigningConfiguration secConfiguration = SecurityConfigurationSupport @@ -280,7 +288,7 @@ public class Saml2Utils { keyInfoGenFac = keyInfoGenManager.getFactory(credential); } else { - keyInfoGenFac = createKeyInfoWithoutCertificate(credential); + keyInfoGenFac = createKeyInfoWithoutCertificate(); } @@ -288,7 +296,6 @@ public class Saml2Utils { } - /** * Create a SAML2 object. * @@ -462,19 +469,20 @@ public class Saml2Utils { .buildObject(Signature.DEFAULT_ELEMENT_NAME); signature.setSigningCredential(signingCredential); signature.setSignatureAlgorithm(usedSigAlg); - final KeyInfo keyInfo = getKeyInfoGenerator(signingCredential, injectCertificate).generate(signingCredential); + final KeyInfo keyInfo = getKeyInfoGenerator(signingCredential, injectCertificate).generate( + signingCredential); signature.setKeyInfo(keyInfo); signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); return signature; } - private static KeyInfoGeneratorFactory createKeyInfoWithoutCertificate(X509Credential credential) { + private static KeyInfoGeneratorFactory createKeyInfoWithoutCertificate() { final KeyInfoGeneratorFactory keyInfoGenFac = new BasicKeyInfoGeneratorFactory(); - ((BasicKeyInfoGeneratorFactory)keyInfoGenFac).setEmitPublicKeyValue(true); - ((BasicKeyInfoGeneratorFactory)keyInfoGenFac).setEmitEntityIDAsKeyName(true); - ((BasicKeyInfoGeneratorFactory)keyInfoGenFac).setEmitKeyNames(true); - ((BasicKeyInfoGeneratorFactory)keyInfoGenFac).setEmitPublicDEREncodedKeyValue(true); + ((BasicKeyInfoGeneratorFactory) keyInfoGenFac).setEmitPublicKeyValue(true); + ((BasicKeyInfoGeneratorFactory) keyInfoGenFac).setEmitEntityIDAsKeyName(true); + ((BasicKeyInfoGeneratorFactory) keyInfoGenFac).setEmitKeyNames(true); + ((BasicKeyInfoGeneratorFactory) keyInfoGenFac).setEmitPublicDEREncodedKeyValue(true); return keyInfoGenFac; } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SamlHttpUtils.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SamlHttpUtils.java new file mode 100644 index 00000000..2e02bf22 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SamlHttpUtils.java @@ -0,0 +1,33 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.utils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; + +public class SamlHttpUtils { + + /** + * Always read the last parameter with this name from request to get a strict + * deterministic behavior. <br> + * <br> + * <b><i>If more than one parameters with the same name exists, this method + * always select the last parameter value.</i></b> + * + * @param request Incoming http request + * @param paramName Name of the http parameter + * @return the last parameter value with this name, or <code>null</code> if the + * parameter not exists + */ + @Nullable + public static String getLastParameterFromRequest(@Nonnull HttpServletRequest request, + @Nonnull String paramName) { + final String[] values = request.getParameterValues(paramName); + if (values != null && values.length > 0) { + return values[values.length - 1]; + + } + + return null; + + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java index 1591198c..f0758706 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java @@ -23,9 +23,11 @@ import java.util.ArrayList; import java.util.List; import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException; import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver; import org.opensaml.saml.security.impl.MetadataCredentialResolver; +import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver; import org.opensaml.xmlsec.keyinfo.impl.BasicProviderKeyInfoCredentialResolver; import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider; import org.opensaml.xmlsec.keyinfo.impl.provider.DSAKeyValueProvider; @@ -34,29 +36,50 @@ import org.opensaml.xmlsec.keyinfo.impl.provider.RSAKeyValueProvider; import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; import org.opensaml.xmlsec.signature.support.impl.ExplicitKeySignatureTrustEngine; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; + +@Slf4j public class TrustEngineFactory { /** * Get OpenSAML2 TrustEngine. * * @param mdResolver Metadata provider - * @return + * @return TrustEngine for SAML2 message validation + * @throws Pvp2InternalErrorException In case of a TrustEngine initialization + * error */ public static SignatureTrustEngine getSignatureKnownKeysTrustEngine( - final IPvp2MetadataProvider mdResolver) { - final MetadataCredentialResolver resolver = new MetadataCredentialResolver(); - resolver.setRoleDescriptorResolver(new PredicateRoleDescriptorResolver(mdResolver)); + final IPvp2MetadataProvider mdResolver) throws Pvp2InternalErrorException { + try { + final List<KeyInfoProvider> keyInfoProvider = new ArrayList<>(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + final KeyInfoCredentialResolver keyInfoCredentialResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + final PredicateRoleDescriptorResolver roleDescriptorResolver = new PredicateRoleDescriptorResolver( + mdResolver); + roleDescriptorResolver.setRequireValidMetadata(true); + roleDescriptorResolver.initialize(); + + final MetadataCredentialResolver resolver = new MetadataCredentialResolver(); + resolver.setRoleDescriptorResolver(roleDescriptorResolver); + resolver.setKeyInfoCredentialResolver(keyInfoCredentialResolver); + resolver.initialize(); + + final ExplicitKeySignatureTrustEngine engine = + new ExplicitKeySignatureTrustEngine(resolver, keyInfoCredentialResolver); - final List<KeyInfoProvider> keyInfoProvider = new ArrayList<>(); - keyInfoProvider.add(new DSAKeyValueProvider()); - keyInfoProvider.add(new RSAKeyValueProvider()); - keyInfoProvider.add(new InlineX509DataProvider()); + return engine; - final ExplicitKeySignatureTrustEngine engine = - new ExplicitKeySignatureTrustEngine(resolver, - new BasicProviderKeyInfoCredentialResolver(keyInfoProvider)); + } catch (final ComponentInitializationException e) { + log.warn("Initialization of SignatureTrustEngine FAILED.", e); + throw new Pvp2InternalErrorException(e); - return engine; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java index 73a11c49..1994eba0 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java @@ -32,7 +32,6 @@ import org.opensaml.saml.metadata.resolver.filter.FilterException; import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.xml.sax.SAXException; public class SchemaValidationFilter implements MetadataFilter { private static final Logger log = LoggerFactory.getLogger(SchemaValidationFilter.class); @@ -58,8 +57,6 @@ public class SchemaValidationFilter implements MetadataFilter { @Override public XMLObject filter(final XMLObject arg0) throws FilterException { - String errString = null; - if (isActive) { try { final Schema test = schemaBuilder.getSAMLSchema(); @@ -68,15 +65,6 @@ public class SchemaValidationFilter implements MetadataFilter { val.validate(source); log.info("Metadata Schema validation check done OK"); - } catch (final SAXException e) { - if (log.isDebugEnabled() || log.isTraceEnabled()) { - log.warn("Metadata Schema validation FAILED with exception:", e); - } else { - log.warn("Metadata Schema validation FAILED with message: " + e.getMessage()); - } - - errString = e.getMessage(); - } catch (final Exception e) { if (log.isDebugEnabled() || log.isTraceEnabled()) { log.warn("Metadata Schema validation FAILED with exception:", e); @@ -84,13 +72,10 @@ public class SchemaValidationFilter implements MetadataFilter { log.warn("Metadata Schema validation FAILED with message: " + e.getMessage()); } - errString = e.getMessage(); - + throw new FilterException(new SchemaValidationException("internal.pvp.03", + new Object[] { e.getMessage() }, e)); } - throw new FilterException(new SchemaValidationException("pvp2.26", - new Object[] { "Metadata Schema validation FAILED with message: " + errString })); - } else { log.info("Metadata Schema validation check is DEACTIVATED!"); diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java new file mode 100644 index 00000000..ef09e5c4 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java @@ -0,0 +1,146 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * 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.egiz.eaaf.modules.pvp2.impl.validation.metadata; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nonnull; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlMetadataSignatureException; + +import org.opensaml.saml.common.SignableSAMLObject; +import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator; +import org.opensaml.security.x509.BasicX509Credential; +import org.opensaml.xmlsec.signature.support.SignatureException; +import org.opensaml.xmlsec.signature.support.SignatureValidator; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SimpleMetadataSignatureVerificationFilter extends AbstractMetadataSignatureFilter { + + private final String metadataUrl; + private final List<BasicX509Credential> trustedCredential = new ArrayList<>(); + + private static final String ERROR_07 = "internal.pvp.07"; + private static final String ERROR_12 = "internal.pvp.12"; + private static final String ERROR_MSG_ENTITIESDESC = "EntitiesDescritors are NOT supported"; + private static final String ERROR_MSG_SIGNOTVALID = "Signature not valid or no trusted certificate found"; + + /** + * SAML2 metadata-signature verification-filter that uses a simple {@link List} + * of trusted {@link BasicX509Credential} as truststore. <br> + * <p> + * This filter only validates {@link EntityDescriptor} elements.<br> + * SAML2 metadata with {@link EntitiesDescriptor} <b>are not supported.</b> + * </p> + * + * @param credentials Trust X509 certificates + * @param metadataUrl Metadata URL for logging purposes + */ + public SimpleMetadataSignatureVerificationFilter(@Nonnull List<BasicX509Credential> credentials, + @Nonnull String metadataUrl) { + this.metadataUrl = metadataUrl; + this.trustedCredential.addAll(credentials); + + } + + @Override + protected void verify(EntityDescriptor desc) throws Pvp2MetadataException { + try { + internalVerify(desc); + + } catch (final EaafException e) { + log.info("Metadata verification FAILED for: {} Reason: {}", metadataUrl, e.getMessage()); + throw new Pvp2MetadataException(ERROR_07, + new Object[] { metadataUrl, e.getMessage() }, e); + + } + } + + @Override + protected void verify(EntitiesDescriptor desc) throws Pvp2MetadataException { + throw new Pvp2MetadataException(ERROR_07, + new Object[] { metadataUrl, ERROR_MSG_ENTITIESDESC }); + + } + + @Override + protected void verify(EntityDescriptor entity, EntitiesDescriptor desc) throws Pvp2MetadataException { + throw new Pvp2MetadataException(ERROR_07, + new Object[] { metadataUrl, ERROR_MSG_ENTITIESDESC }); + + } + + private void internalVerify(SignableSAMLObject signedElement) + throws EaafException { + // check if signature exists + if (signedElement.getSignature() == null) { + throw new Pvp2MetadataException(ERROR_12, + new Object[] { metadataUrl }); + + } + + // perform general signature validation + try { + final SAMLSignatureProfileValidator sigValidator = new SAMLSignatureProfileValidator(); + sigValidator.validate(signedElement.getSignature()); + + } catch (final SignatureException e) { + log.error("Failed to validate Signature", e); + throw new Pvp2MetadataException(ERROR_07, + new Object[] { metadataUrl, e.getMessage() }, e); + + } + + // perform cryptographic signature verification + boolean isTrusted = false; + for (final BasicX509Credential cred : trustedCredential) { + log.trace("Validating signature with credential: {} ... ", + cred.getEntityCertificate().getSubjectDN()); + try { + SignatureValidator.validate(signedElement.getSignature(), cred); + isTrusted = true; + + } catch (final SignatureException e) { + log.debug("Failed to verfiy Signature with cert: {} Reason: {}", + cred.getEntityCertificate().getSubjectDN(), e.getMessage()); + + } + } + + if (!isTrusted) { + log.info("PVP2 metadata: " + metadataUrl + " are NOT trusted!"); + throw new SamlMetadataSignatureException(metadataUrl, ERROR_MSG_SIGNOTVALID); + + } + + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java index 2672bef2..aba0a68b 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java @@ -1,23 +1,64 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.verification; +import javax.annotation.Nonnull; + +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; + +import org.opensaml.core.config.ConfigurationService; import org.opensaml.messaging.context.MessageContext; import org.opensaml.messaging.handler.AbstractMessageHandler; import org.opensaml.messaging.handler.MessageHandlerException; import org.opensaml.saml.common.SAMLObject; import org.opensaml.saml.common.messaging.context.SAMLMessageInfoContext; import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext; +import org.opensaml.xmlsec.SignatureValidationConfiguration; +import org.opensaml.xmlsec.SignatureValidationParameters; +import org.opensaml.xmlsec.context.SecurityParametersContext; +import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; @Slf4j public class EaafMessageContextInitializationHandler extends AbstractMessageHandler<SAMLObject> { + private final IPvp2MetadataProvider internalMetadataProvider; + private SignatureTrustEngine trustEngine; + + public EaafMessageContextInitializationHandler(@Nonnull IPvp2MetadataProvider metadataProvider) { + internalMetadataProvider = metadataProvider; + } + + @Override + protected void doInitialize() throws ComponentInitializationException { + try { + trustEngine = TrustEngineFactory.getSignatureKnownKeysTrustEngine(internalMetadataProvider); + + } catch (final Pvp2InternalErrorException e) { + throw new ComponentInitializationException("TrustEngine injection FAILED", e); + + } + } + + @Override protected void doInvoke(MessageContext<SAMLObject> messageContext) throws MessageHandlerException { log.trace("Injecting sub-context to SAML2 message ... "); messageContext.addSubcontext(new SAMLPeerEntityContext()); messageContext.addSubcontext(new SAMLMessageInfoContext()); + + final SecurityParametersContext securityParameterContext = new SecurityParametersContext(); + final SignatureValidationParameters sigValParameters = new SignatureValidationParameters(); + securityParameterContext.setSignatureValidationParameters(sigValParameters); + messageContext.addSubcontext(securityParameterContext); + + sigValParameters.setBlacklistedAlgorithms( + ConfigurationService.get(SignatureValidationConfiguration.class) + .getBlacklistedAlgorithms()); + sigValParameters.setSignatureTrustEngine(trustEngine); } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSaml2HttpRedirectDeflateSignatureSecurityHandler.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSaml2HttpRedirectDeflateSignatureSecurityHandler.java new file mode 100644 index 00000000..204229ee --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSaml2HttpRedirectDeflateSignatureSecurityHandler.java @@ -0,0 +1,107 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.verification; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SamlHttpUtils; + +import org.opensaml.messaging.context.MessageContext; +import org.opensaml.messaging.handler.MessageHandlerException; +import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext; +import org.opensaml.saml.saml2.binding.security.impl.SAML2HTTPRedirectDeflateSignatureSecurityHandler; + +import com.google.common.base.Strings; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.codec.Base64Support; + +/** + * Always extracts the last http parameter with a specific name from request, if + * more than one with the same name exists. + * + * @author tlenz + * + */ +@Slf4j +public class EaafSaml2HttpRedirectDeflateSignatureSecurityHandler extends + SAML2HTTPRedirectDeflateSignatureSecurityHandler { + + public static final String HTTP_REDIRECT_SIGALG = "SigAlg"; + public static final String HTTP_REDIRECT_SIGNATURE = "Signature"; + + private IRefreshableMetadataProvider refreshableMetadataProvider = null; + + /** + * Signature verification handler that reloads SAML2 metadata if signature + * verification fails. + * + * @param metadataProvider Metadata provider implementation. Refreshing is only + * possible, if that provider implements + * {@link IRefreshableMetadataProvider} + */ + public EaafSaml2HttpRedirectDeflateSignatureSecurityHandler( + @Nullable IPvp2MetadataProvider metadataProvider) { + if (metadataProvider != null) { + if (metadataProvider instanceof IRefreshableMetadataProvider) { + refreshableMetadataProvider = (IRefreshableMetadataProvider) metadataProvider; + + } else { + log.trace("Refreshing is not supported by {} metadata-provider", + metadataProvider.getClass().getSimpleName()); + + } + } + } + + @Override + protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException { + try { + super.doInvoke(messageContext); + + } catch (final MessageHandlerException e) { + if (refreshableMetadataProvider != null) { + + log.debug("Starting metadata refresh process ... "); + if (refreshableMetadataProvider.refreshMetadataProvider( + messageContext.getSubcontext(SAMLPeerEntityContext.class).getEntityId())) { + log.trace("Refreshing successful. Restarting message evaluation ... "); + + try { + super.doInvoke(messageContext); + return; + + } catch (final MessageHandlerException e1) { + log.debug("Signature validation fails twice with second error: {}", e.getMessage()); + + } + } + } + + log.info("Signature validation of SAML message failed. Reason: {}", e.getMessage()); + throw new MessageHandlerException( + new SamlSigningException("internal.pvp.10", new Object[] { e.getMessage() }, e)); + } + } + + @Override + @Nullable + protected byte[] getSignature() throws MessageHandlerException { + final String signature = SamlHttpUtils.getLastParameterFromRequest( + getHttpServletRequest(), HTTP_REDIRECT_SIGNATURE); + + if (Strings.isNullOrEmpty(signature)) { + return null; + + } + return Base64Support.decode(signature); + } + + @Override + @Nullable + protected String getSignatureAlgorithm() throws MessageHandlerException { + return SamlHttpUtils.getLastParameterFromRequest(getHttpServletRequest(), HTTP_REDIRECT_SIGALG); + + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSamlProtocolMessageXmlSignatureSecurityHandler.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSamlProtocolMessageXmlSignatureSecurityHandler.java new file mode 100644 index 00000000..9f6bc864 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSamlProtocolMessageXmlSignatureSecurityHandler.java @@ -0,0 +1,75 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.verification; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; + +import org.opensaml.messaging.context.MessageContext; +import org.opensaml.messaging.handler.MessageHandlerException; +import org.opensaml.saml.common.binding.security.impl.SAMLProtocolMessageXMLSignatureSecurityHandler; +import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EaafSamlProtocolMessageXmlSignatureSecurityHandler extends + SAMLProtocolMessageXMLSignatureSecurityHandler { + + private IRefreshableMetadataProvider refreshableMetadataProvider = null; + + /** + * Signature verification handler that reloads SAML2 metadata if signature + * verification fails. + * + * @param metadataProvider Metadata provider implementation. Refreshing is only + * possible, if that provider implements + * {@link IRefreshableMetadataProvider} + */ + public EaafSamlProtocolMessageXmlSignatureSecurityHandler( + @Nullable IPvp2MetadataProvider metadataProvider) { + if (metadataProvider != null) { + if (metadataProvider instanceof IRefreshableMetadataProvider) { + refreshableMetadataProvider = (IRefreshableMetadataProvider) metadataProvider; + + } else { + log.trace("Refreshing is not supported by {} metadata-provider", + metadataProvider.getClass().getSimpleName()); + + } + } + } + + @Override + public void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException { + try { + super.doInvoke(messageContext); + + } catch (final MessageHandlerException e) { + if (refreshableMetadataProvider != null) { + + log.debug("Starting metadata refresh process ... "); + if (refreshableMetadataProvider.refreshMetadataProvider( + messageContext.getSubcontext(SAMLPeerEntityContext.class).getEntityId())) { + log.trace("Refreshing successful. Restarting message evaluation ... "); + + try { + super.doInvoke(messageContext); + return; + + } catch (final MessageHandlerException e1) { + log.debug("Signature validation fails twice with second error: {}", e.getMessage()); + + } + } + } + + log.info("Signature validation of SAML message failed. Reason: {}", e.getMessage()); + throw new MessageHandlerException( + new SamlSigningException("internal.pvp.10", new Object[] { e.getMessage() }, e)); + } + + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java index e43d0423..a1365023 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java @@ -24,12 +24,12 @@ public class PvpSamlMessageHandlerChain implements MessageHandlerChain<SAMLObjec + PvpSamlMessageHandlerChain.class.getName() + " not initialized"); } + for (final MessageHandler<SAMLObject> handler : getHandlers()) { log.trace("Initializing SAML message handler: {}", handler.getClass().getName()); handler.invoke(messageContext); } - } @Override diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java index 658dfe16..2e26de7f 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java @@ -68,9 +68,10 @@ public class SamlVerificationEngine { * * @param msg SAML2 message * @param sigTrustEngine TrustEngine - * @throws org.opensaml.xml.security.SecurityException In case of - * invalid signature - * @throws Exception In case of a general error + * @throws org.opensaml.xml.security.SecurityException In case of invalid + * signature + * @throws Exception In case of a general + * error */ public void verify(final InboundMessage msg, final SignatureTrustEngine sigTrustEngine) throws SecurityException, Exception { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties index cee622c2..8a91c68c 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties @@ -4,6 +4,18 @@ internal.pvp.02=PVP message contains no signature. internal.pvp.03=Schema-validation of SAML2 message failed with error: {0} internal.pvp.04=Can not initialize metadata provider for metadata: {0} internal.pvp.05=Can not initialize metadata provider for metadata: {0}. Reason: {1} +internal.pvp.06=SSL-Server certificate for metadata: {0} not trusted. Details: {1} +internal.pvp.07=Signature verification for metadata: {0} FAILED. Details: {1} +internal.pvp.08=Schema validation for metadata: {0} FAILED. Details: {1} +internal.pvp.09=Can not initialize metadata provider for metadata: {0}. Details: {1} +internal.pvp.10=Signature verification of SAML2 message FAILED. Reason: {0} +internal.pvp.11=General SAML2 message validation error. Reason: {0} +internal.pvp.12=SAML2 metadata: {0} is NOT signed +internal.pvp.13=SAML2 metadata generation failed. Reason: {0} + +pvp2.21=Signature validation of SAML2 Authn. request failed. Reason: {0} +pvp2.22=Validation of SAML2 Authn. request failed. Reason: {0} +pvp2.24=General error during SAML2 Auth. request pre-processing. Reason: {0} internal.pvp.95=OpenSAML {0}-binding message {1} failed. Reason: {2} internal.pvp.96=OpenSAML signing FAILED with key: {0}. Reason: {1} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/PostBindingTest.java b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/PostBindingTest.java index 6adce26e..87073e81 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/PostBindingTest.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/PostBindingTest.java @@ -3,6 +3,7 @@ package at.gv.egiz.eaaf.modules.pvp2.test.binding; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.util.Base64; import java.util.Map; @@ -13,23 +14,30 @@ import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiBuilderConfiguration; import at.gv.egiz.eaaf.core.impl.idp.module.gui.DummyGuiBuilderConfigurationFactory; import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.core.impl.utils.IHttpClientFactory; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface; import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlMessageValidationException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare; import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; +import at.gv.egiz.eaaf.modules.pvp2.test.metadata.MetadataResolverTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomStringUtils; +import org.joda.time.DateTime; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.opensaml.core.config.InitializationException; import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.io.Unmarshaller; import org.opensaml.core.xml.io.UnmarshallerFactory; @@ -40,6 +48,7 @@ import org.opensaml.messaging.encoder.MessageEncodingException; import org.opensaml.saml.common.SignableSAMLObject; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.StatusResponseType; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -49,9 +58,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.net.URIComparator; import net.shibboleth.utilities.java.support.xml.XMLParserException; +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"/spring/test_eaaf_pvp.beans.xml"}) @@ -65,15 +76,27 @@ public class PostBindingTest { @Autowired private PostBinding bindingImpl; @Autowired private DummyCredentialProvider credentialProvider; @Autowired private DummyGuiBuilderConfigurationFactory guiBuilderFactory; + @Autowired private PvpMetadataResolverFactory metadataResolverFactory; + @Autowired private IHttpClientFactory httpClientFactory; + + private static MockWebServer mockWebServer; + private static HttpUrl mockServerUrl; protected MockHttpServletRequest httpReq; protected MockHttpServletResponse httpResp; protected IRequest pendingReq; + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ @BeforeClass - public static void classInitializer() throws InitializationException, ComponentInitializationException { + public static void classInitializer() throws Exception { EaafOpenSaml3xInitializer.eaafInitialize(); + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/metadata"); } /** @@ -101,12 +124,14 @@ public class PostBindingTest { } @Test - public void decodeRequestSuccess() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { - final String serviceUrl = "http://testservice.org"; + public void decodeRequestWrongEndpoint() throws MessageDecodingException, SecurityException, + IOException, Pvp2MetadataException { + final String serviceUrl = "https://wrongEndpoint/pvp2/post"; - final IPvp2MetadataProvider metadataProvider = null; + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_wrong_sig.xml", null, "jUnit metadata resolver", null); - final boolean isSpEndPoint = false; final URIComparator comparator = new EaafUriCompare(serviceUrl); final String b64AuthnReq = Base64.getEncoder().encodeToString(IOUtils.toByteArray( @@ -114,39 +139,169 @@ public class PostBindingTest { httpReq.setMethod("POST"); httpReq.addParameter("SAMLRequest", b64AuthnReq); + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); + Assert.fail("Wrong http end-point not detected"); + + } catch (final Pvp2Exception e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.11", e.getErrorId()); + Assert.assertNotNull("Parameters null", e.getParams()); + Assert.assertEquals("Wrong numer of parameters", 1, e.getParams().length); + + + } + + } + + @Test + public void decodeRequestMissingSignature() throws MessageDecodingException, SecurityException, + IOException, Pvp2MetadataException { + final String serviceUrl = "https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp2/post"; + + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_wrong_sig.xml", null, "jUnit metadata resolver", null); + + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + final String b64AuthnReq = Base64.getEncoder().encodeToString(IOUtils.toByteArray( + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml"))); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); + + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); + Assert.fail("Missing signature not detected"); + + } catch (final Pvp2Exception e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.02", e.getErrorId()); + + } + + } + + @Test + public void decodeRequestWrongSignature() throws MessageDecodingException, SecurityException, + IOException, Pvp2Exception { + final String serviceUrl = "https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp2/post"; + + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_wrong_sig.xml", null, "jUnit metadata resolver", null); + + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + final String b64AuthnReq = Base64.getEncoder().encodeToString(IOUtils.toByteArray( + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_with_sig_1.xml"))); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); + + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); + Assert.fail("Invalid signature not detected"); + + } catch (final Pvp2Exception e) { + org.springframework.util.Assert.isInstanceOf(SamlSigningException.class, e, "Wrong Exception type"); + Assert.assertEquals("Wrong errorCode", "internal.pvp.10", e.getErrorId()); + Assert.assertNotNull("No error params", e.getParams()); + Assert.assertEquals("Wrong param size", 1, e.getParams().length); + + } + + } + + @Test + public void decodeRequestMsgExpired() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + final String serviceUrl = "https://eidas-test.bmi.gv.at/ms_connector/pvp/post"; + + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_moaid_test.xml", null, "jUnit metadata resolver", null); + + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + final String b64AuthnReq = new String(IOUtils.toByteArray( + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_withsig_expired.b64")), "UTF-8"); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); + + + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); + Assert.fail("Expired msg not detected"); + + } catch (final Pvp2Exception e) { + org.springframework.util.Assert.isInstanceOf(SamlMessageValidationException.class, e, "Wrong Exception type"); + Assert.assertEquals("Wrong errorCode", "internal.pvp.11", e.getErrorId()); + Assert.assertNotNull("No error params", e.getParams()); + Assert.assertEquals("Wrong param size", 1, e.getParams().length); + + } + + } + + @Test + public void decodeRequestSuccessMetadataReloadRequired() throws MessageDecodingException, SecurityException, + IOException, Pvp2Exception, CredentialsNotAvailableException, XMLParserException, UnmarshallingException { + final String serviceUrl = "http://testservice.org"; + + final String b64AuthnReq = generateSaml2AuthnRequest( + credentialProvider.getIdpMetaDataSigningCredential()); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_wrong_sig.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_junit_keystore.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); + + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + mockServerUrl.url().toString(), + null, "jUnit test", httpClientFactory.getHttpClient()); + + final URIComparator comparator = new EaafUriCompare(serviceUrl); + final InboundMessageInterface msg = - bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, comparator); + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); Assert.assertNotNull("PVP msg is null", msg); - Assert.assertNull("RelayState is not null", msg.getRelayState()); + Assert.assertNull("RelayState not null", msg.getRelayState()); Assert.assertNotNull("AuthnReq is null", msg.getInboundMessage()); Assert.assertNotNull("EntityId is null", msg.getEntityID()); Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg.getEntityID()); - Assert.assertFalse("Wrong isVerified flag", msg.isVerified()); + Assert.assertTrue("Wrong isVerified flag", msg.isVerified()); } @Test - public void decodeRequestSuccessWithRelayState() throws MessageDecodingException, SecurityException, - IOException, Pvp2Exception { + public void decodeRequestSuccessWithRelayStateRsaSig() throws MessageDecodingException, SecurityException, + IOException, Pvp2Exception, CredentialsNotAvailableException, XMLParserException, UnmarshallingException { final String serviceUrl = "http://testservice.org"; final String relayState = RandomStringUtils.randomAlphanumeric(10); - final String b64AuthnReq = Base64.getEncoder().encodeToString(IOUtils.toByteArray( - PostBindingTest.class.getResourceAsStream("/data/AuthRequest_with_sig_1.xml"))); + final String b64AuthnReq = generateSaml2AuthnRequest( + credentialProvider.getIdpMetaDataSigningCredential()); httpReq.setMethod("POST"); httpReq.addParameter("SAMLRequest", b64AuthnReq); httpReq.addParameter("RelayState", relayState); - final IPvp2MetadataProvider metadataProvider = null; + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); - final boolean isSpEndPoint = false; final URIComparator comparator = new EaafUriCompare(serviceUrl); - final InboundMessageInterface msg = - bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, comparator); + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); Assert.assertNotNull("PVP msg is null", msg); Assert.assertNotNull("RelayState is not null", msg.getRelayState()); @@ -154,64 +309,63 @@ public class PostBindingTest { Assert.assertNotNull("AuthnReq is null", msg.getInboundMessage()); Assert.assertNotNull("EntityId is null", msg.getEntityID()); Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg.getEntityID()); - Assert.assertFalse("Wrong isVerified flag", msg.isVerified()); + Assert.assertTrue("Wrong isVerified flag", msg.isVerified()); } @Test - public void decodeResponseSuccess() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + public void decodeRequestSuccessWithoutRelayStateEcdsaSig() throws MessageDecodingException, SecurityException, + IOException, Pvp2Exception, CredentialsNotAvailableException, XMLParserException, UnmarshallingException { final String serviceUrl = "http://testservice.org"; - final IPvp2MetadataProvider metadataProvider = null; - - final boolean isSpEndPoint = false; - final URIComparator comparator = new EaafUriCompare(serviceUrl); - - final String b64AuthnReq = Base64.getEncoder().encodeToString(IOUtils.toByteArray( - PostBindingTest.class.getResourceAsStream("/data/Response_with_sig_1.xml"))); + final String b64AuthnReq = generateSaml2AuthnRequest( + credentialProvider.getIdpAssertionSigningCredential()); httpReq.setMethod("POST"); httpReq.addParameter("SAMLRequest", b64AuthnReq); + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); + + final URIComparator comparator = new EaafUriCompare(serviceUrl); + final InboundMessageInterface msg = - bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, comparator); + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); Assert.assertNotNull("PVP msg is null", msg); Assert.assertNull("RelayState is not null", msg.getRelayState()); - Assert.assertNotNull("Response is null", msg.getInboundMessage()); + Assert.assertNotNull("AuthnReq is null", msg.getInboundMessage()); Assert.assertNotNull("EntityId is null", msg.getEntityID()); - Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata", msg.getEntityID()); - Assert.assertFalse("Wrong isVerified flag", msg.isVerified()); + Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg.getEntityID()); + Assert.assertTrue("Wrong isVerified flag", msg.isVerified()); } @Test - public void decodeResponseSuccessWithRelayState() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + public void decodeResponseSuccess() throws MessageDecodingException, SecurityException, + IOException, Pvp2Exception, CredentialsNotAvailableException, XMLParserException, UnmarshallingException { final String serviceUrl = "http://testservice.org"; - final String relayState = RandomStringUtils.randomAlphanumeric(10); - final String b64AuthnReq = Base64.getEncoder().encodeToString(IOUtils.toByteArray( - PostBindingTest.class.getResourceAsStream("/data/Response_with_sig_1.xml"))); - httpReq.setMethod("POST"); - httpReq.addParameter("SAMLRequest", b64AuthnReq); - httpReq.addParameter("RelayState", relayState); + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); - final IPvp2MetadataProvider metadataProvider = null; - - final boolean isSpEndPoint = false; final URIComparator comparator = new EaafUriCompare(serviceUrl); + final String b64AuthnReq = generateSaml2Response(credentialProvider.getIdpMetaDataSigningCredential()); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); final InboundMessageInterface msg = - bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, comparator); + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); Assert.assertNotNull("PVP msg is null", msg); - Assert.assertNotNull("RelayState is not null", msg.getRelayState()); - Assert.assertEquals("RelayState not match", relayState, msg.getRelayState()); + Assert.assertNull("RelayState is not null", msg.getRelayState()); Assert.assertNotNull("Response is null", msg.getInboundMessage()); Assert.assertNotNull("EntityId is null", msg.getEntityID()); - Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata", msg.getEntityID()); - Assert.assertFalse("Wrong isVerified flag", msg.isVerified()); + Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg.getEntityID()); + Assert.assertTrue("Wrong isVerified flag", msg.isVerified()); } @@ -445,4 +599,48 @@ public class PostBindingTest { } + private String generateSaml2AuthnRequest(EaafX509Credential credentials) + throws XMLParserException, UnmarshallingException, Pvp2Exception, CredentialsNotAvailableException, + UnsupportedEncodingException { + final MockHttpServletRequest intHttpReq = new MockHttpServletRequest(); + final MockHttpServletResponse intHttpResp = new MockHttpServletResponse(); + guiBuilderFactory.setVelocityBuilderConfig(createDummyGuiConfig()); + final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + authnReq.setIssueInstant(DateTime.now()); + + bindingImpl.encodeRequest(intHttpReq, intHttpResp, authnReq, "http://testservice.org", null, + credentials, pendingReq); + + Assert.assertEquals("http StatusCode", 200, intHttpResp.getStatus()); + final String http = intHttpResp.getContentAsString(); + Assert.assertNotNull("http body is null", http); + Assert.assertTrue("SAMLRequest parameter", http.contains(HTTP_FORM_SAMLREQ)); + return extractParamFromHttpForm(http, HTTP_FORM_SAMLREQ); + + } + + private String generateSaml2Response(EaafX509Credential credentials) + throws XMLParserException, UnmarshallingException, Pvp2Exception, CredentialsNotAvailableException, + UnsupportedEncodingException { + final MockHttpServletRequest intHttpReq = new MockHttpServletRequest(); + final MockHttpServletResponse intHttpResp = new MockHttpServletResponse(); + guiBuilderFactory.setVelocityBuilderConfig(createDummyGuiConfig()); + final StatusResponseType response = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/Response_without_sig_1.xml")); + response.setIssueInstant(DateTime.now()); + + bindingImpl.encodeResponse(intHttpReq, intHttpResp, response, "http://testservice.org", null, + credentials, pendingReq); + + Assert.assertEquals("http StatusCode", 200, intHttpResp.getStatus()); + final String http = intHttpResp.getContentAsString(); + Assert.assertNotNull("http body is null", http); + Assert.assertTrue("SAMLRequest parameter", http.contains(HTTP_FORM_SAMLRESP)); + return extractParamFromHttpForm(http, HTTP_FORM_SAMLRESP); + + } + } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java index a99c8461..23cc98a6 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java @@ -6,15 +6,34 @@ import java.util.Base64; import javax.xml.parsers.ParserConfigurationException; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.utils.IHttpClientFactory; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlMessageValidationException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare; +import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; +import at.gv.egiz.eaaf.modules.pvp2.test.metadata.MetadataResolverTest; + import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomStringUtils; +import org.joda.time.DateTime; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.opensaml.core.config.InitializationException; import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.io.UnmarshallingException; import org.opensaml.core.xml.util.XMLObjectSupport; @@ -22,6 +41,7 @@ import org.opensaml.messaging.decoder.MessageDecodingException; import org.opensaml.messaging.encoder.MessageEncodingException; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.StatusResponseType; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -30,46 +50,57 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.xml.sax.SAXException; -import at.gv.egiz.eaaf.core.api.IRequest; -import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; -import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; -import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; -import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare; -import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; -import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.net.URIComparator; +import net.shibboleth.utilities.java.support.net.URISupport; import net.shibboleth.utilities.java.support.xml.XMLParserException; +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration({"/spring/test_eaaf_pvp.beans.xml"}) -@TestPropertySource(locations = {"/config/config_1.props"}) +@ContextConfiguration({ "/spring/test_eaaf_pvp.beans.xml" }) +@TestPropertySource(locations = { "/config/config_1.props" }) public class RedirectBindingTest { - public static final String HTTP_FORM_RELAYSTATE = "RelayState="; - public static final String HTTP_FORM_SAMLREQ = "SAMLRequest="; - public static final String HTTP_FORM_SAMLRESP = "SAMLResponse="; + public static final String HTTP_FORM_RELAYSTATE = "RelayState"; + public static final String HTTP_FORM_RELAYSTATE_PARAM = HTTP_FORM_RELAYSTATE + "="; + + public static final String HTTP_FORM_SAMLREQ = "SAMLRequest"; + public static final String HTTP_FORM_SAMLREQ_PARAM = HTTP_FORM_SAMLREQ + "="; + public static final String HTTP_FORM_SAMLRESP = "SAMLResponse"; + public static final String HTTP_FORM_SAMLRESP_PARM = HTTP_FORM_SAMLRESP + "="; + + public static final String HTTP_REDIRECT_SIGALG = "SigAlg"; + public static final String HTTP_REDIRECT_SIGALG_PARAM = HTTP_REDIRECT_SIGALG + "="; + public static final String HTTP_REDIRECT_SIGNATURE = "Signature"; + public static final String HTTP_REDIRECT_SIGNATURE_PARAM = HTTP_REDIRECT_SIGNATURE + "="; - public static final String HTTP_REDIRECT_SIGALG = "SigAlg="; - public static final String HTTP_REDIRECT_SIGNATURE = "Signature="; + @Autowired + private RedirectBinding bindingImpl; + @Autowired + private DummyCredentialProvider credentialProvider; + @Autowired + private PvpMetadataResolverFactory metadataResolverFactory; + @Autowired private IHttpClientFactory httpClientFactory; - @Autowired private RedirectBinding bindingImpl; - @Autowired private DummyCredentialProvider credentialProvider; - @Autowired private PvpMetadataResolverFactory metadataResolverFactory; + private static MockWebServer mockWebServer; + private static HttpUrl mockServerUrl; protected MockHttpServletRequest httpReq; protected MockHttpServletResponse httpResp; protected IRequest pendingReq; + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ @BeforeClass - public static void classInitializer() throws InitializationException, ComponentInitializationException { + public static void classInitializer() throws Exception { EaafOpenSaml3xInitializer.eaafInitialize(); + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/metadata"); } /** @@ -97,34 +128,236 @@ public class RedirectBindingTest { } @Test - public void decodeRequestSuccess() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + public void decodeRequestNoSignature() throws MessageDecodingException, + SecurityException, IOException, Pvp2MetadataException { + final String serviceUrl = "http://testservice.org"; + + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_wrong_sig.xml", null, "jUnit metadata resolver", null); + + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + httpReq.setMethod("GET"); + httpReq.setRequestURI("http://testservice.org"); + httpReq.setQueryString("SAMLRequest=nVRNb9swDD13wP6DoXvkr%2FRjQuzCSFAgQDd0TbfDLoVi0642Wcok2kn766c4duABWw%" + + "2B%2BSdQj%2BfhIanF7qKXXgrFCq4SENCAeqFwXQlUJ%2BfZ0N7sht%2BnC8lpGO5Y1%2BKIe4XcDFj3nqCw7vSSkMYppboVli" + + "tdgGeZsk32%2BZxEN2M5o1LmWxMusBYMu1VIr29RgNmBakcNaFXBw6R0C0Yhtg3BCOBp%2FQxy%2FlcsuFMeO8Qvijvk%2BOps" + + "9Aak2FfHWq4Q8c4BtySHO4eomLCEuipyXURjzeVQGYRE7mLWNC22RK0xIFITzWRDPgsun4IrFn1gQ0evryx%2FE%2Bz4o5Oohv" + + "R6sczZjId7XgQ%2FVE%2B9Om5rj%2B%2FCjRRSzsoMyUCjwlaTHgq2ruIBaU6jEG61ayrG777RBLp%2BPR6krofyFP2Y68N402" + + "5%2BQ4xTi6ccPFxd9mC8Ot15NI9T7umiDpSd1nrUT4kFLkb96mZR6vzTAERKCpoEpCu6OPbTohCRThtc%2FU%2Bs3AIpuH9ygI" + + "hwm7cNYzXGspXSKP0I5qUP9Ruz3e2pRm1%2B00i2Fxne77ecCxRuor1l2Dy1Ifz6o%2F6%2Fso%2B78p%2Bb0%2FDz%2BGdI%2" + + "F&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=DOVMqh17xn4wl%2" + + "Byvifm4McMsBjKDVf1eqph9ss362ZEbp2nkAIXUzkNWv72I96iNK3r%2BYbAxY9dwZ8Z7jKzCGiJ9Qm34YSfPvzXWl3EVrdI86" + + "9U%2BH6HGIMqVew3cVdr4q3Qv9ZBIhdRxbrDu%2F%2BnMjdf8mzbgcQnfjSQiQIYWxOIXZFyxKsyrxJtIam4hoNwUT7mMN6Rjg" + + "zvyeS3mARsTJdcI0Vn4ItiprhLgIkD18V9WIdeSZR0gfRaFj8PKdmXCD%2FIa0cKgjhVKoiIZisV4vcthBOeDIqBORL2Ad3Xhc" + + "NRQ3%2BcpAf65zHGMBAv1aRy7Bmv0%2B%2BOvCavufykqI2EHtg%3D%3D"); + + httpReq.setParameter(HTTP_FORM_SAMLREQ, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_FORM_SAMLREQ).substring(HTTP_FORM_SAMLREQ_PARAM.length()), "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGALG, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGALG).substring(HTTP_REDIRECT_SIGALG_PARAM.length()), + "UTF-8")); + + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, + comparator); + Assert.fail("Missing signature not detected"); + + } catch (final Pvp2Exception e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.02", e.getErrorId()); + + } + + } + + @Test + public void decodeRequestWrongEndpoint() throws MessageDecodingException, + SecurityException, IOException, Pvp2Exception { + final String serviceUrl = "http://wrongEndPoint.org"; + + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_wrong_sig.xml", null, "jUnit metadata resolver", null); + + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + httpReq.setMethod("GET"); + httpReq.setRequestURI("http://testservice.org"); + httpReq.setQueryString("SAMLRequest=nVRNb9swDD13wP6DoXvkr%2FRjQuzCSFAgQDd0TbfDLoVi0642Wcok2kn766c4duABWw%" + + "2B%2BSdQj%2BfhIanF7qKXXgrFCq4SENCAeqFwXQlUJ%2BfZ0N7sht%2BnC8lpGO5Y1%2BKIe4XcDFj3nqCw7vSSkMYppboVli" + + "tdgGeZsk32%2BZxEN2M5o1LmWxMusBYMu1VIr29RgNmBakcNaFXBw6R0C0Yhtg3BCOBp%2FQxy%2FlcsuFMeO8Qvijvk%2BOps" + + "9Aak2FfHWq4Q8c4BtySHO4eomLCEuipyXURjzeVQGYRE7mLWNC22RK0xIFITzWRDPgsun4IrFn1gQ0evryx%2FE%2Bz4o5Oohv" + + "R6sczZjId7XgQ%2FVE%2B9Om5rj%2B%2FCjRRSzsoMyUCjwlaTHgq2ruIBaU6jEG61ayrG777RBLp%2BPR6krofyFP2Y68N402" + + "5%2BQ4xTi6ccPFxd9mC8Ot15NI9T7umiDpSd1nrUT4kFLkb96mZR6vzTAERKCpoEpCu6OPbTohCRThtc%2FU%2Bs3AIpuH9ygI" + + "hwm7cNYzXGspXSKP0I5qUP9Ruz3e2pRm1%2B00i2Fxne77ecCxRuor1l2Dy1Ifz6o%2F6%2Fso%2B78p%2Bb0%2FDz%2BGdI%2" + + "F&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=DOVMqh17xn4wl%2" + + "Byvifm4McMsBjKDVf1eqph9ss362ZEbp2nkAIXUzkNWv72I96iNK3r%2BYbAxY9dwZ8Z7jKzCGiJ9Qm34YSfPvzXWl3EVrdI86" + + "9U%2BH6HGIMqVew3cVdr4q3Qv9ZBIhdRxbrDu%2F%2BnMjdf8mzbgcQnfjSQiQIYWxOIXZFyxKsyrxJtIam4hoNwUT7mMN6Rjg" + + "zvyeS3mARsTJdcI0Vn4ItiprhLgIkD18V9WIdeSZR0gfRaFj8PKdmXCD%2FIa0cKgjhVKoiIZisV4vcthBOeDIqBORL2Ad3Xhc" + + "NRQ3%2BcpAf65zHGMBAv1aRy7Bmv0%2B%2BOvCavufykqI2EHtg%3D%3D"); + + httpReq.setParameter(HTTP_FORM_SAMLREQ, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_FORM_SAMLREQ).substring(HTTP_FORM_SAMLREQ_PARAM.length()), "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGALG, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGALG).substring(HTTP_REDIRECT_SIGALG_PARAM.length()), + "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGNATURE, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGNATURE).substring(HTTP_REDIRECT_SIGNATURE_PARAM.length()), + "UTF-8")); + + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, + comparator); + Assert.fail("Wrong signature not detected"); + + } catch (final Pvp2Exception e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.10", e.getErrorId()); + Assert.assertNotNull("Parameters null", e.getParams()); + Assert.assertEquals("Wrong numer of parameters", 1, e.getParams().length); + + } + + } + + @Test + public void decodeRequestWrongSignature() throws MessageDecodingException, + SecurityException, IOException, Pvp2Exception { + final String serviceUrl = "http://testservice.org"; + + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_wrong_sig.xml", null, "jUnit metadata resolver", null); + + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + httpReq.setMethod("GET"); + httpReq.setRequestURI("http://testservice.org"); + httpReq.setQueryString("SAMLRequest=nVRNb9swDD13wP6DoXvkr%2FRjQuzCSFAgQDd0TbfDLoVi0642Wcok2kn766c4duABWw%" + + "2B%2BSdQj%2BfhIanF7qKXXgrFCq4SENCAeqFwXQlUJ%2BfZ0N7sht%2BnC8lpGO5Y1%2BKIe4XcDFj3nqCw7vSSkMYppboVli" + + "tdgGeZsk32%2BZxEN2M5o1LmWxMusBYMu1VIr29RgNmBakcNaFXBw6R0C0Yhtg3BCOBp%2FQxy%2FlcsuFMeO8Qvijvk%2BOps" + + "9Aak2FfHWq4Q8c4BtySHO4eomLCEuipyXURjzeVQGYRE7mLWNC22RK0xIFITzWRDPgsun4IrFn1gQ0evryx%2FE%2Bz4o5Oohv" + + "R6sczZjId7XgQ%2FVE%2B9Om5rj%2B%2FCjRRSzsoMyUCjwlaTHgq2ruIBaU6jEG61ayrG777RBLp%2BPR6krofyFP2Y68N402" + + "5%2BQ4xTi6ccPFxd9mC8Ot15NI9T7umiDpSd1nrUT4kFLkb96mZR6vzTAERKCpoEpCu6OPbTohCRThtc%2FU%2Bs3AIpuH9ygI" + + "hwm7cNYzXGspXSKP0I5qUP9Ruz3e2pRm1%2B00i2Fxne77ecCxRuor1l2Dy1Ifz6o%2F6%2Fso%2B78p%2Bb0%2FDz%2BGdI%2" + + "F&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=DOVMqh17xn4wl%2" + + "Byvifm4McMsBjKDVf1eqph9ss362ZEbp2nkAIXUzkNWv72I96iNK3r%2BYbAxY9dwZ8Z7jKzCGiJ9Qm34YSfPvzXWl3EVrdI86" + + "9U%2BH6HGIMqVew3cVdr4q3Qv9ZBIhdRxbrDu%2F%2BnMjdf8mzbgcQnfjSQiQIYWxOIXZFyxKsyrxJtIam4hoNwUT7mMN6Rjg" + + "zvyeS3mARsTJdcI0Vn4ItiprhLgIkD18V9WIdeSZR0gfRaFj8PKdmXCD%2FIa0cKgjhVKoiIZisV4vcthBOeDIqBORL2Ad3Xhc" + + "NRQ3%2BcpAf65zHGMBAv1aRy7Bmv0%2B%2BOvCavufykqI2EHtg%3D%3D"); + + httpReq.setParameter(HTTP_FORM_SAMLREQ, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_FORM_SAMLREQ).substring(HTTP_FORM_SAMLREQ_PARAM.length()), "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGALG, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGALG).substring(HTTP_REDIRECT_SIGALG_PARAM.length()), + "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGNATURE, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGNATURE).substring(HTTP_REDIRECT_SIGNATURE_PARAM.length()), + "UTF-8")); + + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, + comparator); + Assert.fail("Wrong signature not detected"); + + } catch (final Pvp2Exception e) { + org.springframework.util.Assert.isInstanceOf(SamlSigningException.class, e, "Wrong Exception type"); + Assert.assertEquals("Wrong errorCode", "internal.pvp.10", e.getErrorId()); + Assert.assertNotNull("No error params", e.getParams()); + Assert.assertEquals("Wrong param size", 1, e.getParams().length); + + } + + } + + @Test + public void decodeRequestExpired() throws MessageDecodingException, + SecurityException, IOException, Pvp2Exception, CredentialsNotAvailableException, + XMLParserException, UnmarshallingException { final String serviceUrl = "http://testservice.org"; - - final IPvp2MetadataProvider metadataProvider = + + final IPvp2MetadataProvider metadataProvider = metadataResolverFactory.createMetadataProvider( - "classpath:/data/metadata_1.xml", null, "jUnit metadata resolver", null); + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); - final boolean isSpEndPoint = false; final URIComparator comparator = new EaafUriCompare(serviceUrl); httpReq.setMethod("GET"); httpReq.setRequestURI("http://testservice.org"); - httpReq.setParameter("SAMLRequest","nVRNb9swDD13wP6DoXvkr/RjQuzCSFAgQDd0TbfDLoVi0642Wcok2kn766c4duABWw++SdQj+fhIanF7qKXXgrFCq4SENCAeqFwXQlUJ+fZ0N7sht+nC8lpGO5Y1+KIe4XcDFj3nqCw7vSSkMYppboVlitdgGeZsk32+ZxEN2M5o1LmWxMusBYMu1VIr29RgNmBakcNaFXBw6R0C0Yhtg3BCOBp/Qxy/lcsuFMeO8Qvijvk+Ops9Aak2FfHWq4Q8c4BtySHO4eomLCEuipyXURjzeVQGYRE7mLWNC22RK0xIFITzWRDPgsun4IrFn1gQ0evryx/E+z4o5OohvR6sczZjId7XgQ/VE+9Om5rj+/CjRRSzsoMyUCjwlaTHgq2ruIBaU6jEG61ayrG777RBLp+PR6krofyFP2Y68N4025+Q4xTi6ccPFxd9mC8Ot15NI9T7umiDpSd1nrUT4kFLkb96mZR6vzTAERKCpoEpCu6OPbTohCRThtc/U+s3AIpuH9ygIhwm7cNYzXGspXSKP0I5qUP9Ruz3e2pRm1+00i2Fxne77ecCxRuor1l2Dy1Ifz6o/6/so+78p+b0/Dz+GdI/"); - httpReq.setParameter("SigAlg","http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"); - httpReq.setParameter("Signature","DOVMqh17xn4wl+yvifm4McMsBjKDVf1eqph9ss362ZEbp2nkAIXUzkNWv72I96iNK3r+YbAxY9dwZ8Z7jKzCGiJ9Qm34YSfPvzXWl3EVrdI869U+H6HGIMqVew3cVdr4q3Qv9ZBIhdRxbrDu/+nMjdf8mzbgcQnfjSQiQIYWxOIXZFyxKsyrxJtIam4hoNwUT7mMN6RjgzvyeS3mARsTJdcI0Vn4ItiprhLgIkD18V9WIdeSZR0gfRaFj8PKdmXCD/Ia0cKgjhVKoiIZisV4vcthBOeDIqBORL2Ad3XhcNRQ3+cpAf65zHGMBAv1aRy7Bmv0++OvCavufykqI2EHtg=="); + httpReq.setQueryString("SAMLRequest=nVRNb9swDD13wP6DoXvkj2RFJsQujAQFAnTD1nQ97FIoNu1qkyVPop20v36KYwcusPVgQ" + + "AeLeiQfH0mvbo6V9FowVmgVk5AGxAOV6VyoMiY%2FHm5nS3KTrCyvZFSztMFndQ9%2FGrDoOUdl2fklJo1RTHMrLFO8AsswY7v" + + "0yx2LaMBqo1FnWhIvtRYMulRrrWxTgdmBaUUGW5XD0aV3CEQj9g3CGeFovIU4fhuXXSiOHeNnxJr5PjqbPQOpNiXxtpuYPHGAf" + + "cFhnsH1MixgnucZL6JwzhdREYT53MGsbVxoi1xhTKIgCmZBNAsWD8Fn5s6na7qMwp%2FEexwUcvWQXg%2FWOZuxEO%2FrwIfqi" + + "XerTcXxffjJIvJZ0UEZKBT4QpJTwdZVnEOlKZTilZYt5djda22Qy6fTp9SlUP7KHzMdeO%2Ba%2FS%2FIcArx5OOHq6s%2BzFe" + + "H226mEep9XbTB0pO6zNoZ8U1Lkb14qZT6sDbAEWKCpoEpCtanHlp0QpIpw%2BtfqPUbAHm3D25QEY6T9mGs5jjWWjrF76GY1KF" + + "%2BIw6HA7WozW9a6pZC47vd9jOB4hXU9zS9gxakvxjU%2F1f2UXf%2BU3NyeR7%2FGZK%2F&SigAlg=http%3A%2F%2Fwww.w3" + + ".org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=JogFpk2oimCnBCgE7eZx%2B6yoJu2ZCgus5vM1opkTk" + + "OLM9qgNMUJJJbIeA3j2TR%2BWx3pUApnV7ed9CuTBF94b3ELkFdaZAetfLzY8gnPLCBmcYIYkwg3bK7ZQWEBJpjNoU%2BaBHXV" + + "OgptLUt0qRWavm%2BiPOUXRWpb0PtgvApTieRk32gBfZbuPOltWjrRCKaa2ulKBjB34LqYdAaIWaVix2sGvg128p6lC7bQ%2Fz" + + "wmz6j8S5Vn8snvlg48MlBldTWKSZrUERx3MwTyaB17A617XmX2QKo8fGCQ6O7FF4umFyWGAlujI%2FwqafTfPlaNX2usHynHS6" + + "XkH5HWCDSAe3%2BVR1w%3D%3D "); + + httpReq.setParameter(HTTP_FORM_SAMLREQ, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_FORM_SAMLREQ).substring(HTTP_FORM_SAMLREQ_PARAM.length()), "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGALG, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGALG).substring(HTTP_REDIRECT_SIGALG_PARAM.length()), + "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGNATURE, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGNATURE).substring(HTTP_REDIRECT_SIGNATURE_PARAM.length()), + "UTF-8")); + + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, + comparator); + Assert.fail("Expired message not detected"); + + } catch (final Pvp2Exception e) { + org.springframework.util.Assert.isInstanceOf(SamlMessageValidationException.class, e, + "Wrong Exception type"); + Assert.assertEquals("Wrong errorCode", "internal.pvp.11", e.getErrorId()); + Assert.assertNotNull("No error params", e.getParams()); + Assert.assertEquals("Wrong param size", 1, e.getParams().length); + + } + + } + @Test + public void decodeRequestSuccess() throws MessageDecodingException, + SecurityException, IOException, Pvp2Exception, CredentialsNotAvailableException, + XMLParserException, UnmarshallingException { + final String serviceUrl = "http://testservice.org"; + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + httpReq.setMethod("GET"); + httpReq.setRequestURI("http://testservice.org"); + httpReq.setQueryString(generateAuthnRequest(credentialProvider.getIdpMetaDataSigningCredential())); + + httpReq.setParameter(HTTP_FORM_SAMLREQ, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_FORM_SAMLREQ).substring(HTTP_FORM_SAMLREQ_PARAM.length()), "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGALG, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGALG).substring(HTTP_REDIRECT_SIGALG_PARAM.length()), + "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGNATURE, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGNATURE).substring(HTTP_REDIRECT_SIGNATURE_PARAM.length()), + "UTF-8")); final InboundMessageInterface msg = - bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, comparator); + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, + comparator); Assert.assertNotNull("PVP msg is null", msg); Assert.assertNull("RelayState is not null", msg.getRelayState()); Assert.assertNotNull("AuthnReq is null", msg.getInboundMessage()); Assert.assertNotNull("EntityId is null", msg.getEntityID()); - Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg.getEntityID()); - Assert.assertFalse("Wrong isVerified flag", msg.isVerified()); + Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg + .getEntityID()); + Assert.assertTrue("Wrong isVerified flag", msg.isVerified()); } @@ -143,88 +376,123 @@ public class RedirectBindingTest { final IPvp2MetadataProvider metadataProvider = null; - final boolean isSpEndPoint = false; final URIComparator comparator = new EaafUriCompare(serviceUrl); - final InboundMessageInterface msg = - bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, comparator); + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, + comparator); Assert.assertNotNull("PVP msg is null", msg); Assert.assertNotNull("RelayState is not null", msg.getRelayState()); Assert.assertEquals("RelayState not match", relayState, msg.getRelayState()); Assert.assertNotNull("AuthnReq is null", msg.getInboundMessage()); Assert.assertNotNull("EntityId is null", msg.getEntityID()); - Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg.getEntityID()); + Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg + .getEntityID()); Assert.assertFalse("Wrong isVerified flag", msg.isVerified()); } - @Ignore @Test - public void decodeResponseSuccess() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + public void decodeResponseSuccess() throws MessageDecodingException, SecurityException, IOException, + Pvp2Exception, CredentialsNotAvailableException, XMLParserException, UnmarshallingException { final String serviceUrl = "http://testservice.org"; - final IPvp2MetadataProvider metadataProvider = null; + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); - final boolean isSpEndPoint = false; final URIComparator comparator = new EaafUriCompare(serviceUrl); - final String b64AuthnReq = Base64.getEncoder().encodeToString(IOUtils.toByteArray( - RedirectBindingTest.class.getResourceAsStream("/data/Response_with_sig_1.xml"))); - httpReq.setMethod("POST"); - httpReq.addParameter("SAMLRequest", b64AuthnReq); + httpReq.setMethod("GET"); + httpReq.setRequestURI("http://testservice.org"); + httpReq.setQueryString(generateResponse(credentialProvider.getIdpMetaDataSigningCredential())); + httpReq.setParameter(HTTP_FORM_SAMLRESP, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_FORM_SAMLRESP).substring(HTTP_FORM_SAMLRESP_PARM.length()), "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGALG, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGALG).substring(HTTP_REDIRECT_SIGALG_PARAM.length()), + "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGNATURE, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGNATURE).substring(HTTP_REDIRECT_SIGNATURE_PARAM.length()), + "UTF-8")); final InboundMessageInterface msg = - bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, comparator); + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, + comparator); Assert.assertNotNull("PVP msg is null", msg); Assert.assertNull("RelayState is not null", msg.getRelayState()); Assert.assertNotNull("Response is null", msg.getInboundMessage()); Assert.assertNotNull("EntityId is null", msg.getEntityID()); - Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata", msg.getEntityID()); - Assert.assertFalse("Wrong isVerified flag", msg.isVerified()); + Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg + .getEntityID()); + Assert.assertTrue("Wrong isVerified flag", msg.isVerified()); } - @Ignore @Test - public void decodeResponseSuccessWithRelayState() throws MessageDecodingException, SecurityException, - IOException, Pvp2Exception { + public void decodeResponseSuccessWithRelayStateAndMetadataReload() throws MessageDecodingException, + SecurityException, IOException, Pvp2Exception, CredentialsNotAvailableException, + XMLParserException, UnmarshallingException { final String serviceUrl = "http://testservice.org"; final String relayState = RandomStringUtils.randomAlphanumeric(10); - final String b64AuthnReq = Base64.getEncoder().encodeToString(IOUtils.toByteArray( - RedirectBindingTest.class.getResourceAsStream("/data/Response_with_sig_1.xml"))); - httpReq.setMethod("POST"); - httpReq.addParameter("SAMLRequest", b64AuthnReq); - httpReq.addParameter("RelayState", relayState); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_wrong_sig.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); - final IPvp2MetadataProvider metadataProvider = null; + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_junit_keystore.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); - final boolean isSpEndPoint = false; - final URIComparator comparator = new EaafUriCompare(serviceUrl); + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + mockServerUrl.url().toString(), + null, "jUnit test", httpClientFactory.getHttpClient()); + httpReq.setMethod("GET"); + httpReq.setRequestURI("http://testservice.org"); + httpReq.setParameter(HTTP_FORM_RELAYSTATE, relayState); + httpReq.setQueryString(generateResponse(credentialProvider.getIdpMetaDataSigningCredential())); + + httpReq.setParameter(HTTP_FORM_SAMLRESP, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_FORM_SAMLRESP).substring(HTTP_FORM_SAMLRESP_PARM.length()), "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGALG, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGALG).substring(HTTP_REDIRECT_SIGALG_PARAM.length()), + "UTF-8")); + httpReq.setParameter(HTTP_REDIRECT_SIGNATURE, URLDecoder.decode(URISupport.getRawQueryStringParameter( + httpReq.getQueryString(), HTTP_REDIRECT_SIGNATURE).substring(HTTP_REDIRECT_SIGNATURE_PARAM.length()), + "UTF-8")); + + final URIComparator comparator = new EaafUriCompare(serviceUrl); + final InboundMessageInterface msg = - bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, comparator); + bindingImpl.decode(httpReq, httpResp, metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, + comparator); Assert.assertNotNull("PVP msg is null", msg); - Assert.assertNotNull("RelayState is not null", msg.getRelayState()); + Assert.assertNotNull("RelayState is null", msg.getRelayState()); Assert.assertEquals("RelayState not match", relayState, msg.getRelayState()); Assert.assertNotNull("Response is null", msg.getInboundMessage()); Assert.assertNotNull("EntityId is null", msg.getEntityID()); - Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata", msg.getEntityID()); - Assert.assertFalse("Wrong isVerified flag", msg.isVerified()); + Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg + .getEntityID()); + Assert.assertTrue("Wrong isVerified flag", msg.isVerified()); } @Test public void encodeRequestSuccess() throws MessageDecodingException, SecurityException, MessageEncodingException, XMLParserException, UnmarshallingException, - CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { - //build test data + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, + Pvp2Exception { + // build test data final String serviceUrl = "http://testservice.org"; final String relayState = null; final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( @@ -234,7 +502,7 @@ public class RedirectBindingTest { bindingImpl.encodeRequest(httpReq, httpResp, authnReq, serviceUrl, relayState, credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); - //validate + // validate Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); @@ -246,33 +514,33 @@ public class RedirectBindingTest { Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); Assert.assertTrue("Wrong redirect URL", - locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLREQ)); + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLREQ_PARAM)); - final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLREQ, true); + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLREQ_PARAM, true); Assert.assertNotNull("Saml msg is null", respSamlMsg); Assert.assertFalse("Saml msg is empty", respSamlMsg.isEmpty()); - final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG, true); + final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG_PARAM, true); Assert.assertNotNull("SigAlg is null", sigAlg); Assert.assertFalse("SigAlg is empty", sigAlg.isEmpty()); Assert.assertEquals("SigAlg not match", PvpConstants.DEFAULT_SIGNING_METHODE_RSA, URLDecoder.decode(sigAlg, "UTF-8")); - final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE, true); + final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE_PARAM, true); Assert.assertNotNull("Saml signature null", samlSig); Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); - final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, false); + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE_PARAM, false); Assert.assertNull("RelayState parameter", respRelayState); } - @Test public void encodeRequestSuccessEcdsa() throws MessageDecodingException, SecurityException, MessageEncodingException, XMLParserException, UnmarshallingException, - CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { - //build test data + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, + Pvp2Exception { + // build test data final String serviceUrl = "http://testservice.org"; final String relayState = null; final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( @@ -282,8 +550,8 @@ public class RedirectBindingTest { bindingImpl.encodeRequest(httpReq, httpResp, authnReq, serviceUrl, relayState, credentialProvider.getIdpAssertionSigningCredential(), pendingReq); - //validate - //validate + // validate + // validate Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); @@ -295,34 +563,34 @@ public class RedirectBindingTest { Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); Assert.assertTrue("Wrong redirect URL", - locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLREQ)); + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLREQ_PARAM)); - final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLREQ, true); + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLREQ_PARAM, true); Assert.assertNotNull("Saml msg is null", respSamlMsg); Assert.assertFalse("Saml msg is empty", respSamlMsg.isEmpty()); - final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG, true); + final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG_PARAM, true); Assert.assertNotNull("SigAlg is null", sigAlg); Assert.assertFalse("SigAlg is empty", sigAlg.isEmpty()); Assert.assertEquals("SigAlg not match", PvpConstants.DEFAULT_SIGNING_METHODE_EC, URLDecoder.decode(sigAlg, "UTF-8")); - final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE, true); + final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE_PARAM, true); Assert.assertNotNull("Saml signature null", samlSig); Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); - final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, false); + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE_PARAM, false); Assert.assertNull("RelayState parameter", respRelayState); - } @Test public void encodeRequestSuccessWithRelayState() throws MessageDecodingException, SecurityException, MessageEncodingException, XMLParserException, UnmarshallingException, - CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, + Pvp2Exception { - //build test data + // build test data final String serviceUrl = "http://testservice.org"; final String relayState = RandomStringUtils.randomAlphabetic(10); final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( @@ -332,8 +600,7 @@ public class RedirectBindingTest { bindingImpl.encodeRequest(httpReq, httpResp, authnReq, serviceUrl, relayState, credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); - - //validate + // validate Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); @@ -345,36 +612,36 @@ public class RedirectBindingTest { Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); Assert.assertTrue("Wrong redirect URL", - locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLREQ)); + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLREQ_PARAM)); - final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLREQ, true); + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLREQ_PARAM, true); Assert.assertNotNull("Saml msg is null", respSamlMsg); Assert.assertFalse("Saml msg is empty", respSamlMsg.isEmpty()); - final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG, true); + final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG_PARAM, true); Assert.assertNotNull("SigAlg is null", sigAlg); Assert.assertFalse("SigAlg is empty", sigAlg.isEmpty()); Assert.assertEquals("SigAlg not match", PvpConstants.DEFAULT_SIGNING_METHODE_RSA, URLDecoder.decode(sigAlg, "UTF-8")); - final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE, true); + final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE_PARAM, true); Assert.assertNotNull("Saml signature null", samlSig); Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); - final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, false); + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE_PARAM, false); Assert.assertNotNull("RelayState parameter", respRelayState); Assert.assertEquals("RelayState not match", relayState, URLDecoder.decode(respRelayState, "UTF-8")); - } @Test public void encodeResponseSuccessWithRelayState() throws MessageDecodingException, SecurityException, MessageEncodingException, XMLParserException, UnmarshallingException, - CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, + Pvp2Exception { - //build test data + // build test data final String serviceUrl = "http://testservice.org"; final String relayState = RandomStringUtils.randomAlphabetic(10); final StatusResponseType authnReq = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( @@ -384,8 +651,7 @@ public class RedirectBindingTest { bindingImpl.encodeResponse(httpReq, httpResp, authnReq, serviceUrl, relayState, credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); - - //validate + // validate Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); @@ -397,23 +663,23 @@ public class RedirectBindingTest { Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); Assert.assertTrue("Wrong redirect URL", - locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLRESP)); + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLRESP_PARM)); - final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLRESP, true); + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLRESP_PARM, true); Assert.assertNotNull("Saml msg is null", respSamlMsg); Assert.assertFalse("Saml msg is empty", respSamlMsg.isEmpty()); - final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG, true); + final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG_PARAM, true); Assert.assertNotNull("SigAlg is null", sigAlg); Assert.assertFalse("SigAlg is empty", sigAlg.isEmpty()); Assert.assertEquals("SigAlg not match", PvpConstants.DEFAULT_SIGNING_METHODE_RSA, URLDecoder.decode(sigAlg, "UTF-8")); - final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE, true); + final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE_PARAM, true); Assert.assertNotNull("Saml signature null", samlSig); Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); - final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, false); + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE_PARAM, false); Assert.assertNotNull("RelayState parameter", respRelayState); Assert.assertEquals("RelayState not match", relayState, URLDecoder.decode(respRelayState, "UTF-8")); @@ -423,9 +689,10 @@ public class RedirectBindingTest { @Test public void encodeResponseSuccess() throws MessageDecodingException, SecurityException, MessageEncodingException, XMLParserException, UnmarshallingException, - CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, + Pvp2Exception { - //build test data + // build test data final String serviceUrl = "http://testservice.org"; final String relayState = null; final StatusResponseType authnReq = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( @@ -435,8 +702,7 @@ public class RedirectBindingTest { bindingImpl.encodeResponse(httpReq, httpResp, authnReq, serviceUrl, relayState, credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); - - //validate + // validate Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); @@ -448,23 +714,23 @@ public class RedirectBindingTest { Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); Assert.assertTrue("Wrong redirect URL", - locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLRESP)); + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLRESP_PARM)); - final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLRESP, true); + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLRESP_PARM, true); Assert.assertNotNull("Saml msg is null", respSamlMsg); Assert.assertFalse("Saml msg is empty", respSamlMsg.isEmpty()); - final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG, true); + final String sigAlg = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGALG_PARAM, true); Assert.assertNotNull("SigAlg is null", sigAlg); Assert.assertFalse("SigAlg is empty", sigAlg.isEmpty()); Assert.assertEquals("SigAlg not match", PvpConstants.DEFAULT_SIGNING_METHODE_RSA, URLDecoder.decode(sigAlg, "UTF-8")); - final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE, true); + final String samlSig = checkMessagePart(locationHeader, HTTP_REDIRECT_SIGNATURE_PARAM, true); Assert.assertNotNull("Saml signature null", samlSig); Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); - final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, false); + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE_PARAM, false); Assert.assertNull("RelayState parameter", respRelayState); } @@ -490,4 +756,45 @@ public class RedirectBindingTest { } + private String generateAuthnRequest(EaafX509Credential credential) throws Pvp2Exception, + XMLParserException, UnmarshallingException { + final MockHttpServletRequest intHttpReq = new MockHttpServletRequest(); + final MockHttpServletResponse intHttpResp = new MockHttpServletResponse(); + + final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + RedirectBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + authnReq.setIssueInstant(DateTime.now()); + + bindingImpl.encodeRequest(intHttpReq, intHttpResp, authnReq, "http://testservice.org", null, + credential, pendingReq); + + Assert.assertEquals("http StatusCode", 302, intHttpResp.getStatus()); + final String locationHeader = intHttpResp.getHeader("Location"); + Assert.assertNotNull("Location header is null", locationHeader); + return locationHeader.split("\\?")[1]; + + } + + private String generateResponse(EaafX509Credential credential) throws Pvp2Exception, + XMLParserException, UnmarshallingException { + new MockHttpServletRequest(); + final MockHttpServletRequest intHttpReq = new MockHttpServletRequest(); + final MockHttpServletResponse intHttpResp = new MockHttpServletResponse(); + + final StatusResponseType authnReq = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + RedirectBindingTest.class.getResourceAsStream("/data/Response_without_sig_1.xml")); + authnReq.setIssueInstant(DateTime.now()); + + bindingImpl.encodeResponse(intHttpReq, intHttpResp, authnReq, "http://testservice.org", null, + credential, pendingReq); + + Assert.assertEquals("http StatusCode", 302, intHttpResp.getStatus()); + final String locationHeader = intHttpResp.getHeader("Location"); + Assert.assertNotNull("Location header is null", locationHeader); + return locationHeader.split("\\?")[1]; + + } + } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/SoapBindingTest.java b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/SoapBindingTest.java new file mode 100644 index 00000000..1125d30e --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/SoapBindingTest.java @@ -0,0 +1,214 @@ +package at.gv.egiz.eaaf.modules.pvp2.test.binding; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; + +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.SoapBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare; +import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; + +import org.joda.time.DateTime; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.Marshaller; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.saml2.core.RequestAbstractType; +import org.opensaml.saml.saml2.core.StatusResponseType; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.opensaml.soap.soap11.Envelope; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import net.shibboleth.utilities.java.support.logic.Constraint; +import net.shibboleth.utilities.java.support.net.URIComparator; +import net.shibboleth.utilities.java.support.xml.SerializeSupport; +import net.shibboleth.utilities.java.support.xml.XMLParserException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({"/spring/test_eaaf_pvp.beans.xml"}) +@TestPropertySource(locations = {"/config/config_1.props"}) +public class SoapBindingTest { + + @Autowired private SoapBinding bindingImpl; + @Autowired private PvpMetadataResolverFactory metadataResolverFactory; + @Autowired private DummyCredentialProvider credentialProvider; + + protected MockHttpServletRequest httpReq; + protected MockHttpServletResponse httpResp; + protected IRequest pendingReq; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void classInitializer() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * Test initializer. + * + */ + @Before + public void initialize() { + httpReq = new MockHttpServletRequest(); + httpResp = new MockHttpServletResponse(); + + pendingReq = new TestRequestImpl(); + + } + + @Test + public void withoutSig() throws Pvp2Exception, MarshallingException, XMLParserException, UnmarshallingException { + final String serviceUrl = "https://localhost/pvp2/post"; + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + final RequestAbstractType payload = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + payload.setIssueInstant(DateTime.now()); + final Envelope enveloped = Saml2Utils.buildSoap11Envelope(payload); + final Marshaller marshaller = Constraint.isNotNull( + XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(enveloped), + "SOAP Envelope marshaller not available"); + final ByteArrayOutputStream arrayOut = new ByteArrayOutputStream(); + SerializeSupport.writeNode(marshaller.marshall(enveloped), arrayOut); + httpReq.setMethod("POST"); + httpReq.setContentType("text/xml"); + httpReq.setContent(arrayOut.toByteArray()); + + + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, + SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); + Assert.fail("Missing signature not detected"); + + } catch (final Pvp2Exception e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.02", e.getErrorId()); + + } + } + + @Test + public void wrongSignature() throws Pvp2Exception, MarshallingException, XMLParserException, UnmarshallingException { + final String serviceUrl = "https://localhost/pvp2/post"; + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + final RequestAbstractType payload = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_with_sig_1.xml")); + payload.setIssueInstant(DateTime.now()); + final Envelope enveloped = Saml2Utils.buildSoap11Envelope(payload); + final Marshaller marshaller = Constraint.isNotNull( + XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(enveloped), + "SOAP Envelope marshaller not available"); + final ByteArrayOutputStream arrayOut = new ByteArrayOutputStream(); + SerializeSupport.writeNode(marshaller.marshall(enveloped), arrayOut); + httpReq.setMethod("POST"); + httpReq.setContentType("text/xml"); + httpReq.setContent(arrayOut.toByteArray()); + + + try { + bindingImpl.decode(httpReq, httpResp, metadataProvider, + SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); + Assert.fail("Missing signature not detected"); + + } catch (final Pvp2Exception e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.10", e.getErrorId()); + + } + } + + @Test + public void validSignature() throws Pvp2Exception, MarshallingException, XMLParserException, + UnmarshallingException, CredentialsNotAvailableException { + final String serviceUrl = "https://localhost/pvp2/post"; + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + final RequestAbstractType payload = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_with_sig_1.xml")); + payload.setIssueInstant(DateTime.now()); + final RequestAbstractType signedPayload = Saml2Utils.signSamlObject( + payload, credentialProvider.getIdpMetaDataSigningCredential(), true); + + final Envelope enveloped = Saml2Utils.buildSoap11Envelope(signedPayload); + final Marshaller marshaller = Constraint.isNotNull( + XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(enveloped), + "SOAP Envelope marshaller not available"); + final ByteArrayOutputStream arrayOut = new ByteArrayOutputStream(); + SerializeSupport.writeNode(marshaller.marshall(enveloped), arrayOut); + httpReq.setMethod("POST"); + httpReq.setContentType("text/xml"); + httpReq.setContent(arrayOut.toByteArray()); + + + final InboundMessageInterface msg = + bindingImpl.decode(httpReq, httpResp, metadataProvider, + SPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); + + Assert.assertNotNull("Inbound msg is null", msg); + Assert.assertNotNull("AuthnReq is null", msg.getInboundMessage()); + Assert.assertNotNull("EntityId is null", msg.getEntityID()); + Assert.assertEquals("EntityId not match", "https://demo.egiz.gv.at/demoportal_demologin/", msg.getEntityID()); + Assert.assertTrue("Wrong isVerified flag", msg.isVerified()); + + } + + @Test + public void encodeResponse() throws XMLParserException, UnmarshallingException, + Pvp2Exception, CredentialsNotAvailableException, UnsupportedEncodingException { + final String serviceUrl = "http://testservice.org"; + + final StatusResponseType response = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/Response_without_sig_1.xml")); + + bindingImpl.encodeResponse(httpReq, httpResp, response, serviceUrl, null, + credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); + + Assert.assertEquals("http StatusCode", 200, httpResp.getStatus()); + Assert.assertNotNull("PVP msg is null", httpResp.getContentLength()); + + Assert.assertEquals("ContentType", "text/xml", httpResp.getContentType()); + Assert.assertEquals("Encoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String http = httpResp.getContentAsString(); + Assert.assertNotNull("http body is null", http); + Assert.assertFalse("http body is empty", http.isEmpty()); + + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/metadata/MetadataBuilderTest.java b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/metadata/MetadataBuilderTest.java new file mode 100644 index 00000000..2d46f102 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/metadata/MetadataBuilderTest.java @@ -0,0 +1,298 @@ +package at.gv.egiz.eaaf.modules.pvp2.test.metadata; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactoryConfigurationError; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.Attribute; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.metadata.ContactPerson; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.Organization; +import org.opensaml.saml.saml2.metadata.RequestedAttribute; +import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator; +import org.opensaml.security.SecurityException; +import org.opensaml.security.credential.Credential; +import org.opensaml.security.x509.BasicX509Credential; +import org.opensaml.xmlsec.signature.support.SignatureException; +import org.opensaml.xmlsec.signature.support.SignatureValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import net.shibboleth.utilities.java.support.xml.XMLParserException; + + + + + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ "/spring/test_eaaf_pvp.beans.xml" }) +@TestPropertySource(locations = { "/config/config_1.props" }) +public class MetadataBuilderTest { + + @Autowired private PvpMetadataBuilder metadataBuilder; + @Autowired private DummyCredentialProvider credentialProvider; + + private static CertificateFactory fact; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void classInitializer() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + fact = CertificateFactory.getInstance("X.509"); + } + + @Test + public void buildIdpMetadata() throws CredentialsNotAvailableException, EaafException, + SecurityException, TransformerFactoryConfigurationError, MarshallingException, + TransformerException, ParserConfigurationException, IOException, SignatureException, + XMLParserException, UnmarshallingException, CertificateException { + + final IPvpMetadataBuilderConfiguration config = idpMetadataConfig(false, true); + + //generate metadata + final String metadata = metadataBuilder.buildPvpMetadata(config); + + //validate + final EntityDescriptor entity = validateMetadata(metadata); + Assert.assertNotNull("IDPSSODescr. is null", entity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS)); + Assert.assertNull("IDPSSODescr. is null", entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS)); + + } + + @Test + public void buildSpMetadata() throws CredentialsNotAvailableException, EaafException, + SecurityException, TransformerFactoryConfigurationError, MarshallingException, + TransformerException, ParserConfigurationException, IOException, SignatureException, + XMLParserException, UnmarshallingException, CertificateException { + + final IPvpMetadataBuilderConfiguration config = idpMetadataConfig(true, false); + + //generate metadata + final String metadata = metadataBuilder.buildPvpMetadata(config); + + //validate + final EntityDescriptor entity = validateMetadata(metadata); + Assert.assertNull("IDPSSODescr. is null", entity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS)); + Assert.assertNotNull("IDPSSODescr. is null", entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS)); + + } + + @Test + public void buildSpAndIdpMetadata() throws CredentialsNotAvailableException, EaafException, + SecurityException, TransformerFactoryConfigurationError, MarshallingException, + TransformerException, ParserConfigurationException, IOException, SignatureException, + XMLParserException, UnmarshallingException, CertificateException { + + final IPvpMetadataBuilderConfiguration config = idpMetadataConfig(true, true); + + //generate metadata + final String metadata = metadataBuilder.buildPvpMetadata(config); + + //validate + final EntityDescriptor entity = validateMetadata(metadata); + Assert.assertNotNull("IDPSSODescr. is null", entity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS)); + Assert.assertNotNull("IDPSSODescr. is null", entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS)); + + } + + private EntityDescriptor validateMetadata(String metadata) throws UnsupportedEncodingException, + XMLParserException, UnmarshallingException, SignatureException, CertificateException { + Assert.assertNotNull("Metadata is null", metadata); + Assert.assertFalse("Metadata is empty", metadata.isEmpty()); + + final EntityDescriptor entity = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + new ByteArrayInputStream(metadata.getBytes("UTF-8"))); + + Assert.assertNotNull("Unmarshalling failed", entity); + Assert.assertNotNull("EntityId is null", entity.getEntityID()); + + Assert.assertNotNull("Signature is null", entity.getSignature()); + final SAMLSignatureProfileValidator sigValidator = new SAMLSignatureProfileValidator(); + sigValidator.validate(entity.getSignature()); + + final Credential cred = new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/junit_metadata_sig_cert.crt"))); + SignatureValidator.validate(entity.getSignature(), cred); + + return entity; + } + + private IPvpMetadataBuilderConfiguration idpMetadataConfig(boolean buildSpInfos, boolean buildIdpInfos) { + return new IPvpMetadataBuilderConfiguration() { + + @Override + public boolean wantAuthnRequestSigned() { + return true; + } + + @Override + public boolean wantAssertionSigned() { + return true; + } + + @Override + public String getSpSloSoapBindingUrl() { + return RandomStringUtils.randomAlphabetic(10); + + } + + @Override + public String getSpSloRedirectBindingUrl() { + return RandomStringUtils.randomAlphabetic(10); + + } + + @Override + public String getSpSloPostBindingUrl() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public Collection<RequestedAttribute> getSpRequiredAttributes() { + return null; + } + + @Override + public String getSpNameForLogging() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public String getSpAssertionConsumerServiceRedirectBindingUrl() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public String getSpAssertionConsumerServicePostBindingUrl() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public List<String> getSpAllowedNameIdTypes() { + return Arrays.asList(NameIDType.PERSISTENT); + } + + @Override + public Credential getRequestorResponseSigningCredentials() throws CredentialsNotAvailableException { + return credentialProvider.getIdpAssertionSigningCredential(); + } + + @Override + public Organization getOrgansiationInformation() { + return null; + } + + @Override + public int getMetadataValidUntil() { + return 10; + } + + @Override + public EaafX509Credential getMetadataSigningCredentials() throws CredentialsNotAvailableException { + return credentialProvider.getIdpMetaDataSigningCredential(); + } + + @Override + public String getIdpWebSsoRedirectBindingUrl() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public String getIdpWebSsoPostBindingUrl() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public String getIdpSloRedirectBindingUrl() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public String getIdpSloPostBindingUrl() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public List<String> getIdpPossibleNameIdTypes() { + return Arrays.asList(NameIDType.PERSISTENT); + } + + @Override + public List<Attribute> getIdpPossibleAttributes() { + return null; + } + + @Override + public String getEntityID() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public String getEntityFriendlyName() { + return RandomStringUtils.randomAlphabetic(10); + } + + @Override + public Credential getEncryptionCredentials() throws CredentialsNotAvailableException { + return credentialProvider.getIdpAssertionSigningCredential(); + } + + @Override + public List<ContactPerson> getContactPersonInformation() { + return null; + } + + @Override + public boolean buildSpSsoDescriptor() { + return buildSpInfos; + } + + @Override + public boolean buildIdpSsoDescriptor() { + return buildIdpInfos; + } + + @Override + public boolean buildEntitiesDescriptorAsRootElement() { + return false; + } + }; + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/metadata/MetadataResolverTest.java b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/metadata/MetadataResolverTest.java new file mode 100644 index 00000000..f40fbc74 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/metadata/MetadataResolverTest.java @@ -0,0 +1,725 @@ +package at.gv.egiz.eaaf.modules.pvp2.test.metadata; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.transform.TransformerException; + +import at.gv.egiz.eaaf.core.impl.utils.IHttpClientFactory; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.PvpEntityCategoryFilter; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SchemaValidationFilter; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SimpleMetadataSignatureVerificationFilter; +import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; + +import org.apache.commons.io.IOUtils; +import org.joda.time.DateTime; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.config.ConfigurationService; +import org.opensaml.core.criterion.EntityIdCriterion; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.criterion.EntityRoleCriterion; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain; +import org.opensaml.saml.metadata.resolver.filter.impl.RequiredValidUntilFilter; +import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.RequestedAttribute; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml.security.impl.MetadataCredentialResolver; +import org.opensaml.security.credential.Credential; +import org.opensaml.security.credential.UsageType; +import org.opensaml.security.criteria.UsageCriterion; +import org.opensaml.security.x509.BasicX509Credential; +import org.opensaml.xmlsec.SignatureValidationConfiguration; +import org.opensaml.xmlsec.SignatureValidationParameters; +import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xmlsec.keyinfo.impl.BasicProviderKeyInfoCredentialResolver; +import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.DSAKeyValueProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.InlineX509DataProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.RSAKeyValueProvider; +import org.opensaml.xmlsec.signature.support.SignatureValidationParametersCriterion; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.w3c.dom.Element; + +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; +import net.shibboleth.utilities.java.support.resolver.CriteriaSet; +import net.shibboleth.utilities.java.support.resolver.ResolverException; +import net.shibboleth.utilities.java.support.xml.SerializeSupport; +import net.shibboleth.utilities.java.support.xml.XMLParserException; +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ "/spring/test_eaaf_pvp.beans.xml" }) +@TestPropertySource(locations = { "/config/config_1.props" }) +public class MetadataResolverTest { + + private static MockWebServer mockWebServer; + private static HttpUrl mockServerUrl; + + @Autowired + private PvpMetadataResolverFactory metadataResolverFactory; + @Autowired + private IHttpClientFactory httpClientFactory; + @Autowired private DummyCredentialProvider credentialProvider; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void classInitializer() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/metadata"); + + } + + /** + * Single test initializer. + * + */ + @Before + public void testInitializer() { + + } + + @Test + public void wrongSchema() { + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + try { + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_wrong_schema.xml", + filterChain, "jUnit test", null); + Assert.fail("Wrong XML Schema not detected"); + + } catch (final Pvp2MetadataException e) { + Assert.assertEquals("Wrong ErrorCode", "internal.pvp.08", e.getErrorId()); + Assert.assertNotNull("params null", e.getParams()); + Assert.assertEquals("Params size", 2, e.getParams().length); + Assert.assertEquals("Param[0] wrong", + "classpath:/data/pvp_metadata_wrong_schema.xml", e.getParams()[0]); + + } + + } + + @Test + public void simpleClasspathMetadataWithoutSigValidation() + throws Pvp2MetadataException, ComponentInitializationException, ResolverException, + Pvp2InternalErrorException { + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + final IPvp2MetadataProvider mdResolver = metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_wrong_sig.xml", + filterChain, "jUnit test", null); + + final EntityDescriptor entityIdNotExists = mdResolver.getEntityDescriptor( + "https://demo.egiz.gv.at/notExtist/"); + Assert.assertNull("No EntityDescripter", entityIdNotExists); + + final EntityDescriptor entityId = mdResolver.getEntityDescriptor( + "https://demo.egiz.gv.at/demoportal_demologin/"); + Assert.assertNotNull("No EntityDescripter", entityId); + + Assert.assertNotNull("Metadata provider is null", mdResolver); + final MetadataCredentialResolver resolver = createKeyInfoResolver(mdResolver); + + final CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new EntityIdCriterion("https://demo.egiz.gv.at/demoportal_demologin/")); + criteriaSet.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME)); + criteriaSet.add(new UsageCriterion(UsageType.SIGNING)); + final SignatureValidationParameters sigValCrit = new SignatureValidationParameters(); + sigValCrit.setBlacklistedAlgorithms( + ConfigurationService.get(SignatureValidationConfiguration.class) + .getBlacklistedAlgorithms()); + sigValCrit.setSignatureTrustEngine( + TrustEngineFactory.getSignatureKnownKeysTrustEngine(mdResolver)); + criteriaSet.add(new SignatureValidationParametersCriterion(sigValCrit)); + + final Iterable<Credential> keyInfos = resolver.resolve(criteriaSet); + Assert.assertNotNull("KeyInfos null", keyInfos); + + } + + @Test + public void noCredentials() { + final String metadataUrl = "classpath:/data/pvp_metadata_moaid_test.xml"; + + final List<BasicX509Credential> credentials = new ArrayList<>(); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + filterList.add(new SimpleMetadataSignatureVerificationFilter( + credentials, + metadataUrl)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + try { + metadataResolverFactory.createMetadataProvider( + metadataUrl, + filterChain, "jUnit test", null); + Assert.fail("Untrusted signature not detected"); + + } catch (final Pvp2MetadataException e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.07", e.getErrorId()); + + } + + } + + @Test + public void wrongCredentials() throws CertificateException { + final String metadataUrl = "classpath:/data/pvp_metadata_moaid_test.xml"; + + final List<BasicX509Credential> credentials = new ArrayList<>(); + final CertificateFactory fact = CertificateFactory.getInstance("X.509"); + final BasicX509Credential credential = new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/assertion_sig_cert.crt"))); + credentials.add(credential); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + filterList.add(new SimpleMetadataSignatureVerificationFilter( + credentials, + metadataUrl)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + try { + metadataResolverFactory.createMetadataProvider( + metadataUrl, + filterChain, "jUnit test", null); + Assert.fail("Untrusted signature not detected"); + + } catch (final Pvp2MetadataException e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.07", e.getErrorId()); + + } + + } + + @Test + public void validCredentialsInvalidSig() throws CertificateException, Pvp2MetadataException, + ResolverException { + final String metadataUrl = "classpath:/data/pvp_metadata_moaid_test.xml"; + + final List<BasicX509Credential> credentials = new ArrayList<>(); + final CertificateFactory fact = CertificateFactory.getInstance("X.509"); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/assertion_sig_cert.crt")))); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/metadata_sig_cert.crt")))); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + filterList.add(new SimpleMetadataSignatureVerificationFilter( + credentials, + metadataUrl)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + try { + metadataResolverFactory.createMetadataProvider( + metadataUrl, + filterChain, "jUnit test", null); + Assert.fail("Untrusted signature not detected"); + + } catch (final Pvp2MetadataException e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.07", e.getErrorId()); + + } + + } + + @Test + public void metadataSignatureValidCredentials() throws CertificateException, Pvp2MetadataException, + ResolverException, XMLParserException, UnmarshallingException, SamlSigningException, + CredentialsNotAvailableException, MarshallingException, TransformerException, IOException { + + final String metadataUrl = "classpath:/data/pvp_metadata_valid.xml"; + + final List<BasicX509Credential> credentials = new ArrayList<>(); + final CertificateFactory fact = CertificateFactory.getInstance("X.509"); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/metadata_sig_cert.crt")))); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/assertion_sig_cert.crt")))); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/junit_metadata_sig_cert.crt")))); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + filterList.add(new SimpleMetadataSignatureVerificationFilter( + credentials, + metadataUrl)); + filterList.add(new PvpEntityCategoryFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + final IPvp2MetadataProvider mdResolver = metadataResolverFactory.createMetadataProvider( + metadataUrl, + filterChain, "jUnit test", httpClientFactory.getHttpClient()); + + final EntityDescriptor entityIdNotExists = mdResolver.getEntityDescriptor( + "https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/metadata"); + Assert.assertNotNull("No EntityDescripter", entityIdNotExists); + + } + + @Test + public void metadataSignatureValidCredentialsSecond() throws CertificateException, Pvp2MetadataException, + ResolverException, XMLParserException, UnmarshallingException, SamlSigningException, + CredentialsNotAvailableException, MarshallingException, TransformerException, IOException { + + final EntityDescriptor metadata = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + MetadataResolverTest.class.getResourceAsStream("/data/pvp_metadata_valid_with_entityCategory.xml")); + metadata.setValidUntil(DateTime.now().plusDays(1)); + metadata.setSignature(null); + Saml2Utils.signSamlObject(metadata, credentialProvider.getIdpMetaDataSigningCredential(), true); + final Element metadataElement = XMLObjectSupport.marshall(metadata); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(SerializeSupport.nodeToString(metadataElement)) + .setHeader("Content-Type", "text/html;charset=utf-8")); + + final List<BasicX509Credential> credentials = new ArrayList<>(); + final CertificateFactory fact = CertificateFactory.getInstance("X.509"); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/metadata_sig_cert.crt")))); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/assertion_sig_cert.crt")))); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/junit_metadata_sig_cert.crt")))); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + filterList.add(new SimpleMetadataSignatureVerificationFilter( + credentials, + mockServerUrl.url().toString())); + filterList.add(new PvpEntityCategoryFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + final IPvp2MetadataProvider mdResolver = metadataResolverFactory.createMetadataProvider( + mockServerUrl.url().toString(), + filterChain, "jUnit test", httpClientFactory.getHttpClient()); + + + + final EntityDescriptor descr = mdResolver.getEntityDescriptor( + "https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/metadata"); + Assert.assertNotNull("No EntityDescripter", descr); + + final List<RequestedAttribute> reqAttr = descr.getSPSSODescriptor(SAMLConstants.SAML20P_NS) + .getAttributeConsumingServices().get(0).getRequestAttributes(); + Assert.assertNotNull("Req. attributes are null", reqAttr); + Assert.assertEquals("# of req. attributes", 20, reqAttr.size()); + + } + + @Test + public void metadataSignatureValidCredentialsThird() throws CertificateException, Pvp2MetadataException, + ResolverException, XMLParserException, UnmarshallingException, SamlSigningException, + CredentialsNotAvailableException, MarshallingException, TransformerException, IOException { + + final EntityDescriptor metadata = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + MetadataResolverTest.class.getResourceAsStream("/data/pvp_metadata_valid_with_entityCategory_egov.xml")); + metadata.setValidUntil(DateTime.now().plusDays(1)); + metadata.setSignature(null); + Saml2Utils.signSamlObject(metadata, credentialProvider.getIdpMetaDataSigningCredential(), true); + final Element metadataElement = XMLObjectSupport.marshall(metadata); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(SerializeSupport.nodeToString(metadataElement)) + .setHeader("Content-Type", "text/html;charset=utf-8")); + + final List<BasicX509Credential> credentials = new ArrayList<>(); + final CertificateFactory fact = CertificateFactory.getInstance("X.509"); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/metadata_sig_cert.crt")))); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/assertion_sig_cert.crt")))); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/junit_metadata_sig_cert.crt")))); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + filterList.add(new SimpleMetadataSignatureVerificationFilter( + credentials, + mockServerUrl.url().toString())); + filterList.add(new PvpEntityCategoryFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + final IPvp2MetadataProvider mdResolver = metadataResolverFactory.createMetadataProvider( + mockServerUrl.url().toString(), + filterChain, "jUnit test", httpClientFactory.getHttpClient()); + + + + final EntityDescriptor descr = mdResolver.getEntityDescriptor( + "https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/metadata"); + Assert.assertNotNull("No EntityDescripter", descr); + + final List<RequestedAttribute> reqAttr = descr.getSPSSODescriptor(SAMLConstants.SAML20P_NS) + .getAttributeConsumingServices().get(0).getRequestAttributes(); + Assert.assertNotNull("Req. attributes are null", reqAttr); + Assert.assertEquals("# of req. attributes", 9, reqAttr.size()); + + } + + @Test + public void metadataExpired() throws CertificateException, Pvp2MetadataException, + ResolverException, XMLParserException, UnmarshallingException, SamlSigningException, + CredentialsNotAvailableException, MarshallingException, TransformerException, IOException { + + final EntityDescriptor metadata = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + MetadataResolverTest.class.getResourceAsStream("/data/pvp_metadata_valid.xml")); + metadata.setValidUntil(DateTime.now().minusDays(2)); + metadata.setSignature(null); + Saml2Utils.signSamlObject(metadata, credentialProvider.getIdpMetaDataSigningCredential(), true); + final Element metadataElement = XMLObjectSupport.marshall(metadata); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(SerializeSupport.nodeToString(metadataElement)) + .setHeader("Content-Type", "text/html;charset=utf-8")); + + final List<BasicX509Credential> credentials = new ArrayList<>(); + final CertificateFactory fact = CertificateFactory.getInstance("X.509"); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/metadata_sig_cert.crt")))); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/assertion_sig_cert.crt")))); + credentials.add(new BasicX509Credential((X509Certificate) fact.generateCertificate( + MetadataResolverTest.class.getResourceAsStream("/data/junit_metadata_sig_cert.crt")))); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + filterList.add(new SimpleMetadataSignatureVerificationFilter( + credentials, + mockServerUrl.url().toString())); + filterList.add(new RequiredValidUntilFilter()); + filterList.add(new PvpEntityCategoryFilter(false)); + + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + try { + metadataResolverFactory.createMetadataProvider( + mockServerUrl.url().toString(), + filterChain, "jUnit test", httpClientFactory.getHttpClient()); + Assert.fail("Expired metadata not detected"); + + } catch (final Pvp2MetadataException e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.09", e.getErrorId()); + + } + + + } + + @Test + public void simpleClasspathMetadataWithoutSigValidationMoaidTwoSigKeys() + throws Pvp2MetadataException, ComponentInitializationException, ResolverException, + Pvp2InternalErrorException { + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + final String entityIdToResolve = "https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata"; + + final IPvp2MetadataProvider mdResolver = metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_moaid_test.xml", + filterChain, "jUnit test", null); + + final EntityDescriptor entityIdNotExists = mdResolver.getEntityDescriptor( + "https://demo.egiz.gv.at/notExtist/"); + Assert.assertNull("No EntityDescripter", entityIdNotExists); + + final EntityDescriptor entityId = mdResolver.getEntityDescriptor(entityIdToResolve); + Assert.assertNotNull("No EntityDescripter", entityId); + + Assert.assertNotNull("Metadata provider is null", mdResolver); + final MetadataCredentialResolver resolver = createKeyInfoResolver(mdResolver); + + final CriteriaSet sigCriteriaSet = new CriteriaSet(); + sigCriteriaSet.add(new EntityIdCriterion(entityIdToResolve)); + sigCriteriaSet.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME)); + sigCriteriaSet.add(new UsageCriterion(UsageType.SIGNING)); + final SignatureValidationParameters sigValCrit = new SignatureValidationParameters(); + sigValCrit.setBlacklistedAlgorithms( + ConfigurationService.get(SignatureValidationConfiguration.class) + .getBlacklistedAlgorithms()); + sigValCrit.setSignatureTrustEngine( + TrustEngineFactory.getSignatureKnownKeysTrustEngine(mdResolver)); + sigCriteriaSet.add(new SignatureValidationParametersCriterion(sigValCrit)); + + final Iterable<Credential> singingKeyInfos = resolver.resolve(sigCriteriaSet); + Assert.assertNotNull("Signing KeyInfos null", singingKeyInfos); + Assert.assertTrue("First Credential resolved", singingKeyInfos.iterator().hasNext()); + Assert.assertTrue("Second Credential resolved", singingKeyInfos.iterator().hasNext()); + + final CriteriaSet encCriteriaSet = new CriteriaSet(); + encCriteriaSet.add(new EntityIdCriterion(entityIdToResolve)); + encCriteriaSet.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME)); + encCriteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION)); + final Iterable<Credential> encKeyInfos = resolver.resolve(encCriteriaSet); + Assert.assertNotNull("Encryption KeyInfos null", encKeyInfos); + Assert.assertTrue("No Credential resolved", encKeyInfos.iterator().hasNext()); + + } + + @Test + public void httpMetadataLoading() throws UnsupportedEncodingException, + IOException, ResolverException, Pvp2MetadataException { + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_moaid_test.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + final String entityIdToResolve = "https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata"; + + final IPvp2MetadataProvider mdResolver = metadataResolverFactory.createMetadataProvider( + mockServerUrl.url().toString(), + filterChain, "jUnit test", httpClientFactory.getHttpClient()); + + final EntityDescriptor entityIdNotExists = mdResolver.getEntityDescriptor( + "https://demo.egiz.gv.at/notExtist/"); + Assert.assertNull("No EntityDescripter", entityIdNotExists); + + final EntityDescriptor entityId = mdResolver.getEntityDescriptor(entityIdToResolve); + Assert.assertNotNull("No EntityDescripter", entityId); + + } + + @Test + public void httpMetadataLoadingRefeshFailed() throws UnsupportedEncodingException, + IOException, ResolverException, Pvp2MetadataException { + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_moaid_test.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + final String entityIdToResolve = "https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata"; + + final IPvp2MetadataProvider mdResolver = metadataResolverFactory.createMetadataProvider( + mockServerUrl.url().toString(), + filterChain, "jUnit test", httpClientFactory.getHttpClient()); + + final EntityDescriptor entityIdNotExists = mdResolver.getEntityDescriptor( + "https://demo.egiz.gv.at/notExtist/"); + Assert.assertNull("No EntityDescripter", entityIdNotExists); + + final EntityDescriptor entityId = mdResolver.getEntityDescriptor(entityIdToResolve); + Assert.assertNotNull("No EntityDescripter", entityId); + + final DateTime lastRefreshSucess = mdResolver.getLastSuccessfulRefresh(); + + try { + mdResolver.refresh(); + Assert.fail("Refesh possible without available metadata"); + + } catch (final ResolverException e) { + Assert.assertFalse("Wrong Refesh success flag", mdResolver.wasLastRefreshSuccess()); + Assert.assertEquals("Wrong refresh success date", lastRefreshSucess, mdResolver + .getLastSuccessfulRefresh()); + + } + + } + + @Test + public void httpMetadataLoadingWithRefeshSuccess() throws UnsupportedEncodingException, + IOException, ResolverException, Pvp2MetadataException { + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_moaid_test.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_moaid_test.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + final String entityIdToResolve = "https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata"; + + final IPvp2MetadataProvider mdResolver = metadataResolverFactory.createMetadataProvider( + mockServerUrl.url().toString(), + filterChain, "jUnit test", httpClientFactory.getHttpClient()); + + final EntityDescriptor entityIdNotExists = mdResolver.getEntityDescriptor( + "https://demo.egiz.gv.at/notExtist/"); + Assert.assertNull("No EntityDescripter", entityIdNotExists); + + final EntityDescriptor entityId = mdResolver.getEntityDescriptor(entityIdToResolve); + Assert.assertNotNull("No EntityDescripter", entityId); + + final DateTime lastRefresh = mdResolver.getLastRefresh(); + + // refresh metadata + mdResolver.refresh(); + + Assert.assertTrue("Refresh not sucessful", mdResolver.wasLastRefreshSuccess()); + Assert.assertTrue("Wrong last refresh date", lastRefresh.isBefore(mdResolver.getLastRefresh())); + + } + + @Test + public void httpMetadataLoadingWithoutHttpClient() throws UnsupportedEncodingException, + IOException, ResolverException, Pvp2MetadataException { + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_moaid_test.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + try { + metadataResolverFactory.createMetadataProvider( + mockServerUrl.url().toString(), + filterChain, "jUnit test", null); + Assert.fail("No httpclient not detected"); + + } catch (final Pvp2MetadataException e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.09", e.getErrorId()); + Assert.assertNotNull("No error params", e.getParams()); + Assert.assertEquals("Wrong params size", 2, e.getParams().length); + + } + } + + @Test + public void httpMetadataLoadingWrongUrl() throws UnsupportedEncodingException, + IOException, ResolverException, Pvp2MetadataException { + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(new String(IOUtils.toByteArray( + MetadataResolverTest.class.getResourceAsStream( + "/data/pvp_metadata_moaid_test.xml")), "UTF-8")) + .setHeader("Content-Type", "text/xml")); + + final List<MetadataFilter> filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + + final MetadataFilterChain filterChain = new MetadataFilterChain(); + filterChain.setFilters(filterList); + + try { + metadataResolverFactory.createMetadataProvider( + "http://127.0.0.1/notexist", + filterChain, "jUnit test", httpClientFactory.getHttpClient()); + Assert.fail("No httpclient not detected"); + + } catch (final Pvp2MetadataException e) { + Assert.assertEquals("Wrong errorCode", "internal.pvp.09", e.getErrorId()); + Assert.assertNotNull("No error params", e.getParams()); + Assert.assertEquals("Wrong params size", 2, e.getParams().length); + + } + + } + + private MetadataCredentialResolver createKeyInfoResolver(IPvp2MetadataProvider mdResolver) + throws ComponentInitializationException { + final List<KeyInfoProvider> keyInfoProvider = new ArrayList<>(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + final KeyInfoCredentialResolver keyInfoCredentialResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + final PredicateRoleDescriptorResolver roleDescriptorResolver = new PredicateRoleDescriptorResolver( + mdResolver); + roleDescriptorResolver.setRequireValidMetadata(true); + roleDescriptorResolver.initialize(); + + final MetadataCredentialResolver resolver = new MetadataCredentialResolver(); + resolver.setRoleDescriptorResolver(roleDescriptorResolver); + resolver.setKeyInfoCredentialResolver(keyInfoCredentialResolver); + resolver.initialize(); + + return resolver; + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/config/config_1.props b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/config/config_1.props index 74b805ba..164b8807 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/config/config_1.props +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/config/config_1.props @@ -5,4 +5,8 @@ key.metadata.pass=password key.sig.alias=sig key.sig.pass=password key.enc.alias= -key.enc.pass=
\ No newline at end of file +key.enc.pass= + +client.http.connection.timeout.socket=2 +client.http.connection.timeout.connection=2 +client.http.connection.timeout.request=2
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/AuthRequest_withsig_expired.b64 b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/AuthRequest_withsig_expired.b64 new file mode 100644 index 00000000..f02ce2ea --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/AuthRequest_withsig_expired.b64 @@ -0,0 +1 @@ +PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOkF1dGhuUmVxdWVzdCB4bWxuczpzYW1sMnA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgQXNzZXJ0aW9uQ29uc3VtZXJTZXJ2aWNlSW5kZXg9IjAiIERlc3RpbmF0aW9uPSJodHRwczovL2VpZGFzLXRlc3QuYm1pLmd2LmF0L21zX2Nvbm5lY3Rvci9wdnAvcG9zdCIgSUQ9Il9lZDJjZDQ0NjNiODJkYzYwOTI0MzM5YjEwZWIyNzQ4OCIgSXNQYXNzaXZlPSJmYWxzZSIgSXNzdWVJbnN0YW50PSIyMDIwLTAyLTA0VDA2OjQ4OjU4LjA3NFoiIFByb3ZpZGVyTmFtZT0iT3BlbklEIENvbm5lY3QgRGVtbyIgVmVyc2lvbj0iMi4wIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiPjxzYW1sMjpJc3N1ZXIgeG1sbnM6c2FtbDI9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5Ij5odHRwczovL2RlbW8uZWdpei5ndi5hdC9kZW1vcG9ydGFsX21vYWlkLTIuMC9zcC9laWRhcy9tZXRhZGF0YTwvc2FtbDI6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI19lZDJjZDQ0NjNiODJkYzYwOTI0MzM5YjEwZWIyNzQ4OCI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyI+PGVjOkluY2x1c2l2ZU5hbWVzcGFjZXMgeG1sbnM6ZWM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIgUHJlZml4TGlzdD0ieHMiLz48L2RzOlRyYW5zZm9ybT48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT5aSEZ0UVpYeXBTbFhrK3ZYdGZlSDVMWEdNcTE2MUpmUHdFUHBPVFhUSzlRPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5CSFFHeXpMZE5rb2dGZmt5T0FxVnBTRXh1NXhRaWxvVUs5L01GejBTM01LZnRkaDVtTXVaT0tBSUU1SUMrKzlPS25UbUlncUVNdWJVKzAvTEVobTUwUk1oZGtxYUFFWG02Y2xKYmlaOHBvT0pPd09sWlhQVWtub0J4NkZxRi9MNThqTFV6ZlluNEh0OUtCOGVQV2djU2FVR3lpMHB4OEdzMzNJUDd3eGF2bnhGYUMvSERpZkN0UytaZzJ5QVpJR2lnQksxcXIrUTMweWIrNWZEQmprU3pWMWJGb2NKdHY2cDJhSXlUMTNnb2x6N0FuK3JSWVloVnd5WENBY25CdHJjQTREbmNpWVVnTVNLQTRTR1hLNExyZ1RTdjFXUHJEdlJmWkVLMk9xL2JEMHE0MWF1T1d4VVkzK2x2T2pJYUI3YnRobURiSVJPbmhaWW1rMDlPSFZJMVE9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJREt6Q0NBaE1DQkZyeEtPNHdEUVlKS29aSWh2Y05BUUVMQlFBd1dqRUxNQWtHQTFVRUJoTUNRVlF4RFRBTEJnTlZCQW9NQkVWSApTVm94R0RBV0JnTlZCQXNNRDJSbGJXOHVaV2RwZWk1bmRpNWhkREVpTUNBR0ExVUVBd3daVFU5QkxVbEVJRWxFVUNBb1ZHVnpkQzFXClpYSnphVzl1S1RBZUZ3MHhPREExTURnd05ETTBOVFJhRncweU1UQXhNekV3TkRNME5UUmFNRm94Q3pBSkJnTlZCQVlUQWtGVU1RMHcKQ3dZRFZRUUtEQVJGUjBsYU1SZ3dGZ1lEVlFRTERBOWtaVzF2TG1WbmFYb3VaM1l1WVhReElqQWdCZ05WQkFNTUdVMVBRUzFKUkNCSgpSRkFnS0ZSbGMzUXRWbVZ5YzJsdmJpa3dnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDYUZucW9hWW9xClVwdGVuZW1DNkZpVkRnNUYyaEVqcGppeDgrb3c2LzZRaFVsMmNQT1MwdXdaSGFJdndUL1JWYko5Q1BkaWw2KzExcWFDUGZaK0ZvWSsKTStrZTdUUmQyUlMxRHFGYmUxS0MwaW1FbndlbXlMUXJZZTVQbTdETmNhWS9rSFRUcStrMGVlR2JZSDBVL0lvcHlpMFZ1TjVPV2w0RgpWZzQ1cGY3a25oWGthaW1JdGRqbkNYbktjWU05MW1tbHRDZjZURGdVcno3VVM3UG1ndmlubmhmQmdkSVRBVDRHUnI0ZWhsaVQrL2p0CjFPekhFeVdSSGFuQkdJcFhOZVpOcXhnbnBuR3RhRGg0Slp1WVI4cWZIK0dSSzZkdFcyemllajZyR0lpVUVsR1ZDa1hzb2hneE1OenEKbldlRDlKVDgreXlwMVhabHlRZitJeGhoRVNRTEFnTUJBQUV3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUlGZWpBRlFlcGFFbC9rQwpWTHZpZE1SK01YcTVMQ0dIdGhVaUk2ZURUUVorSDdsWmRIbGo1NDdYd0VkWDE1YjZNZDNoN2VTSjRod2xmVjRnby8wRmFvTFB6dlZxCml0d3RZWTVodHl3QjNCNlpWMzRFeWk2QzU5R2wzNFhyVjhDV3hINEtLd0xzVkFqQXkrL3AvWGgwcTJwelNCa2VPQ2h6Qk1Ca2pteWMKMlVlNE1FS2RMOWd1enA2K1ljL0hML3BoSEFLWWFwa1Z5Rnd2c2RxV09neVJ6eEFISU5rbzhFeEltTU1CM3hCNWE1MmtmcUxjdWk1TwpmekVoandMRkphR0JNbUZDbUZHR09Vd3RJdmwvNlpRMkxMek9FOStnaVZLOVdzSWdIMTFQdStlalBGQWJYZjhjZjRvV2hiQWZUa2l5CjRqcFhycDc3SlhGUlNEV2RkYjB5ZVBjPTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjxzYW1sMnA6RXh0ZW5zaW9ucz48ZWlkOlJlcXVlc3RlZEF0dHJpYnV0ZXMgeG1sbnM6ZWlkPSJodHRwOi8vZWlkLmd2LmF0L2VJRC9hdHRyaWJ1dGVzL3NhbWwtZXh0ZW5zaW9ucyI+PGVpZDpSZXF1ZXN0ZWRBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJFSUQtU0VDVE9SLUZPUi1JREVOVElGSUVSIiBOYW1lPSJ1cm46b2lkOjEuMi40MC4wLjEwLjIuMS4xLjI2MS4zNCIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDp1cmkiIGlzUmVxdWlyZWQ9InRydWUiPjxlaWQ6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+dXJuOnB1YmxpY2lkOmd2LmF0OmNkaWQrQkY8L2VpZDpBdHRyaWJ1dGVWYWx1ZT48L2VpZDpSZXF1ZXN0ZWRBdHRyaWJ1dGU+PC9laWQ6UmVxdWVzdGVkQXR0cmlidXRlcz48L3NhbWwycDpFeHRlbnNpb25zPjxzYW1sMnA6TmFtZUlEUG9saWN5IEFsbG93Q3JlYXRlPSJ0cnVlIiBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OnBlcnNpc3RlbnQiLz48c2FtbDJwOlJlcXVlc3RlZEF1dGhuQ29udGV4dCBDb21wYXJpc29uPSJtaW5pbXVtIj48c2FtbDI6QXV0aG5Db250ZXh0Q2xhc3NSZWYgeG1sbnM6c2FtbDI9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPmh0dHA6Ly9laWRhcy5ldXJvcGEuZXUvTG9BL2xvdzwvc2FtbDI6QXV0aG5Db250ZXh0Q2xhc3NSZWY+PC9zYW1sMnA6UmVxdWVzdGVkQXV0aG5Db250ZXh0PjxzYW1sMnA6U2NvcGluZz48c2FtbDJwOlJlcXVlc3RlcklEPmh0dHBzOi8vZGVtby5lZ2l6Lmd2LmF0L2RlbW9wb3J0YWwtb3BlbklEX2RlbW88L3NhbWwycDpSZXF1ZXN0ZXJJRD48L3NhbWwycDpTY29waW5nPjwvc2FtbDJwOkF1dGhuUmVxdWVzdD4
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/Response_without_sig_1.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/Response_without_sig_1.xml index 3607cbc4..2683742e 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/Response_without_sig_1.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/Response_without_sig_1.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://demo.egiz.gv.at/demoportal_demologin/securearea.action" InResponseTo="_aeebfae3ce681fe3ddcaf213a42f01d3" IssueInstant="2014-03-05T06:39:51.017Z" Version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata</saml2:Issuer> + <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://demo.egiz.gv.at/demoportal_demologin/</saml2:Issuer> <saml2p:Status> <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </saml2p:Status> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/assertion_sig_cert.crt b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/assertion_sig_cert.crt new file mode 100644 index 00000000..b53c558d --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/assertion_sig_cert.crt @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBbTCCARKgAwIBAgIEXjF+qTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +HhcNMjAwMTI5MTI0NjMzWhcNMjcwMTI4MTI0NjMzWjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASRt7gZRrr4rSEE7Q922oKQJF+mlkwC +LZnv8ZzHtH54s4VdyQFIBjQF1PPf9PTn+5tid8QJehZPndcoeD7J8fPJMAoGCCqG +SM49BAMCA0kAMEYCIQDFUO0owvqMVRO2FmD+vb8mqJBpWCE6Cl5pEHaygTa5LwIh +ANsmjI2azWiTSFjb7Ou5fnCfbeiJUP0s66m8qS4rYl9L +-----END CERTIFICATE----- diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/junit_metadata_sig_cert.crt b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/junit_metadata_sig_cert.crt new file mode 100644 index 00000000..b544c194 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/junit_metadata_sig_cert.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC+jCCAeKgAwIBAgIEXjF+fTANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJB +VDENMAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxETAPBgNVBAMMCE1ldGFk +YXRhMB4XDTIwMDEyOTEyNDU0OVoXDTI2MDEyODEyNDU0OVowPzELMAkGA1UEBhMC +QVQxDTALBgNVBAcMBEVHSVoxDjAMBgNVBAoMBWpVbml0MREwDwYDVQQDDAhNZXRh +ZGF0YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK230G3dxNbNlSYA +O5Kx/Js0aBAgxMt7q9m+dA35fK/dOvF/GjrqjWsMCnax+no9gLnq6x0gXiJclz6H +rp/YDOfLrJjMpNL/r0FWT947vbnEj7eT8TdY5d6Yi8AZulZmjiCI5nbZh2zwrP4+ +WqRroLoPhXQj8mDyp26M4xHBBUhLMRc2HV4S+XH4uNZ/vTmb8vBg31XGHCY33gl7 +/KA54JNGxJdN8Dxv6yHYsm91ZfVrX39W0iYLUNhUCkolwuQmjDVfrExM8BTLIONb +f+erJoCm3A9ghZyDYRQ/e69/UEUqDa6XOzykr88INkQscEiAXCDS+EBPMpKo+t3l +PIA9r7kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAh/2mg4S03bdZy1OVtEAudBT9 +YZb9OF34hxPtNbkB/V04wSIg1d4TBr5KDhV7CdiUOxPZzHpS8LUCgfGX306FB6NX +zh/b67uTOPaE72AB4VIT/Np0fsM7k5WhG9k9NoprIGiqCz2lXcfpZiT+LtSO1vWS +YI87wR9KOSWjcw/5i5qZIAJuwvLCQj5JtUsmrhHK75222J3TJf4dS/gfN4xfY2rW +9vcXtH6//8WdWp/zx9V7Z1ZsDb8TDKtBCEGuFDgVeU5ScKtVq8qRoUKD3Ve76cZi +purO3KrRrVAuZP2EfLkZdHEHqe8GPigNnZ5kTn8V2VJ3iRAQ73hpJRR98tFd0A== +-----END CERTIFICATE----- diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/metadata_sig_cert.crt b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/metadata_sig_cert.crt new file mode 100644 index 00000000..61aa137b --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/metadata_sig_cert.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc= +-----END CERTIFICATE-----
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_junit_keystore.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_junit_keystore.xml new file mode 100644 index 00000000..52549a88 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_junit_keystore.xml @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="UTF-8"?> +<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_2e23ca9b2ba4dc9eef15187830d07ff0" entityID="https://demo.egiz.gv.at/demoportal_demologin/" validUntil="2020-02-05T06:41:42.966Z"> + <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:SignedInfo> + <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> + <ds:Reference URI="#_2e23ca9b2ba4dc9eef15187830d07ff0"> + <ds:Transforms> + <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + </ds:Transforms> + <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> + <ds:DigestValue>Jy/c0ZvVJSfWzSoAcxDx/o+T5W61vvNJNqTFz2o+ILc=</ds:DigestValue> + </ds:Reference> + </ds:SignedInfo> + <ds:SignatureValue>chMxIdwrPvr78j3oTtgS7udbydy9kye1bbeQ4jm2GeFKUfxvJqY+vt9MjVnWFeR4c16gd80BjZJ6xxD5i5Ifci3YtxeKSxq0ttH/xZYEhJZkD/0NrGUhSvNV9zuLAz3uGk/LJ+2JxRq7dbnW4n9MtGuYhea8OW9/Pr1xI1KyskQS76NZDsGjjfnFWbFXahLoQZULU4Ke3SfZVqLATTn0J34RZnjNH3QieY3LhRzOVu/I5yeZtnLgUS6dg0Gab9DA/pdNFaC632iaE5QCXJmhgpqkjbkayO9e8N93YGFjbszhU1Kws5OUGjXjfCZwezLeOUZoKEfo5c+4+zEaTrEQjg==</ds:SignatureValue> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </ds:Signature> + <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> + <md:KeyDescriptor use="signing"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIC+jCCAeKgAwIBAgIEXjF+fTANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJB +VDENMAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxETAPBgNVBAMMCE1ldGFk +YXRhMB4XDTIwMDEyOTEyNDU0OVoXDTI2MDEyODEyNDU0OVowPzELMAkGA1UEBhMC +QVQxDTALBgNVBAcMBEVHSVoxDjAMBgNVBAoMBWpVbml0MREwDwYDVQQDDAhNZXRh +ZGF0YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK230G3dxNbNlSYA +O5Kx/Js0aBAgxMt7q9m+dA35fK/dOvF/GjrqjWsMCnax+no9gLnq6x0gXiJclz6H +rp/YDOfLrJjMpNL/r0FWT947vbnEj7eT8TdY5d6Yi8AZulZmjiCI5nbZh2zwrP4+ +WqRroLoPhXQj8mDyp26M4xHBBUhLMRc2HV4S+XH4uNZ/vTmb8vBg31XGHCY33gl7 +/KA54JNGxJdN8Dxv6yHYsm91ZfVrX39W0iYLUNhUCkolwuQmjDVfrExM8BTLIONb +f+erJoCm3A9ghZyDYRQ/e69/UEUqDa6XOzykr88INkQscEiAXCDS+EBPMpKo+t3l +PIA9r7kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAh/2mg4S03bdZy1OVtEAudBT9 +YZb9OF34hxPtNbkB/V04wSIg1d4TBr5KDhV7CdiUOxPZzHpS8LUCgfGX306FB6NX +zh/b67uTOPaE72AB4VIT/Np0fsM7k5WhG9k9NoprIGiqCz2lXcfpZiT+LtSO1vWS +YI87wR9KOSWjcw/5i5qZIAJuwvLCQj5JtUsmrhHK75222J3TJf4dS/gfN4xfY2rW +9vcXtH6//8WdWp/zx9V7Z1ZsDb8TDKtBCEGuFDgVeU5ScKtVq8qRoUKD3Ve76cZi +purO3KrRrVAuZP2EfLkZdHEHqe8GPigNnZ5kTn8V2VJ3iRAQ73hpJRR98tFd0A==</ds:X509Certificate> + </ds:X509Data> + <ds:X509Data> + <ds:X509Certificate>MIIBbTCCARKgAwIBAgIEXjF+qTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +HhcNMjAwMTI5MTI0NjMzWhcNMjcwMTI4MTI0NjMzWjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASRt7gZRrr4rSEE7Q922oKQJF+mlkwC +LZnv8ZzHtH54s4VdyQFIBjQF1PPf9PTn+5tid8QJehZPndcoeD7J8fPJMAoGCCqG +SM49BAMCA0kAMEYCIQDFUO0owvqMVRO2FmD+vb8mqJBpWCE6Cl5pEHaygTa5LwIh +ANsmjI2azWiTSFjb7Ou5fnCfbeiJUP0s66m8qS4rYl9L + </ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:KeyDescriptor use="encryption"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/post" index="0" isDefault="true"/> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/redirect" index="1"/> + <md:AttributeConsumingService index="0" isDefault="true"> + <md:ServiceName xml:lang="en">Default Service</md:ServiceName> + <md:RequestedAttribute FriendlyName="BPK" Name="urn:oid:1.2.40.0.10.2.1.1.149" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="PRINCIPAL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.20" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.55" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="PVP-VERSION" Name="urn:oid:1.2.40.0.10.2.1.1.261.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="EID-ISSUING-NATION" Name="urn:oid:1.2.40.0.10.2.1.1.261.32" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.76" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-FULL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.84" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="MANDATE-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.68" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN" Name="urn:oid:1.2.40.0.10.2.1.1.261.100" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="GIVEN-NAME" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="EID-SECTOR-FOR-IDENTIFIER" Name="urn:oid:1.2.40.0.10.2.1.1.261.34" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="MANDATE-TYPE-OID" Name="urn:oid:1.2.40.0.10.2.1.1.261.106" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="EID-IDENTITY-LINK" Name="urn:oid:1.2.40.0.10.2.1.1.261.38" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="EID-CITIZEN-QAA-EIDAS-LEVEL" Name="urn:oid:1.2.40.0.10.2.1.1.261.108" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + </md:AttributeConsumingService> + </md:SPSSODescriptor> + <md:Organization> + <md:OrganizationName xml:lang="de">EGIZ</md:OrganizationName> + <md:OrganizationDisplayName xml:lang="de">E-Government Innovationszentrum</md:OrganizationDisplayName> + <md:OrganizationURL xml:lang="de">http://www.egiz.gv.at</md:OrganizationURL> + </md:Organization> + <md:ContactPerson contactType="technical"> + <md:Company>E-Government Innovationszentrum</md:Company> + <md:GivenName>Lenz</md:GivenName> + <md:SurName>Thomas</md:SurName> + <md:EmailAddress>thomas.lenz@egiz.gv.at</md:EmailAddress> + <md:TelephoneNumber>+43 316 873 5525</md:TelephoneNumber> + </md:ContactPerson> +</md:EntityDescriptor> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_moaid_test.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_moaid_test.xml new file mode 100644 index 00000000..f1fbd9be --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_moaid_test.xml @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="UTF-8"?> +<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_2e23ca9b2ba4dc9eef15187830d07ff0" entityID="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata" validUntil="2020-02-05T06:41:42.966Z"> + <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:SignedInfo> + <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> + <ds:Reference URI="#_2e23ca9b2ba4dc9eef15187830d07ff0"> + <ds:Transforms> + <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + </ds:Transforms> + <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> + <ds:DigestValue>Jy/c0ZvVJSfWzSoAcxDx/o+T5W61vvNJNqTFz2o+ILc=</ds:DigestValue> + </ds:Reference> + </ds:SignedInfo> + <ds:SignatureValue>chMxIdwrPvr78j3oTtgS7udbydy9kye1bbeQ4jm2GeFKUfxvJqY+vt9MjVnWFeR4c16gd80BjZJ6xxD5i5Ifci3YtxeKSxq0ttH/xZYEhJZkD/0NrGUhSvNV9zuLAz3uGk/LJ+2JxRq7dbnW4n9MtGuYhea8OW9/Pr1xI1KyskQS76NZDsGjjfnFWbFXahLoQZULU4Ke3SfZVqLATTn0J34RZnjNH3QieY3LhRzOVu/I5yeZtnLgUS6dg0Gab9DA/pdNFaC632iaE5QCXJmhgpqkjbkayO9e8N93YGFjbszhU1Kws5OUGjXjfCZwezLeOUZoKEfo5c+4+zEaTrEQjg==</ds:SignatureValue> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </ds:Signature> + <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> + <md:KeyDescriptor use="signing"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + <ds:X509Data> + <ds:X509Certificate>MIIEFTCCAv2gAwIBAgIJAI/HXXgQpJtFMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNVBAYTAkFUMRMw + EQYDVQQIEwpTb21lLVN0YXRlMQ0wCwYDVQQHEwRHcmF6MQ0wCwYDVQQKEwRFR0laMSIwIAYDVQQD + ExlNT0EtSUQgSURQIChUZXN0LVZlcnNpb24pMB4XDTE0MDEyMTA4NDAxOFoXDTE1MDEyMTA4NDAx + OFowZDELMAkGA1UEBhMCQVQxEzARBgNVBAgTClNvbWUtU3RhdGUxDTALBgNVBAcTBEdyYXoxDTAL + BgNVBAoTBEVHSVoxIjAgBgNVBAMTGU1PQS1JRCBJRFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqG + SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFETzd0nLV2P4pUGnlLKj3V+MZ4bUyYkNK5NnkzB0PO8hm + tsrdg+HSNsnPiU5KvD26tFpxq9lfibZcAp9JHFqjA/capOHcTDhYkTvJcSdaKJzttTPy4wivTbRu + y+ocK9jjz6g8BFvP9wQ5/k2AwFaqj0SeJt0jJTn4CZ8XMNozA2hwkQA2heuMtOl24Ie9PRC3/Af7 + utV2CNfV2MysGHIxazsZDIgFF+5/nybyR1yiIxKb0BYDh3gbNdyH5uLVBHOP4hvzQN5Z1xc/cdzq + lzKn/4v6HJraNn00xLzK6nrG6gB6HvDok2l8T1Cc7f8I+sNlO2aM8rY4hGSGCfhiL6IFAgMBAAGj + gckwgcYwHQYDVR0OBBYEFKG3LzuPtAGCXUPTw3fo9dtsS9wWMIGWBgNVHSMEgY4wgYuAFKG3LzuP + tAGCXUPTw3fo9dtsS9wWoWikZjBkMQswCQYDVQQGEwJBVDETMBEGA1UECBMKU29tZS1TdGF0ZTEN + MAsGA1UEBxMER3JhejENMAsGA1UEChMERUdJWjEiMCAGA1UEAxMZTU9BLUlEIElEUCAoVGVzdC1W + ZXJzaW9uKYIJAI/HXXgQpJtFMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAME3wzEi + UAcF2pCDtMMJzX4IDhSkWNuvWtSMMy8Vgtcc2t570teIKh+qNKQWZyX3QFVE6ovDABg3ZUhn780l + G4/t6aMOUEeGg4udl7l0QRBRbdd+9oc0Aw5dQqku02AQ6wQd695PLj+F0GeA7cdef90aLPu6Rwa5 + z5BiKpReJZoul3NpjQXz7A1IslZOlIhEDcFUlBSn/+QfLOeNDKurvPT0OzUGSGfrv0AoniNHc/fz + lfyRmgFbzAVHedU5cIxcE0yHtEKFjFSVwtGng9rTJpoOoY4pvGvAHlw6GEgO+HwFukPDtnvY8vi/ + cfmNJhb06H+6mmHz929Bk4HuHoQj8X8= + </ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:KeyDescriptor use="encryption"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/post" index="0" isDefault="true"/> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/redirect" index="1"/> + <md:AttributeConsumingService index="0" isDefault="true"> + <md:ServiceName xml:lang="en">Default Service</md:ServiceName> + <md:RequestedAttribute FriendlyName="BPK" Name="urn:oid:1.2.40.0.10.2.1.1.149" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="PRINCIPAL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.20" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.55" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="PVP-VERSION" Name="urn:oid:1.2.40.0.10.2.1.1.261.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="EID-ISSUING-NATION" Name="urn:oid:1.2.40.0.10.2.1.1.261.32" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.76" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-FULL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.84" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="MANDATE-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.68" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN" Name="urn:oid:1.2.40.0.10.2.1.1.261.100" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="GIVEN-NAME" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="EID-SECTOR-FOR-IDENTIFIER" Name="urn:oid:1.2.40.0.10.2.1.1.261.34" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="MANDATE-TYPE-OID" Name="urn:oid:1.2.40.0.10.2.1.1.261.106" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="EID-IDENTITY-LINK" Name="urn:oid:1.2.40.0.10.2.1.1.261.38" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="EID-CITIZEN-QAA-EIDAS-LEVEL" Name="urn:oid:1.2.40.0.10.2.1.1.261.108" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + </md:AttributeConsumingService> + </md:SPSSODescriptor> + <md:Organization> + <md:OrganizationName xml:lang="de">EGIZ</md:OrganizationName> + <md:OrganizationDisplayName xml:lang="de">E-Government Innovationszentrum</md:OrganizationDisplayName> + <md:OrganizationURL xml:lang="de">http://www.egiz.gv.at</md:OrganizationURL> + </md:Organization> + <md:ContactPerson contactType="technical"> + <md:Company>E-Government Innovationszentrum</md:Company> + <md:GivenName>Lenz</md:GivenName> + <md:SurName>Thomas</md:SurName> + <md:EmailAddress>thomas.lenz@egiz.gv.at</md:EmailAddress> + <md:TelephoneNumber>+43 316 873 5525</md:TelephoneNumber> + </md:ContactPerson> +</md:EntityDescriptor> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_valid.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_valid.xml new file mode 100644 index 00000000..d5855d43 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_valid.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_ee52efc823faa4334d93d1a787fb2c24" entityID="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/metadata" validUntil="2020-02-05T10:58:10.849Z"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#_ee52efc823faa4334d93d1a787fb2c24"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>O4rfKjKlNT+p4hNR5NtYkrnu/AATuSGxsKxn3C4+VhA=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>G8jkWHT0baEviEcd4Xd/+u/WMyVK1H/Jdy2y1YE1nv+61zrm3rEgzuW70kGGdpxGt3enWznYem9jwkckXVu21QWZa9XDICu1MIrnpWs37Iz2ph3uHqvfYLS3awEs4GzinB6sLNM+2xEgmv/hXjSFIeOsCAIxdAsA7Btbq6iIx0xIknVZHlp3pWBzXAFvsizWx7QFldaMhzsfZ1HgSd7EdqFoMEjhEr6FHsppj2NjKjqNVg4AGHFp+GkzxXcXHTcojwigIx4qFli4B6EdqGPvC1oX1fBy09iYxeA0maI/qwLsWLfShrtNE3eFi7aQblTkTaK1cFO8q5P8u61yKtv3wg==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:KeyDescriptor use="encryption"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat><md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/post" index="0" isDefault="true"/><md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/redirect" index="1"/><md:AttributeConsumingService index="0" isDefault="true"><md:ServiceName xml:lang="en">Default Service</md:ServiceName><md:RequestedAttribute FriendlyName="MANDATOR-NATURAL-PERSON-BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.261.82" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="BPK" Name="urn:oid:1.2.40.0.10.2.1.1.149" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATOR-NATURAL-PERSON-FAMILY-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.80" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="PRINCIPAL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.20" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.55" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="EID-CCS-URL" Name="urn:oid:1.2.40.0.10.2.1.1.261.64" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATE-PROF-REP-OID" Name="urn:oid:1.2.40.0.10.2.1.1.261.86" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-FULL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.84" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATE-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.68" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="ENC-BPK-LIST" Name="urn:oid:1.2.40.0.10.2.1.1.261.22" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="EID-SIGNER-CERTIFICATE" Name="urn:oid:1.2.40.0.10.2.1.1.261.66" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATE-PROF-REP-DESCRIPTION" Name="urn:oid:1.2.40.0.10.2.1.1.261.88" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="BPK-LIST" Name="urn:oid:1.2.40.0.10.2.1.1.261.28" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATE-REFERENCE-VALUE" Name="urn:oid:1.2.40.0.10.2.1.1.261.90" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATOR-NATURAL-PERSON-ENC-BPK-LIST" Name="urn:oid:1.2.40.0.10.2.1.1.261.72" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="PVP-VERSION" Name="urn:oid:1.2.40.0.10.2.1.1.261.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="EID-ISSUING-NATION" Name="urn:oid:1.2.40.0.10.2.1.1.261.32" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.76" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATOR-NATURAL-PERSON-BPK" Name="urn:oid:1.2.40.0.10.2.1.1.261.98" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATOR-NATURAL-PERSON-BPK-LIST" Name="urn:oid:1.2.40.0.10.2.1.1.261.73" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN" Name="urn:oid:1.2.40.0.10.2.1.1.261.100" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="GIVEN-NAME" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="EID-SECTOR-FOR-IDENTIFIER" Name="urn:oid:1.2.40.0.10.2.1.1.261.34" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATOR-NATURAL-PERSON-GIVEN-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.78" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="EID-E-ID-TOKEN" Name="urn:oid:1.2.40.0.10.2.1.1.261.39" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="MANDATE-TYPE-OID" Name="urn:oid:1.2.40.0.10.2.1.1.261.106" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="EID-CITIZEN-QAA-EIDAS-LEVEL" Name="urn:oid:1.2.40.0.10.2.1.1.261.108" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/><md:RequestedAttribute FriendlyName="EID-IDENTITY-STATUS-LEVEL" Name="urn:oid:1.2.40.0.10.2.1.1.261.109" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/></md:AttributeConsumingService></md:SPSSODescriptor><md:Organization><md:OrganizationName xml:lang="de">EGIZ</md:OrganizationName><md:OrganizationDisplayName xml:lang="de">E-Government Innovationszentrum</md:OrganizationDisplayName><md:OrganizationURL xml:lang="de">http://www.egiz.gv.at</md:OrganizationURL></md:Organization><md:ContactPerson contactType="technical"><md:Company>E-Government Innovationszentrum</md:Company><md:GivenName>Lenz</md:GivenName><md:SurName>Thomas</md:SurName><md:EmailAddress>thomas.lenz@egiz.gv.at</md:EmailAddress><md:TelephoneNumber>+43 316 873 5525</md:TelephoneNumber></md:ContactPerson></md:EntityDescriptor>
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_valid_with_entityCategory.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_valid_with_entityCategory.xml new file mode 100644 index 00000000..54ad2b03 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_valid_with_entityCategory.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_ee52efc823faa4334d93d1a787fb2c24" entityID="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/metadata" validUntil="2020-02-05T10:58:10.849Z"> + <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:SignedInfo> + <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> + <ds:Reference URI="#_ee52efc823faa4334d93d1a787fb2c24"> + <ds:Transforms> + <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + </ds:Transforms> + <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> + <ds:DigestValue>O4rfKjKlNT+p4hNR5NtYkrnu/AATuSGxsKxn3C4+VhA=</ds:DigestValue> + </ds:Reference> + </ds:SignedInfo> + <ds:SignatureValue>G8jkWHT0baEviEcd4Xd/+u/WMyVK1H/Jdy2y1YE1nv+61zrm3rEgzuW70kGGdpxGt3enWznYem9jwkckXVu21QWZa9XDICu1MIrnpWs37Iz2ph3uHqvfYLS3awEs4GzinB6sLNM+2xEgmv/hXjSFIeOsCAIxdAsA7Btbq6iIx0xIknVZHlp3pWBzXAFvsizWx7QFldaMhzsfZ1HgSd7EdqFoMEjhEr6FHsppj2NjKjqNVg4AGHFp+GkzxXcXHTcojwigIx4qFli4B6EdqGPvC1oX1fBy09iYxeA0maI/qwLsWLfShrtNE3eFi7aQblTkTaK1cFO8q5P8u61yKtv3wg==</ds:SignatureValue> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </ds:Signature> + <md:Extensions> + <mdattr:EntityAttributes xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute"> + <saml2:Attribute xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Name="http://macedir.org/entity-category" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">http://www.ref.gv.at/ns/names/agiz/pvp/citizentoken</saml2:AttributeValue> + </saml2:Attribute> + </mdattr:EntityAttributes> + </md:Extensions> + <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> + <md:KeyDescriptor use="signing"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:KeyDescriptor use="encryption"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/post" index="0" isDefault="true"/> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/redirect" index="1"/> + <md:AttributeConsumingService index="0" isDefault="true"> + <md:ServiceName xml:lang="en">Default Service</md:ServiceName> + <md:RequestedAttribute FriendlyName="MANDATOR-NATURAL-PERSON-BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.261.82" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + </md:AttributeConsumingService> + </md:SPSSODescriptor> + <md:Organization> + <md:OrganizationName xml:lang="de">EGIZ</md:OrganizationName> + <md:OrganizationDisplayName xml:lang="de">E-Government Innovationszentrum</md:OrganizationDisplayName> + <md:OrganizationURL xml:lang="de">http://www.egiz.gv.at</md:OrganizationURL> + </md:Organization> + <md:ContactPerson contactType="technical"> + <md:Company>E-Government Innovationszentrum</md:Company> + <md:GivenName>Lenz</md:GivenName> + <md:SurName>Thomas</md:SurName> + <md:EmailAddress>thomas.lenz@egiz.gv.at</md:EmailAddress> + <md:TelephoneNumber>+43 316 873 5525</md:TelephoneNumber> + </md:ContactPerson> +</md:EntityDescriptor> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_valid_with_entityCategory_egov.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_valid_with_entityCategory_egov.xml new file mode 100644 index 00000000..cb680e82 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_valid_with_entityCategory_egov.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_ee52efc823faa4334d93d1a787fb2c24" entityID="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/metadata" validUntil="2020-02-05T10:58:10.849Z"> + <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:SignedInfo> + <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> + <ds:Reference URI="#_ee52efc823faa4334d93d1a787fb2c24"> + <ds:Transforms> + <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + </ds:Transforms> + <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> + <ds:DigestValue>O4rfKjKlNT+p4hNR5NtYkrnu/AATuSGxsKxn3C4+VhA=</ds:DigestValue> + </ds:Reference> + </ds:SignedInfo> + <ds:SignatureValue>G8jkWHT0baEviEcd4Xd/+u/WMyVK1H/Jdy2y1YE1nv+61zrm3rEgzuW70kGGdpxGt3enWznYem9jwkckXVu21QWZa9XDICu1MIrnpWs37Iz2ph3uHqvfYLS3awEs4GzinB6sLNM+2xEgmv/hXjSFIeOsCAIxdAsA7Btbq6iIx0xIknVZHlp3pWBzXAFvsizWx7QFldaMhzsfZ1HgSd7EdqFoMEjhEr6FHsppj2NjKjqNVg4AGHFp+GkzxXcXHTcojwigIx4qFli4B6EdqGPvC1oX1fBy09iYxeA0maI/qwLsWLfShrtNE3eFi7aQblTkTaK1cFO8q5P8u61yKtv3wg==</ds:SignatureValue> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </ds:Signature> + <md:Extensions> + <mdattr:EntityAttributes xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute"> + <saml2:Attribute xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Name="http://macedir.org/entity-category" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">http://www.ref.gv.at/ns/names/agiz/pvp/egovtoken</saml2:AttributeValue> + </saml2:Attribute> + </mdattr:EntityAttributes> + </md:Extensions> + <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> + <md:KeyDescriptor use="signing"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:KeyDescriptor use="encryption"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/post" index="0" isDefault="true"/> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eid/redirect" index="1"/> + <md:AttributeConsumingService index="0" isDefault="true"> + <md:ServiceName xml:lang="en">Default Service</md:ServiceName> + <md:RequestedAttribute FriendlyName="MANDATOR-NATURAL-PERSON-BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.261.82" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + </md:AttributeConsumingService> + </md:SPSSODescriptor> + <md:Organization> + <md:OrganizationName xml:lang="de">EGIZ</md:OrganizationName> + <md:OrganizationDisplayName xml:lang="de">E-Government Innovationszentrum</md:OrganizationDisplayName> + <md:OrganizationURL xml:lang="de">http://www.egiz.gv.at</md:OrganizationURL> + </md:Organization> + <md:ContactPerson contactType="technical"> + <md:Company>E-Government Innovationszentrum</md:Company> + <md:GivenName>Lenz</md:GivenName> + <md:SurName>Thomas</md:SurName> + <md:EmailAddress>thomas.lenz@egiz.gv.at</md:EmailAddress> + <md:TelephoneNumber>+43 316 873 5525</md:TelephoneNumber> + </md:ContactPerson> +</md:EntityDescriptor> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_wrong_schema.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_wrong_schema.xml new file mode 100644 index 00000000..5fc61717 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_wrong_schema.xml @@ -0,0 +1,122 @@ +<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://demo.egiz.gv.at/demoportal_demologin/" validUntil="2059-07-27T11:23:29.736Z"> + <ds:Signature> + <ds:SignedInfo> + <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> + <ds:Reference URI="#_c0303e3081ac29bb8329cade76279069"> + <ds:Transforms> + <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + </ds:Transforms> + <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> + <ds:DigestValue>IjxuoZphYVmZdZ5HfoVDr35r2b1V840+SMeC89IO/SQ=</ds:DigestValue> + </ds:Reference> + </ds:SignedInfo> + <ds:SignatureValue>JILQKKPvsK7onsMweJauAcGEniFGJ5bXEOvfYhxAYCB+dXL6pH87USD1v9UqycllBDqQE/Rp2tPtqo11CjdcKs0KkceQCZjzmDlVPqMZrgh0FerTSysF0fcPKoKeAtqqk+WSu7Xk9lU+PCxGArGA+vBLTRRbAOuZpE7ORrS7AF2m5uaO1YOKfO0GN+LoxTiygI2aeqKsKMlPkboh4ZuEjv1ht9xUHeQtAf/MHtaXZDvaRQPXALf0oCRnDWpiiqvKdARJq5NXrrbrdow/M1FpoddtE0Mu65AsorIdXoPSXJnLhw/zDfHv82PQo0pW7ujc0yJY+5VzfURMZOyKmrfCmg==</ds:SignatureValue> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIEFTCCAv2gAwIBAgIJAI/HXXgQpJtFMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNVBAYTAkFUMRMw +EQYDVQQIEwpTb21lLVN0YXRlMQ0wCwYDVQQHEwRHcmF6MQ0wCwYDVQQKEwRFR0laMSIwIAYDVQQD +ExlNT0EtSUQgSURQIChUZXN0LVZlcnNpb24pMB4XDTE0MDEyMTA4NDAxOFoXDTE1MDEyMTA4NDAx +OFowZDELMAkGA1UEBhMCQVQxEzARBgNVBAgTClNvbWUtU3RhdGUxDTALBgNVBAcTBEdyYXoxDTAL +BgNVBAoTBEVHSVoxIjAgBgNVBAMTGU1PQS1JRCBJRFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFETzd0nLV2P4pUGnlLKj3V+MZ4bUyYkNK5NnkzB0PO8hm +tsrdg+HSNsnPiU5KvD26tFpxq9lfibZcAp9JHFqjA/capOHcTDhYkTvJcSdaKJzttTPy4wivTbRu +y+ocK9jjz6g8BFvP9wQ5/k2AwFaqj0SeJt0jJTn4CZ8XMNozA2hwkQA2heuMtOl24Ie9PRC3/Af7 +utV2CNfV2MysGHIxazsZDIgFF+5/nybyR1yiIxKb0BYDh3gbNdyH5uLVBHOP4hvzQN5Z1xc/cdzq +lzKn/4v6HJraNn00xLzK6nrG6gB6HvDok2l8T1Cc7f8I+sNlO2aM8rY4hGSGCfhiL6IFAgMBAAGj +gckwgcYwHQYDVR0OBBYEFKG3LzuPtAGCXUPTw3fo9dtsS9wWMIGWBgNVHSMEgY4wgYuAFKG3LzuP +tAGCXUPTw3fo9dtsS9wWoWikZjBkMQswCQYDVQQGEwJBVDETMBEGA1UECBMKU29tZS1TdGF0ZTEN +MAsGA1UEBxMER3JhejENMAsGA1UEChMERUdJWjEiMCAGA1UEAxMZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKYIJAI/HXXgQpJtFMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAME3wzEi +UAcF2pCDtMMJzX4IDhSkWNuvWtSMMy8Vgtcc2t570teIKh+qNKQWZyX3QFVE6ovDABg3ZUhn780l +G4/t6aMOUEeGg4udl7l0QRBRbdd+9oc0Aw5dQqku02AQ6wQd695PLj+F0GeA7cdef90aLPu6Rwa5 +z5BiKpReJZoul3NpjQXz7A1IslZOlIhEDcFUlBSn/+QfLOeNDKurvPT0OzUGSGfrv0AoniNHc/fz +lfyRmgFbzAVHedU5cIxcE0yHtEKFjFSVwtGng9rTJpoOoY4pvGvAHlw6GEgO+HwFukPDtnvY8vi/ +cfmNJhb06H+6mmHz929Bk4HuHoQj8X8=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </ds:Signature> + <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> + <md:KeyDescriptor use="signing"> + <ds:KeyInfo> + <ds:KeyValue> + <ds:RSAKeyValue> + <ds:Modulus>nEPzKMh3TovnfBnTyv+TMYFsGep8Uil7iNbfVyfLoBfqRdeGDOk4es2qWkgB6az+kM/9Js2H06m4 +pjEY7/RIjd0lMWqgi8eqdjilMmbFQykkYYQhlZbvi8KqoBcCKzj5N3GY4qh8A5qN4y85Q3sZj23T +iiIY1rphE+ZTOHCm6CKeRso9jj409YHP1xAXfPvtIYx2TA1uuagxOmL75OC/hr7gcUm0tmuKiSeq ++TO4VZw2Q7K7YESZ1WkiBoG2i4cHdcBFKnVrGNtyxl6UkjWxXRJSU9aNLs5QxsE6iFwCvFoIO+IU +cVWxfFHqOGbRtAcRUb4fk+KFHE2o1DLmfwZaUQ==</ds:Modulus> + <ds:Exponent>AQAB</ds:Exponent> + </ds:RSAKeyValue> + </ds:KeyValue> + </ds:KeyInfo> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIEFTCCAv2gAwIBAgIJAI/HXXgQpJtFMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNVBAYTAkFUMRMw +EQYDVQQIEwpTb21lLVN0YXRlMQ0wCwYDVQQHEwRHcmF6MQ0wCwYDVQQKEwRFR0laMSIwIAYDVQQD +ExlNT0EtSUQgSURQIChUZXN0LVZlcnNpb24pMB4XDTE0MDEyMTA4NDAxOFoXDTE1MDEyMTA4NDAx +OFowZDELMAkGA1UEBhMCQVQxEzARBgNVBAgTClNvbWUtU3RhdGUxDTALBgNVBAcTBEdyYXoxDTAL +BgNVBAoTBEVHSVoxIjAgBgNVBAMTGU1PQS1JRCBJRFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFETzd0nLV2P4pUGnlLKj3V+MZ4bUyYkNK5NnkzB0PO8hm +tsrdg+HSNsnPiU5KvD26tFpxq9lfibZcAp9JHFqjA/capOHcTDhYkTvJcSdaKJzttTPy4wivTbRu +y+ocK9jjz6g8BFvP9wQ5/k2AwFaqj0SeJt0jJTn4CZ8XMNozA2hwkQA2heuMtOl24Ie9PRC3/Af7 +utV2CNfV2MysGHIxazsZDIgFF+5/nybyR1yiIxKb0BYDh3gbNdyH5uLVBHOP4hvzQN5Z1xc/cdzq +lzKn/4v6HJraNn00xLzK6nrG6gB6HvDok2l8T1Cc7f8I+sNlO2aM8rY4hGSGCfhiL6IFAgMBAAGj +gckwgcYwHQYDVR0OBBYEFKG3LzuPtAGCXUPTw3fo9dtsS9wWMIGWBgNVHSMEgY4wgYuAFKG3LzuP +tAGCXUPTw3fo9dtsS9wWoWikZjBkMQswCQYDVQQGEwJBVDETMBEGA1UECBMKU29tZS1TdGF0ZTEN +MAsGA1UEBxMER3JhejENMAsGA1UEChMERUdJWjEiMCAGA1UEAxMZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKYIJAI/HXXgQpJtFMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAME3wzEi +UAcF2pCDtMMJzX4IDhSkWNuvWtSMMy8Vgtcc2t570teIKh+qNKQWZyX3QFVE6ovDABg3ZUhn780l +G4/t6aMOUEeGg4udl7l0QRBRbdd+9oc0Aw5dQqku02AQ6wQd695PLj+F0GeA7cdef90aLPu6Rwa5 +z5BiKpReJZoul3NpjQXz7A1IslZOlIhEDcFUlBSn/+QfLOeNDKurvPT0OzUGSGfrv0AoniNHc/fz +lfyRmgFbzAVHedU5cIxcE0yHtEKFjFSVwtGng9rTJpoOoY4pvGvAHlw6GEgO+HwFukPDtnvY8vi/ +cfmNJhb06H+6mmHz929Bk4HuHoQj8X8=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:KeyDescriptor use="encryption"> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIEFTCCAv2gAwIBAgIJAI/HXXgQpJtFMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNVBAYTAkFUMRMw +EQYDVQQIEwpTb21lLVN0YXRlMQ0wCwYDVQQHEwRHcmF6MQ0wCwYDVQQKEwRFR0laMSIwIAYDVQQD +ExlNT0EtSUQgSURQIChUZXN0LVZlcnNpb24pMB4XDTE0MDEyMTA4NDAxOFoXDTE1MDEyMTA4NDAx +OFowZDELMAkGA1UEBhMCQVQxEzARBgNVBAgTClNvbWUtU3RhdGUxDTALBgNVBAcTBEdyYXoxDTAL +BgNVBAoTBEVHSVoxIjAgBgNVBAMTGU1PQS1JRCBJRFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFETzd0nLV2P4pUGnlLKj3V+MZ4bUyYkNK5NnkzB0PO8hm +tsrdg+HSNsnPiU5KvD26tFpxq9lfibZcAp9JHFqjA/capOHcTDhYkTvJcSdaKJzttTPy4wivTbRu +y+ocK9jjz6g8BFvP9wQ5/k2AwFaqj0SeJt0jJTn4CZ8XMNozA2hwkQA2heuMtOl24Ie9PRC3/Af7 +utV2CNfV2MysGHIxazsZDIgFF+5/nybyR1yiIxKb0BYDh3gbNdyH5uLVBHOP4hvzQN5Z1xc/cdzq +lzKn/4v6HJraNn00xLzK6nrG6gB6HvDok2l8T1Cc7f8I+sNlO2aM8rY4hGSGCfhiL6IFAgMBAAGj +gckwgcYwHQYDVR0OBBYEFKG3LzuPtAGCXUPTw3fo9dtsS9wWMIGWBgNVHSMEgY4wgYuAFKG3LzuP +tAGCXUPTw3fo9dtsS9wWoWikZjBkMQswCQYDVQQGEwJBVDETMBEGA1UECBMKU29tZS1TdGF0ZTEN +MAsGA1UEBxMER3JhejENMAsGA1UEChMERUdJWjEiMCAGA1UEAxMZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKYIJAI/HXXgQpJtFMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAME3wzEi +UAcF2pCDtMMJzX4IDhSkWNuvWtSMMy8Vgtcc2t570teIKh+qNKQWZyX3QFVE6ovDABg3ZUhn780l +G4/t6aMOUEeGg4udl7l0QRBRbdd+9oc0Aw5dQqku02AQ6wQd695PLj+F0GeA7cdef90aLPu6Rwa5 +z5BiKpReJZoul3NpjQXz7A1IslZOlIhEDcFUlBSn/+QfLOeNDKurvPT0OzUGSGfrv0AoniNHc/fz +lfyRmgFbzAVHedU5cIxcE0yHtEKFjFSVwtGng9rTJpoOoY4pvGvAHlw6GEgO+HwFukPDtnvY8vi/ +cfmNJhb06H+6mmHz929Bk4HuHoQj8X8=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://demo.egiz.gv.at/demoportal_demologin/pvp2/sp/redirect"/> + <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat> + <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> + <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://demo.egiz.gv.at/demoportal_demologin/pvp2/sp/post" index="0" isDefault="true"/> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://demo.egiz.gv.at/demoportal_demologin/pvp2/sp/redirect" index="1"/> + </md:SPSSODescriptor> + <md:Organization> + <md:OrganizationName xml:lang="de">EGIZ</md:OrganizationName> + <md:OrganizationDisplayName xml:lang="de">E-Government Innovationszentrum</md:OrganizationDisplayName> + <md:OrganizationURL xml:lang="de">http://www.egiz.gv.at</md:OrganizationURL> + </md:Organization> + <md:ContactPerson contactType="technical"> + <md:Company>E-Government Innovationszentrum</md:Company> + <md:GivenName>Lenz</md:GivenName> + <md:SurName>Thomas</md:SurName> + <md:EmailAddress>thomas.lenz@egiz.gv.at</md:EmailAddress> + <md:TelephoneNumber>+43 316 873 5525</md:TelephoneNumber> + </md:ContactPerson> +</md:EntityDescriptor> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_wrong_sig.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_wrong_sig.xml new file mode 100644 index 00000000..510c84f8 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_metadata_wrong_sig.xml @@ -0,0 +1,162 @@ +<?xml version="1.0" encoding="UTF-8"?> +<md:EntityDescriptor + xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" + xmlns:ds="http://www.w3.org/2000/09/xmldsig#" + entityID="https://demo.egiz.gv.at/demoportal_demologin/" + validUntil="2059-07-27T11:23:29.736Z"> + <ds:Signature> + <ds:SignedInfo> + <ds:CanonicalizationMethod + Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> + <ds:SignatureMethod + Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /> + <ds:Reference + URI="#_c0303e3081ac29bb8329cade76279069"> + <ds:Transforms> + <ds:Transform + Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> + <ds:Transform + Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> + </ds:Transforms> + <ds:DigestMethod + Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> + <ds:DigestValue>IjxuoZphYVmZdZ5HfoVDr35r2b1V840+SMeC89IO/SQ= + </ds:DigestValue> + </ds:Reference> + </ds:SignedInfo> + <ds:SignatureValue>JILQKKPvsK7onsMweJauAcGEniFGJ5bXEOvfYhxAYCB+dXL6pH87USD1v9UqycllBDqQE/Rp2tPtqo11CjdcKs0KkceQCZjzmDlVPqMZrgh0FerTSysF0fcPKoKeAtqqk+WSu7Xk9lU+PCxGArGA+vBLTRRbAOuZpE7ORrS7AF2m5uaO1YOKfO0GN+LoxTiygI2aeqKsKMlPkboh4ZuEjv1ht9xUHeQtAf/MHtaXZDvaRQPXALf0oCRnDWpiiqvKdARJq5NXrrbrdow/M1FpoddtE0Mu65AsorIdXoPSXJnLhw/zDfHv82PQo0pW7ujc0yJY+5VzfURMZOyKmrfCmg== + </ds:SignatureValue> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIEFTCCAv2gAwIBAgIJAI/HXXgQpJtFMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNVBAYTAkFUMRMw + EQYDVQQIEwpTb21lLVN0YXRlMQ0wCwYDVQQHEwRHcmF6MQ0wCwYDVQQKEwRFR0laMSIwIAYDVQQD + ExlNT0EtSUQgSURQIChUZXN0LVZlcnNpb24pMB4XDTE0MDEyMTA4NDAxOFoXDTE1MDEyMTA4NDAx + OFowZDELMAkGA1UEBhMCQVQxEzARBgNVBAgTClNvbWUtU3RhdGUxDTALBgNVBAcTBEdyYXoxDTAL + BgNVBAoTBEVHSVoxIjAgBgNVBAMTGU1PQS1JRCBJRFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqG + SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFETzd0nLV2P4pUGnlLKj3V+MZ4bUyYkNK5NnkzB0PO8hm + tsrdg+HSNsnPiU5KvD26tFpxq9lfibZcAp9JHFqjA/capOHcTDhYkTvJcSdaKJzttTPy4wivTbRu + y+ocK9jjz6g8BFvP9wQ5/k2AwFaqj0SeJt0jJTn4CZ8XMNozA2hwkQA2heuMtOl24Ie9PRC3/Af7 + utV2CNfV2MysGHIxazsZDIgFF+5/nybyR1yiIxKb0BYDh3gbNdyH5uLVBHOP4hvzQN5Z1xc/cdzq + lzKn/4v6HJraNn00xLzK6nrG6gB6HvDok2l8T1Cc7f8I+sNlO2aM8rY4hGSGCfhiL6IFAgMBAAGj + gckwgcYwHQYDVR0OBBYEFKG3LzuPtAGCXUPTw3fo9dtsS9wWMIGWBgNVHSMEgY4wgYuAFKG3LzuP + tAGCXUPTw3fo9dtsS9wWoWikZjBkMQswCQYDVQQGEwJBVDETMBEGA1UECBMKU29tZS1TdGF0ZTEN + MAsGA1UEBxMER3JhejENMAsGA1UEChMERUdJWjEiMCAGA1UEAxMZTU9BLUlEIElEUCAoVGVzdC1W + ZXJzaW9uKYIJAI/HXXgQpJtFMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAME3wzEi + UAcF2pCDtMMJzX4IDhSkWNuvWtSMMy8Vgtcc2t570teIKh+qNKQWZyX3QFVE6ovDABg3ZUhn780l + G4/t6aMOUEeGg4udl7l0QRBRbdd+9oc0Aw5dQqku02AQ6wQd695PLj+F0GeA7cdef90aLPu6Rwa5 + z5BiKpReJZoul3NpjQXz7A1IslZOlIhEDcFUlBSn/+QfLOeNDKurvPT0OzUGSGfrv0AoniNHc/fz + lfyRmgFbzAVHedU5cIxcE0yHtEKFjFSVwtGng9rTJpoOoY4pvGvAHlw6GEgO+HwFukPDtnvY8vi/ + cfmNJhb06H+6mmHz929Bk4HuHoQj8X8= + </ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </ds:Signature> + <md:SPSSODescriptor AuthnRequestsSigned="true" + WantAssertionsSigned="true" + protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> + <md:KeyDescriptor use="signing"> + <ds:KeyInfo> + <ds:KeyValue> + <ds:RSAKeyValue> + <ds:Modulus>nEPzKMh3TovnfBnTyv+TMYFsGep8Uil7iNbfVyfLoBfqRdeGDOk4es2qWkgB6az+kM/9Js2H06m4 + pjEY7/RIjd0lMWqgi8eqdjilMmbFQykkYYQhlZbvi8KqoBcCKzj5N3GY4qh8A5qN4y85Q3sZj23T + iiIY1rphE+ZTOHCm6CKeRso9jj409YHP1xAXfPvtIYx2TA1uuagxOmL75OC/hr7gcUm0tmuKiSeq + +TO4VZw2Q7K7YESZ1WkiBoG2i4cHdcBFKnVrGNtyxl6UkjWxXRJSU9aNLs5QxsE6iFwCvFoIO+IU + cVWxfFHqOGbRtAcRUb4fk+KFHE2o1DLmfwZaUQ== + </ds:Modulus> + <ds:Exponent>AQAB</ds:Exponent> + </ds:RSAKeyValue> + </ds:KeyValue> + <ds:KeyValue> + <ds:RSAKeyValue> + <ds:Modulus>xA7SEU+e0yQH5rm9kbCDN9o3aPIo7HbP7tX6WOocLZAtNfyxSZDU16ksL6W + jubafOqNEpcwR3RdFsT7bCqnXPBe5ELh5u4VEy19MzxkXRgrMvavzyBpVRgBUwUlV + 5foK5hhmbktQhyNdy/6LpQRhDUDsTvK+g9Ucj47es9AQJ3U= + </ds:Modulus> + <ds:Exponent>AQAB</ds:Exponent> + </ds:RSAKeyValue> + </ds:KeyValue> + <!-- ds:X509Data> + <ds:X509Certificate>MIIEFTCCAv2gAwIBAgIJAI/HXXgQpJtFMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNVBAYTAkFUMRMw + EQYDVQQIEwpTb21lLVN0YXRlMQ0wCwYDVQQHEwRHcmF6MQ0wCwYDVQQKEwRFR0laMSIwIAYDVQQD + ExlNT0EtSUQgSURQIChUZXN0LVZlcnNpb24pMB4XDTE0MDEyMTA4NDAxOFoXDTE1MDEyMTA4NDAx + OFowZDELMAkGA1UEBhMCQVQxEzARBgNVBAgTClNvbWUtU3RhdGUxDTALBgNVBAcTBEdyYXoxDTAL + BgNVBAoTBEVHSVoxIjAgBgNVBAMTGU1PQS1JRCBJRFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqG + SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFETzd0nLV2P4pUGnlLKj3V+MZ4bUyYkNK5NnkzB0PO8hm + tsrdg+HSNsnPiU5KvD26tFpxq9lfibZcAp9JHFqjA/capOHcTDhYkTvJcSdaKJzttTPy4wivTbRu + y+ocK9jjz6g8BFvP9wQ5/k2AwFaqj0SeJt0jJTn4CZ8XMNozA2hwkQA2heuMtOl24Ie9PRC3/Af7 + utV2CNfV2MysGHIxazsZDIgFF+5/nybyR1yiIxKb0BYDh3gbNdyH5uLVBHOP4hvzQN5Z1xc/cdzq + lzKn/4v6HJraNn00xLzK6nrG6gB6HvDok2l8T1Cc7f8I+sNlO2aM8rY4hGSGCfhiL6IFAgMBAAGj + gckwgcYwHQYDVR0OBBYEFKG3LzuPtAGCXUPTw3fo9dtsS9wWMIGWBgNVHSMEgY4wgYuAFKG3LzuP + tAGCXUPTw3fo9dtsS9wWoWikZjBkMQswCQYDVQQGEwJBVDETMBEGA1UECBMKU29tZS1TdGF0ZTEN + MAsGA1UEBxMER3JhejENMAsGA1UEChMERUdJWjEiMCAGA1UEAxMZTU9BLUlEIElEUCAoVGVzdC1W + ZXJzaW9uKYIJAI/HXXgQpJtFMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAME3wzEi + UAcF2pCDtMMJzX4IDhSkWNuvWtSMMy8Vgtcc2t570teIKh+qNKQWZyX3QFVE6ovDABg3ZUhn780l + G4/t6aMOUEeGg4udl7l0QRBRbdd+9oc0Aw5dQqku02AQ6wQd695PLj+F0GeA7cdef90aLPu6Rwa5 + z5BiKpReJZoul3NpjQXz7A1IslZOlIhEDcFUlBSn/+QfLOeNDKurvPT0OzUGSGfrv0AoniNHc/fz + lfyRmgFbzAVHedU5cIxcE0yHtEKFjFSVwtGng9rTJpoOoY4pvGvAHlw6GEgO+HwFukPDtnvY8vi/ + cfmNJhb06H+6mmHz929Bk4HuHoQj8X8= + </ds:X509Certificate> + </ds:X509Data--> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:KeyDescriptor use="encryption"> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIEFTCCAv2gAwIBAgIJAI/HXXgQpJtFMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNVBAYTAkFUMRMw + EQYDVQQIEwpTb21lLVN0YXRlMQ0wCwYDVQQHEwRHcmF6MQ0wCwYDVQQKEwRFR0laMSIwIAYDVQQD + ExlNT0EtSUQgSURQIChUZXN0LVZlcnNpb24pMB4XDTE0MDEyMTA4NDAxOFoXDTE1MDEyMTA4NDAx + OFowZDELMAkGA1UEBhMCQVQxEzARBgNVBAgTClNvbWUtU3RhdGUxDTALBgNVBAcTBEdyYXoxDTAL + BgNVBAoTBEVHSVoxIjAgBgNVBAMTGU1PQS1JRCBJRFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqG + SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFETzd0nLV2P4pUGnlLKj3V+MZ4bUyYkNK5NnkzB0PO8hm + tsrdg+HSNsnPiU5KvD26tFpxq9lfibZcAp9JHFqjA/capOHcTDhYkTvJcSdaKJzttTPy4wivTbRu + y+ocK9jjz6g8BFvP9wQ5/k2AwFaqj0SeJt0jJTn4CZ8XMNozA2hwkQA2heuMtOl24Ie9PRC3/Af7 + utV2CNfV2MysGHIxazsZDIgFF+5/nybyR1yiIxKb0BYDh3gbNdyH5uLVBHOP4hvzQN5Z1xc/cdzq + lzKn/4v6HJraNn00xLzK6nrG6gB6HvDok2l8T1Cc7f8I+sNlO2aM8rY4hGSGCfhiL6IFAgMBAAGj + gckwgcYwHQYDVR0OBBYEFKG3LzuPtAGCXUPTw3fo9dtsS9wWMIGWBgNVHSMEgY4wgYuAFKG3LzuP + tAGCXUPTw3fo9dtsS9wWoWikZjBkMQswCQYDVQQGEwJBVDETMBEGA1UECBMKU29tZS1TdGF0ZTEN + MAsGA1UEBxMER3JhejENMAsGA1UEChMERUdJWjEiMCAGA1UEAxMZTU9BLUlEIElEUCAoVGVzdC1W + ZXJzaW9uKYIJAI/HXXgQpJtFMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAME3wzEi + UAcF2pCDtMMJzX4IDhSkWNuvWtSMMy8Vgtcc2t570teIKh+qNKQWZyX3QFVE6ovDABg3ZUhn780l + G4/t6aMOUEeGg4udl7l0QRBRbdd+9oc0Aw5dQqku02AQ6wQd695PLj+F0GeA7cdef90aLPu6Rwa5 + z5BiKpReJZoul3NpjQXz7A1IslZOlIhEDcFUlBSn/+QfLOeNDKurvPT0OzUGSGfrv0AoniNHc/fz + lfyRmgFbzAVHedU5cIxcE0yHtEKFjFSVwtGng9rTJpoOoY4pvGvAHlw6GEgO+HwFukPDtnvY8vi/ + cfmNJhb06H+6mmHz929Bk4HuHoQj8X8= + </ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:SingleLogoutService + Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" + Location="https://demo.egiz.gv.at/demoportal_demologin/pvp2/sp/redirect" /> + <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + </md:NameIDFormat> + <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient + </md:NameIDFormat> + <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified + </md:NameIDFormat> + <md:AssertionConsumerService + Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" + Location="https://demo.egiz.gv.at/demoportal_demologin/pvp2/sp/post" + index="0" isDefault="true" /> + <md:AssertionConsumerService + Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" + Location="https://demo.egiz.gv.at/demoportal_demologin/pvp2/sp/redirect" + index="1" /> + </md:SPSSODescriptor> + <md:Organization> + <md:OrganizationName xml:lang="de">EGIZ + </md:OrganizationName> + <md:OrganizationDisplayName xml:lang="de">E-Government + Innovationszentrum</md:OrganizationDisplayName> + <md:OrganizationURL xml:lang="de">http://www.egiz.gv.at + </md:OrganizationURL> + </md:Organization> + <md:ContactPerson contactType="technical"> + <md:Company>E-Government Innovationszentrum</md:Company> + <md:GivenName>Lenz</md:GivenName> + <md:SurName>Thomas</md:SurName> + <md:EmailAddress>thomas.lenz@egiz.gv.at</md:EmailAddress> + <md:TelephoneNumber>+43 316 873 5525</md:TelephoneNumber> + </md:ContactPerson> +</md:EntityDescriptor> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml index de3cfbd1..375224bb 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml @@ -18,5 +18,8 @@ <bean id="dummyGuiBuilderConfigFactory" class="at.gv.egiz.eaaf.core.impl.idp.module.gui.DummyGuiBuilderConfigurationFactory" /> + + <bean id="httpClientFactory" + class="at.gv.egiz.eaaf.core.impl.utils.HttpClientFactory" /> </beans>
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_pvp.beans.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_pvp.beans.xml index f261e893..aac94041 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_pvp.beans.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_pvp.beans.xml @@ -10,20 +10,11 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> - <import resource="test_eaaf_core.beans.xml"/> + <import resource="test_eaaf_core.beans.xml"/> + <import resource="classpath:/eaaf_pvp.beans.xml"/> <bean id="dummyCredentialProvider" class="at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider" /> - <bean id="PvpPostBinding" - class="at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding" /> - - <bean id="PvpRedirectBinding" - class="at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding" /> - - <bean id="PvpSoapBinding" - class="at.gv.egiz.eaaf.modules.pvp2.impl.binding.SoapBinding" /> - - - + </beans>
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_idp/pom.xml b/eaaf_modules/eaaf_module_pvp2_idp/pom.xml index e687f48a..2e9cb88d 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/pom.xml +++ b/eaaf_modules/eaaf_module_pvp2_idp/pom.xml @@ -8,7 +8,7 @@ <version>1.1.0-SNAPSHOT</version> </parent> <artifactId>eaaf_module_pvp2_idp</artifactId> - <name>eaaf_module_pvp2_core</name> + <name>eaaf_module_pvp2_idp</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> @@ -32,6 +32,23 @@ <artifactId>junit</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>at.gv.egiz.eaaf</groupId> + <artifactId>eaaf-core</artifactId> + <scope>test</scope> + <type>test-jar</type> + </dependency> + <dependency> + <groupId>at.gv.egiz.eaaf</groupId> + <artifactId>eaaf_module_pvp2_core</artifactId> + <scope>test</scope> + <type>test-jar</type> + </dependency> </dependencies> <build> @@ -49,21 +66,20 @@ </plugin> <!-- enable co-existence of testng and junit --> - <plugin> - <artifactId>maven-surefire-plugin</artifactId> - <version>${surefire.version}</version> - <configuration> - <threadCount>1</threadCount> - <argLine>--add-modules java.xml.bind</argLine> - </configuration> - <dependencies> - <dependency> - <groupId>org.apache.maven.surefire</groupId> - <artifactId>surefire-junit47</artifactId> - <version>${surefire.version}</version> - </dependency> - </dependencies> - </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>${surefire.version}</version> + <configuration> + <threadCount>1</threadCount> + </configuration> + <dependencies> + <dependency> + <groupId>org.apache.maven.surefire</groupId> + <artifactId>surefire-junit47</artifactId> + <version>${surefire.version}</version> + </dependency> + </dependencies> + </plugin> </plugins> </build> diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java index 9414dc33..7e572d70 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java @@ -20,6 +20,7 @@ package at.gv.egiz.eaaf.modules.pvp2.idp; import at.gv.egiz.components.spring.api.SpringResourceProvider; + import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -41,7 +42,7 @@ public class Pvp2SProfileIdpSpringResourceProvider implements SpringResourceProv final ClassPathResource sl20AuthConfig = new ClassPathResource("/eaaf_pvp_idp.beans.xml", Pvp2SProfileIdpSpringResourceProvider.class); - return new Resource[] {sl20AuthConfig}; + return new Resource[] { sl20AuthConfig }; } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java index 0003b829..a7e05664 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java @@ -28,21 +28,19 @@ public class InvalidAssertionConsumerServiceException extends Pvp2Exception { private static final long serialVersionUID = 7861790149343943091L; public InvalidAssertionConsumerServiceException(final int idx) { - super("pvp2.28", new Object[] {idx}); + super("pvp2.28", new Object[] { idx }); this.statusCodeValue = StatusCode.REQUESTER; } /** * Invalid assertion consumer-service URL. * - * @param wrongUrl invalid URL + * @param wrongUrl invalid URL */ public InvalidAssertionConsumerServiceException(final String wrongUrl) { - super("pvp2.23", new Object[] {wrongUrl}); + super("pvp2.23", new Object[] { wrongUrl }); this.statusCodeValue = StatusCode.REQUESTER; } - - } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java index c02e534c..add2103b 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java @@ -37,7 +37,4 @@ public class SamlRequestNotSignedException extends Pvp2Exception { this.statusCodeValue = StatusCode.REQUESTER; } - - - } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java index b0dcdb2e..d672f457 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java @@ -23,7 +23,6 @@ import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import org.opensaml.saml.saml2.core.StatusCode; - public class SamlRequestNotSupported extends Pvp2Exception { private static final long serialVersionUID = 1244883178458802767L; @@ -33,7 +32,4 @@ public class SamlRequestNotSupported extends Pvp2Exception { this.statusCodeValue = StatusCode.REQUEST_UNSUPPORTED; } - - - } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java index 0f84b8fb..3a56b414 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java @@ -28,7 +28,7 @@ public class UnprovideableAttributeException extends Pvp2Exception { private static final long serialVersionUID = 3972197758163647157L; public UnprovideableAttributeException(final String attributeName) { - super("pvp2.10", new Object[] {attributeName}); + super("pvp2.10", new Object[] { attributeName }); this.statusCodeValue = StatusCode.UNKNOWN_ATTR_PROFILE; } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java index f86fd883..1ef7da29 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java @@ -46,6 +46,7 @@ import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException; import at.gv.egiz.eaaf.modules.pvp2.exception.NameIdFormatNotSupportedException; import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionConsumerServiceException; import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; @@ -72,7 +73,6 @@ import org.opensaml.saml.saml2.core.StatusMessage; import org.opensaml.saml.saml2.metadata.AssertionConsumerService; import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.opensaml.saml.saml2.metadata.SPSSODescriptor; -import org.opensaml.ws.security.SecurityPolicyException; import org.opensaml.xmlsec.signature.SignableXMLObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,6 +81,9 @@ import org.springframework.beans.factory.annotation.Autowired; public abstract class AbstractPvp2XProtocol extends AbstractController implements IModulInfo { private static final Logger log = LoggerFactory.getLogger(AbstractPvp2XProtocol.class); + private static final String HTTP_PARAM_SAMLREQ = "SAMLRequest"; + private static final String ERROR_INVALID_REQUEST = "Receive INVALID protocol request: {}"; + @Autowired(required = true) protected IPvp2BasicConfiguration pvpBasicConfiguration; @Autowired(required = true) @@ -92,8 +95,6 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement private AbstractCredentialProvider pvpIdpCredentials; - - /** * Sets a specific credential provider for PVP S-Profile IDP component. * @@ -151,7 +152,6 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement moaError = statusMessager.getResponseErrorCode(e); } - if (StringUtils.isNotEmpty(moaError)) { final StatusCode moaStatusCode = Saml2Utils.createSamlObject(StatusCode.class); moaStatusCode.setValue(moaError); @@ -245,16 +245,16 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement // get POST-Binding decoder implementation final InboundMessage msg = (InboundMessage) new PostBinding().decode(req, resp, - metadataProvider, false, + metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, new EaafUriCompare(pvpBasicConfiguration.getIdpSsoPostService(pendingReq.getAuthUrl()))); pendingReq.setRequest(msg); // preProcess Message preProcess(req, resp, pendingReq); - } catch (final SecurityPolicyException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + } catch (final SamlSigningException e) { + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -264,9 +264,9 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - } catch (final SecurityException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + } catch (final Pvp2Exception e) { + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -274,7 +274,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement pendingReq.getUniqueTransactionIdentifier()); } - throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + throw new InvalidProtocolRequestException("pvp2.22", new Object[] { e.getMessage() }); } catch (final EaafException e) { @@ -287,8 +287,8 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement throw e; } catch (final Throwable e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -296,7 +296,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement pendingReq.getUniqueTransactionIdentifier()); } - throw new EaafException("pvp2.24", new Object[] {e.getMessage()}, e); + throw new EaafException("pvp2.24", new Object[] { e.getMessage() }, e); } } @@ -319,16 +319,16 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement // get POST-Binding decoder implementation final InboundMessage msg = (InboundMessage) new RedirectBinding().decode(req, resp, - metadataProvider, false, new EaafUriCompare( + metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, new EaafUriCompare( pvpBasicConfiguration.getIdpSsoRedirectService(pendingReq.getAuthUrl()))); pendingReq.setRequest(msg); // preProcess Message preProcess(req, resp, pendingReq); - } catch (final SecurityPolicyException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + } catch (final SamlSigningException e) { + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -338,9 +338,9 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - } catch (final SecurityException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + } catch (final Pvp2Exception e) { + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -348,11 +348,11 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement pendingReq.getUniqueTransactionIdentifier()); } - throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + throw new InvalidProtocolRequestException("pvp2.22", new Object[] { e.getMessage() }); } catch (final EaafException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.info("Receive INVALID protocol request: " + samlRequest); + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.info(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -363,8 +363,8 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement throw e; } catch (final Throwable e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -372,17 +372,15 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement pendingReq.getUniqueTransactionIdentifier()); } - throw new EaafException("pvp2.24", new Object[] {e.getMessage()}, e); + throw new EaafException("pvp2.24", new Object[] { e.getMessage() }, e); } } - - /** * Authentication request pre-processor. * - * @param request http request - * @param response http response + * @param request http request + * @param response http response * @param pendingReq current pending request * @return true if preprocess can handle this request type, otherwise false * @throws Throwable In case of an error @@ -419,20 +417,17 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement log.error("Receive unsupported PVP21 message of type: " + ((PvpSProfileRequest) msg).getSamlRequest().getClass().getName()); throw new InvalidPvpRequestException("pvp2.09", - new Object[] {((PvpSProfileRequest) msg).getSamlRequest().getClass().getName()}); + new Object[] { ((PvpSProfileRequest) msg).getSamlRequest().getClass().getName() }); } - - // switch to session authentication protAuthService.performAuthentication(request, response, pendingReq); } - /** * PreProcess Authn request. * - * @param request http request + * @param request http request * @param pendingReq current pending request * @throws Throwable in case of an error */ @@ -458,7 +453,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement if (authnRequest.getIssueInstant() == null) { log.warn("Unsupported request: No IssueInstant Attribute found."); throw new AuthnRequestValidatorException("pvp2.22", - new Object[] {"Unsupported request: No IssueInstant Attribute found"}, pendingReq); + new Object[] { "Unsupported request: No IssueInstant Attribute found" }, pendingReq); } @@ -466,7 +461,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement .isAfterNow()) { log.warn("Unsupported request: No IssueInstant DateTime is not valid anymore."); throw new AuthnRequestValidatorException("pvp2.22", - new Object[] {"Unsupported request: No IssueInstant DateTime is not valid anymore."}, + new Object[] { "Unsupported request: No IssueInstant DateTime is not valid anymore." }, pendingReq); } @@ -496,14 +491,13 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement } - } else { // use AssertionConsumerServiceIndex and select consumerService from metadata final Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); int assertionidx = 0; if (aIdx != null) { - assertionidx = aIdx.intValue(); + assertionidx = aIdx; } else { assertionidx = Saml2Utils.getDefaultAssertionConsumerServiceIndex(spSsoDescriptor); @@ -517,7 +511,6 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement } } - // validate AuthnRequest final AuthnRequest authReq = (AuthnRequest) samlReq; final String oaUrl = moaRequest.getEntityMetadata(metadataProvider).getEntityID(); diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java index 200d98c4..c0190959 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java @@ -23,19 +23,6 @@ import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.joda.time.DateTime; -import org.opensaml.saml.common.xml.SAMLConstants; -import org.opensaml.saml.saml2.core.Assertion; -import org.opensaml.saml.saml2.core.AuthnRequest; -import org.opensaml.saml.saml2.core.Response; -import org.opensaml.saml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml.saml2.metadata.EntityDescriptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.stereotype.Service; - import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.IAction; import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -57,13 +44,23 @@ import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import org.joda.time.DateTime; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; + @Service("PVPAuthenticationRequestAction") public class AuthenticationAction implements IAction { private static final Logger log = LoggerFactory.getLogger(AuthenticationAction.class); - private static final String CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION = - "protocols.pvp2.assertion.encryption.active"; - @Autowired(required = true) private IPvp2MetadataProvider metadataProvider; @Autowired(required = true) @@ -115,7 +112,7 @@ public class AuthenticationAction implements IAction { final Response authResponse = AuthResponseBuilder.buildResponse(metadataProvider, issuerEntityID, authnRequest, date, assertion, - authConfig.getBasicConfigurationBoolean(CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION, true)); + authConfig); IEncoder binding = null; @@ -141,7 +138,7 @@ public class AuthenticationAction implements IAction { sloInformation.setSpEntityID(req.getServiceProviderConfiguration().getUniqueIdentifier()); return sloInformation; - } catch (SecurityException e) { + } catch (final SecurityException e) { log.warn("Message Encoding exception", e); throw new ResponderErrorException("pvp2.01", null, e); diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java index a1e8b5ba..3f0ad0b6 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java @@ -22,6 +22,7 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.IAction; import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -33,6 +34,7 @@ import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataConfigurationFactor import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -74,8 +76,6 @@ public class MetadataAction implements IAction { final IPvpMetadataBuilderConfiguration metadataConfig = configFactory .generateMetadataBuilderConfiguration(req.getAuthUrlWithOutSlash(), pvpIdpCredentials); - - final String metadataXml = metadatabuilder.buildPvpMetadata(metadataConfig); log.trace("METADATA: " + metadataXml); @@ -117,5 +117,4 @@ public class MetadataAction implements IAction { } } - } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java index 6c621841..26e04881 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java @@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl; import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java index 8cafebb9..55e3e8b4 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java @@ -19,37 +19,55 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder; +import java.security.PublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.List; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; + import org.joda.time.DateTime; import org.opensaml.core.criterion.EntityIdCriterion; import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.criterion.EntityRoleCriterion; +import org.opensaml.saml.criterion.ProtocolCriterion; +import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver; import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.EncryptedAssertion; import org.opensaml.saml.saml2.core.Issuer; import org.opensaml.saml.saml2.core.NameIDType; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.encryption.Encrypter; import org.opensaml.saml.saml2.encryption.Encrypter.KeyPlacement; import org.opensaml.saml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml.security.impl.MetadataCredentialResolver; -import org.opensaml.security.MetadataCriteria; import org.opensaml.security.credential.UsageType; import org.opensaml.security.criteria.UsageCriterion; import org.opensaml.security.x509.X509Credential; -import org.opensaml.xmlsec.EncryptionParameters; +import org.opensaml.xmlsec.SecurityConfigurationSupport; +import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters; import org.opensaml.xmlsec.encryption.support.EncryptionException; import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters; +import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver; import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorFactory; +import org.opensaml.xmlsec.keyinfo.impl.BasicProviderKeyInfoCredentialResolver; +import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.DSAKeyValueProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.InlineX509DataProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.RSAKeyValueProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.resolver.CriteriaSet; +import net.shibboleth.utilities.java.support.resolver.ResolverException; /** * Authentication response builder. @@ -65,17 +83,17 @@ public class AuthResponseBuilder { * Build PVP2 S-Profile authentication response. * * @param metadataProvider Service-Provider metadata - * @param issuerEntityID IDP entityId - * @param req current pending request - * @param date Timestamp - * @param assertion PVP2 S-Profil Assertion - * @param enableEncryption encrypt Assertion flag + * @param issuerEntityID IDP entityId + * @param req current pending request + * @param date Timestamp + * @param assertion PVP2 S-Profil Assertion + * @param authConfig {@link IConfiguration} * @return PVP2 S-Profile authentication response * @throws InvalidAssertionEncryptionException In case of an error */ public static Response buildResponse(final IPvp2MetadataProvider metadataProvider, final String issuerEntityID, final RequestAbstractType req, final DateTime date, - final Assertion assertion, final boolean enableEncryption) + final Assertion assertion, IConfiguration authConfig) throws InvalidAssertionEncryptionException { final Response authResponse = Saml2Utils.createSamlObject(Response.class); @@ -90,72 +108,117 @@ public class AuthResponseBuilder { final String remoteSessionID = Saml2Utils.getSecureIdentifier(); authResponse.setID(remoteSessionID); - // SAML2 response required IssueInstant authResponse.setIssueInstant(date); authResponse.setStatus(Saml2Utils.getSuccessStatus()); // check, if metadata includes an encryption key - final MetadataCredentialResolver mdCredResolver = - new MetadataCredentialResolver(metadataProvider); - - final CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add(new EntityIdCriterion(req.getIssuer().getValue())); - criteriaSet - .add(new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); - criteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION)); + final X509Credential encryptionCredentials = resolveEncryptionCredential(req, metadataProvider); - X509Credential encryptionCredentials = null; - try { - encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); + if (encryptionCredentials != null + && authConfig.getBasicConfigurationBoolean( + PvpConstants.CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION, true)) { + authResponse.getEncryptedAssertions().add( + doEncryption(assertion, encryptionCredentials, authConfig)); - } catch (final SecurityException e2) { - log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); - throw new InvalidAssertionEncryptionException(); + } else { + authResponse.getAssertions().add(assertion); } - if (encryptionCredentials != null && enableEncryption) { - // encrypt SAML2 assertion + return authResponse; + } + + private static EncryptedAssertion doEncryption(Assertion assertion, + X509Credential encryptionCredentials, IConfiguration authConfig) + throws InvalidAssertionEncryptionException { + try { + final String keyEncAlg = selectKeyEncryptionAlgorithm(encryptionCredentials, authConfig); - try { + final DataEncryptionParameters dataEncParams = new DataEncryptionParameters(); + dataEncParams.setAlgorithm(authConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_DATA, PvpConstants.DEFAULT_SYM_ENCRYPTION_METHODE)); - final EncryptionParameters dataEncParams = new EncryptionParameters(); - dataEncParams.setAlgorithm(PvpConstants.DEFAULT_SYM_ENCRYPTION_METHODE); + final List<KeyEncryptionParameters> keyEncParamList = new ArrayList<>(); + final KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); + keyEncParam.setEncryptionCredential(encryptionCredentials); + keyEncParam.setAlgorithm(keyEncAlg); - final List<KeyEncryptionParameters> keyEncParamList = new ArrayList<>(); - final KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); + final KeyInfoGeneratorFactory kigf = + SecurityConfigurationSupport.getGlobalEncryptionConfiguration() + .getKeyTransportKeyInfoGeneratorManager().getDefaultManager().getFactory(encryptionCredentials); + keyEncParam.setKeyInfoGenerator(kigf.newInstance()); + keyEncParamList.add(keyEncParam); - keyEncParam.setEncryptionCredential(encryptionCredentials); - keyEncParam.setAlgorithm(PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE); - final KeyInfoGeneratorFactory kigf = - org.opensaml.xml.Configuration.getGlobalSecurityConfiguration() - .getKeyInfoGeneratorManager().getDefaultManager().getFactory(encryptionCredentials); - keyEncParam.setKeyInfoGenerator(kigf.newInstance()); - keyEncParamList.add(keyEncParam); + final Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); + samlEncrypter.setKeyPlacement(KeyPlacement.PEER); - final Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); - // samlEncrypter.setKeyPlacement(KeyPlacement.INLINE); - samlEncrypter.setKeyPlacement(KeyPlacement.PEER); + return samlEncrypter.encrypt(assertion); - EncryptedAssertion encryptAssertion = null; + } catch (final EncryptionException | SamlSigningException e1) { + log.warn("Can not encrypt the PVP2 assertion", e1); + throw new InvalidAssertionEncryptionException(); - encryptAssertion = samlEncrypter.encrypt(assertion); + } - authResponse.getEncryptedAssertions().add(encryptAssertion); + } - } catch (final EncryptionException e1) { - log.warn("Can not encrypt the PVP2 assertion", e1); - throw new InvalidAssertionEncryptionException(); + private static String selectKeyEncryptionAlgorithm(X509Credential encryptionCredentials, + IConfiguration authConfig) throws SamlSigningException { + final PublicKey privatekey = encryptionCredentials.getPublicKey(); + if (privatekey instanceof RSAPublicKey) { + return authConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_KEY_RSA_ALG, + PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE_RSA); - } + } else if (privatekey instanceof ECPublicKey) { + return authConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_KEY_EC_ALG, + PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE_EC); } else { - authResponse.getAssertions().add(assertion); + log.warn("Could NOT evaluate the Private-Key type from " + encryptionCredentials.getEntityId() + + " credential."); + throw new SamlSigningException("internal.pvp.97", + new Object[] { encryptionCredentials.getEntityId(), privatekey.getClass().getName() }); } - return authResponse; + } + + private static X509Credential resolveEncryptionCredential(RequestAbstractType req, + IPvp2MetadataProvider metadataProvider) throws InvalidAssertionEncryptionException { + try { + final List<KeyInfoProvider> keyInfoProvider = new ArrayList<>(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + final KeyInfoCredentialResolver keyInfoCredentialResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + final PredicateRoleDescriptorResolver roleDescriptorResolver = new PredicateRoleDescriptorResolver( + metadataProvider); + roleDescriptorResolver.setRequireValidMetadata(true); + roleDescriptorResolver.initialize(); + + final MetadataCredentialResolver mdCredResolver = new MetadataCredentialResolver(); + mdCredResolver.setRoleDescriptorResolver(roleDescriptorResolver); + mdCredResolver.setKeyInfoCredentialResolver(keyInfoCredentialResolver); + mdCredResolver.initialize(); + + final CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new EntityIdCriterion(req.getIssuer().getValue())); + criteriaSet.add(new ProtocolCriterion(SAMLConstants.SAML20P_NS)); + criteriaSet.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME)); + criteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION)); + + return (X509Credential) mdCredResolver.resolveSingle(criteriaSet); + + } catch (final SecurityException | ComponentInitializationException | ResolverException e2) { + log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); + throw new InvalidAssertionEncryptionException(); + + } } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java index 922e7efe..b7b18f0f 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java @@ -24,6 +24,8 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import javax.naming.ConfigurationException; + import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.data.ILoALevelMapper; import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -86,17 +88,16 @@ public class Pvp2AssertionBuilder implements PvpConstants { @Autowired private ISubjectNameIdGenerator subjectNameIdGenerator; - /** * Build a PVP assertion as response for a SAML2 AttributeQuery request. * * @param issuerEntityID EnitiyID, which should be used for this IDP response - * @param attrQuery AttributeQuery request from Service-Provider - * @param attrList List of PVP response attributes - * @param now Current time - * @param validTo ValidTo time of the assertion - * @param qaaLevel QAA level of the authentication - * @param sessionIndex SAML2 SessionIndex, which should be included * + * @param attrQuery AttributeQuery request from Service-Provider + * @param attrList List of PVP response attributes + * @param now Current time + * @param validTo ValidTo time of the assertion + * @param qaaLevel QAA level of the authentication + * @param sessionIndex SAML2 SessionIndex, which should be included * * @return PVP 2.1 Assertion * @throws Pvp2Exception In case of an error */ @@ -119,18 +120,21 @@ public class Pvp2AssertionBuilder implements PvpConstants { validTo); } - /** * Build a PVP 2.1 assertion as response of a SAML2 AuthnRequest. * - * @param issuerEntityID EnitiyID, which should be used for this IDP response - * @param pendingReq Current processed pendingRequest DAO - * @param authnRequest Current processed PVP AuthnRequest - * @param authData AuthenticationData of the user, which is already authenticated - * @param peerEntity SAML2 EntityDescriptor of the service-provider, which receives the response - * @param date TimeStamp - * @param assertionConsumerService SAML2 endpoint of the service-provider, which should be used - * @param sloInformation Single LogOut information DAO + * @param issuerEntityID EnitiyID, which should be used for this IDP + * response + * @param pendingReq Current processed pendingRequest DAO + * @param authnRequest Current processed PVP AuthnRequest + * @param authData AuthenticationData of the user, which is + * already authenticated + * @param peerEntity SAML2 EntityDescriptor of the + * service-provider, which receives the response + * @param date TimeStamp + * @param assertionConsumerService SAML2 endpoint of the service-provider, which + * should be used + * @param sloInformation Single LogOut information DAO * @return PVP2 S-Profil Assertion * @throws Pvp2Exception In case of an error */ @@ -203,7 +207,6 @@ public class Pvp2AssertionBuilder implements PvpConstants { } } - // load SPSS decriptor from service-provider metadata final SPSSODescriptor spSsoDescriptor = peerEntity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); @@ -217,7 +220,7 @@ public class Pvp2AssertionBuilder implements PvpConstants { AttributeConsumingService attributeConsumingService = null; if (aIdx != null) { - idx = aIdx.intValue(); + idx = aIdx; attributeConsumingService = spSsoDescriptor.getAttributeConsumingServices().get(idx); } else { @@ -231,8 +234,8 @@ public class Pvp2AssertionBuilder implements PvpConstants { } /* - * TODO: maybe use first AttributeConsumingService if no is selected in request or on service - * is marked as default + * TODO: maybe use first AttributeConsumingService if no is selected in request + * or on service is marked as default * */ if (attributeConsumingService == null) { @@ -244,7 +247,6 @@ public class Pvp2AssertionBuilder implements PvpConstants { } - if (attributeConsumingService != null) { final Iterator<RequestedAttribute> it = attributeConsumingService.getRequestAttributes().iterator(); @@ -268,7 +270,6 @@ public class Pvp2AssertionBuilder implements PvpConstants { throw new UnprovideableAttributeException(reqAttribut.getName()); } - } catch (final Pvp2Exception e) { log.info("Attribute generation failed! for " + reqAttribut.getFriendlyName()); if (reqAttribut.isRequired()) { @@ -342,10 +343,10 @@ public class Pvp2AssertionBuilder implements PvpConstants { subjectNameID.setFormat(nameIdFormat); } - String sessionIndex = null; - // if request is a reauthentication and NameIDFormat match reuse old session information + // if request is a reauthentication and NameIDFormat match reuse old session + // information if (StringUtils.isNotEmpty(authData.getNameID()) && StringUtils.isNotEmpty(authData.getNameIdFormat()) && nameIdFormat.equals(authData.getNameIdFormat())) { @@ -368,7 +369,8 @@ public class Pvp2AssertionBuilder implements PvpConstants { // set 'recipient' attribute in subjectConformationData subjectConfirmationData.setRecipient(assertionConsumerService.getLocation()); - // set IP address of the user machine as 'Address' attribute in subjectConformationData + // set IP address of the user machine as 'Address' attribute in + // subjectConformationData final String usersIpAddress = pendingReq.getRawData(RequestImpl.DATAID_REQUESTER_IP_ADDRESS, String.class); if (StringUtils.isNotEmpty(usersIpAddress)) { @@ -388,15 +390,15 @@ public class Pvp2AssertionBuilder implements PvpConstants { /** * Build generic part of PVP S-Profile Assertion. * - * @param issuer IDP EntityID - * @param entityID Service Provider EntityID - * @param date Timestamp - * @param authnContextClassRef SAML2 AuthnContextClassReference - * @param attrList List of attributes - * @param subjectNameID SubjectNameId + * @param issuer IDP EntityID + * @param entityID Service Provider EntityID + * @param date Timestamp + * @param authnContextClassRef SAML2 AuthnContextClassReference + * @param attrList List of attributes + * @param subjectNameID SubjectNameId * @param subjectConfirmationData SubjectConfirmationInformation - * @param sessionIndex SessionIndex - * @param isValidTo ValidTo Timestamp + * @param sessionIndex SessionIndex + * @param isValidTo ValidTo Timestamp * @return PVP S-Profile Assertion * @throws ConfigurationException In case on an error */ diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/java/at/gv/egiz/eaaf/modules/pvp2/idp/test/AuthnResponseBuilderTest.java b/eaaf_modules/eaaf_module_pvp2_idp/src/test/java/at/gv/egiz/eaaf/modules/pvp2/idp/test/AuthnResponseBuilderTest.java new file mode 100644 index 00000000..98cf5f40 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/java/at/gv/egiz/eaaf/modules/pvp2/idp/test/AuthnResponseBuilderTest.java @@ -0,0 +1,102 @@ +package at.gv.egiz.eaaf.modules.pvp2.idp.test; + +import java.io.IOException; + +import javax.xml.transform.TransformerException; + +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyAuthConfig; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; +import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.AuthResponseBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.test.binding.PostBindingTest; + +import org.apache.commons.lang3.RandomStringUtils; +import org.joda.time.DateTime; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.RequestAbstractType; +import org.opensaml.saml.saml2.core.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.w3c.dom.Element; + +import net.shibboleth.utilities.java.support.xml.XMLParserException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({"/spring/test_eaaf_pvp.beans.xml"}) +@TestPropertySource( + locations = {"/config/config_1.props"}) +public class AuthnResponseBuilderTest { + + @Autowired private DummyAuthConfig authConfig; + @Autowired private PvpMetadataResolverFactory metadataResolverFactory; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void classInitializer() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + @Test + public void encryptedAssertion() throws InvalidAssertionEncryptionException, Pvp2MetadataException, + XMLParserException, UnmarshallingException, MarshallingException, TransformerException, IOException { + final String issuerEntityID = RandomStringUtils.randomAlphabetic(15); + + final IPvp2MetadataProvider metadataProvider = + metadataResolverFactory.createMetadataProvider( + "classpath:/data/pvp_metadata_junit_keystore.xml", null, "jUnit metadata resolver", null); + + final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + authnReq.setID("_" + RandomStringUtils.randomAlphanumeric(10)); + + final Assertion assertion = (Assertion) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/Assertion_1.xml")); + + //build response + final DateTime now = DateTime.now(); + final Response response = AuthResponseBuilder.buildResponse( + metadataProvider, issuerEntityID, authnReq, + now, assertion, authConfig); + + + //validate + Assert.assertNotNull("SAML2 response is null", response); + Assert.assertTrue("Assertion not null", response.getAssertions().isEmpty()); + Assert.assertNotNull("Enc. assertion is null", response.getEncryptedAssertions()); + Assert.assertFalse("Enc. assertion is empty", response.getEncryptedAssertions().isEmpty()); + Assert.assertEquals("# enc. assertions wrong", 1, response.getEncryptedAssertions().size()); + + Assert.assertEquals("InResponseTo", authnReq.getID(), response.getInResponseTo()); + Assert.assertEquals("Issuer EntityId", issuerEntityID, response.getIssuer().getValue()); + Assert.assertNotNull("ResponseId is null", response.getID()); + Assert.assertFalse("ResponseId is emptry", response.getID().isEmpty()); + + final Element responseElement = XMLObjectSupport.getMarshaller(response).marshall(response); + final String xmlResp = DomUtils.serializeNode(responseElement); + Assert.assertNotNull("XML response is null", xmlResp); + Assert.assertFalse("XML response is empty", xmlResp.isEmpty()); + + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_1.props b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_1.props new file mode 100644 index 00000000..6324f190 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_1.props @@ -0,0 +1,14 @@ +keystore.path=classpath:/data/junit.jks +keystore.pass=password +key.metadata.alias=meta +key.metadata.pass=password +key.sig.alias=sig +key.sig.pass=password +key.enc.alias= +key.enc.pass= + +pvp2.assertion.encryption.active=true + +client.http.connection.timeout.socket=2 +client.http.connection.timeout.connection=2 +client.http.connection.timeout.request=2
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/Assertion_1.xml b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/Assertion_1.xml new file mode 100644 index 00000000..7c45b5fa --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/Assertion_1.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> + <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_602c3236bffaf71ac3ac88674e76ff9f" IssueInstant="2014-03-05T06:39:51.017Z" Version="2.0"> + <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata</saml2:Issuer> + <saml2:Subject> + <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" NameQualifier="urn:publicid:gv.at:cdid+BF">QVGm48cqcM4UcyhDTNGYmVdrIoY=</saml2:NameID> + <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> + <saml2:SubjectConfirmationData InResponseTo="_aeebfae3ce681fe3ddcaf213a42f01d3" NotOnOrAfter="2014-03-05T06:44:51.017Z" Recipient="https://demo.egiz.gv.at/demoportal_demologin/securearea.action"/> + </saml2:SubjectConfirmation> + </saml2:Subject> + <saml2:Conditions NotBefore="2014-03-05T06:39:51.017Z" NotOnOrAfter="2014-03-05T06:44:51.017Z"> + <saml2:AudienceRestriction> + <saml2:Audience>https://demo.egiz.gv.at/demoportal_demologin/</saml2:Audience> + </saml2:AudienceRestriction> + </saml2:Conditions> + <saml2:AuthnStatement AuthnInstant="2014-03-05T06:39:51.017Z" SessionIndex="_c0c683509a8ff6ac372a9cf9c5c5a406"> + <saml2:AuthnContext> + <saml2:AuthnContextClassRef>http://www.stork.gov.eu/1.0/citizenQAALevel/4</saml2:AuthnContextClassRef> + </saml2:AuthnContext> + </saml2:AuthnStatement> + <saml2:AttributeStatement> + <saml2:Attribute FriendlyName="PVP-VERSION" Name="urn:oid:1.2.40.0.10.2.1.1.261.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">2.1</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="PRINCIPAL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.20" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Mustermann</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="GIVEN-NAME" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Max</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.55" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">1940-01-01</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="BPK" Name="urn:oid:1.2.40.0.10.2.1.1.149" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">BF:QVGm48cqcM4UcyhDTNGYmVdrIoY=</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="EID-CITIZEN-QAA-LEVEL" Name="urn:oid:1.2.40.0.10.2.1.1.261.94" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:integer">4</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="EID-ISSUING-NATION" Name="urn:oid:1.2.40.0.10.2.1.1.261.32" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">AT</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="EID-SECTOR-FOR-IDENTIFIER" Name="urn:oid:1.2.40.0.10.2.1.1.261.34" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">urn:publicid:gv.at:cdid+BF</saml2:AttributeValue> + </saml2:Attribute> + </saml2:AttributeStatement> + </saml2:Assertion> diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/AuthRequest_without_sig_1.xml b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/AuthRequest_without_sig_1.xml new file mode 100644 index 00000000..ef35ea92 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/AuthRequest_without_sig_1.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceIndex="1" AttributeConsumingServiceIndex="0" Destination="https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp2/post" ID="_aeebfae3ce681fe3ddcaf213a42f01d3" IssueInstant="2014-03-05T06:39:02.775Z" Version="2.0"> + <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://demo.egiz.gv.at/demoportal_demologin/</saml2:Issuer> + <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"> + <saml2:NameID>https://demo.egiz.gv.at/demoportal_demologin/</saml2:NameID> + </saml2:Subject> + <saml2p:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/> + <saml2p:RequestedAuthnContext> + <saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.stork.gov.eu/1.0/citizenQAALevel/4</saml2:AuthnContextClassRef> + </saml2p:RequestedAuthnContext> +</saml2p:AuthnRequest> diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/junit.jks b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/junit.jks Binary files differnew file mode 100644 index 00000000..b5262cb8 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/junit.jks diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/pvp_metadata_junit_keystore.xml b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/pvp_metadata_junit_keystore.xml new file mode 100644 index 00000000..52549a88 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/data/pvp_metadata_junit_keystore.xml @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="UTF-8"?> +<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_2e23ca9b2ba4dc9eef15187830d07ff0" entityID="https://demo.egiz.gv.at/demoportal_demologin/" validUntil="2020-02-05T06:41:42.966Z"> + <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:SignedInfo> + <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> + <ds:Reference URI="#_2e23ca9b2ba4dc9eef15187830d07ff0"> + <ds:Transforms> + <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + </ds:Transforms> + <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> + <ds:DigestValue>Jy/c0ZvVJSfWzSoAcxDx/o+T5W61vvNJNqTFz2o+ILc=</ds:DigestValue> + </ds:Reference> + </ds:SignedInfo> + <ds:SignatureValue>chMxIdwrPvr78j3oTtgS7udbydy9kye1bbeQ4jm2GeFKUfxvJqY+vt9MjVnWFeR4c16gd80BjZJ6xxD5i5Ifci3YtxeKSxq0ttH/xZYEhJZkD/0NrGUhSvNV9zuLAz3uGk/LJ+2JxRq7dbnW4n9MtGuYhea8OW9/Pr1xI1KyskQS76NZDsGjjfnFWbFXahLoQZULU4Ke3SfZVqLATTn0J34RZnjNH3QieY3LhRzOVu/I5yeZtnLgUS6dg0Gab9DA/pdNFaC632iaE5QCXJmhgpqkjbkayO9e8N93YGFjbszhU1Kws5OUGjXjfCZwezLeOUZoKEfo5c+4+zEaTrEQjg==</ds:SignatureValue> + <ds:KeyInfo> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </ds:Signature> + <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> + <md:KeyDescriptor use="signing"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIC+jCCAeKgAwIBAgIEXjF+fTANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJB +VDENMAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxETAPBgNVBAMMCE1ldGFk +YXRhMB4XDTIwMDEyOTEyNDU0OVoXDTI2MDEyODEyNDU0OVowPzELMAkGA1UEBhMC +QVQxDTALBgNVBAcMBEVHSVoxDjAMBgNVBAoMBWpVbml0MREwDwYDVQQDDAhNZXRh +ZGF0YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK230G3dxNbNlSYA +O5Kx/Js0aBAgxMt7q9m+dA35fK/dOvF/GjrqjWsMCnax+no9gLnq6x0gXiJclz6H +rp/YDOfLrJjMpNL/r0FWT947vbnEj7eT8TdY5d6Yi8AZulZmjiCI5nbZh2zwrP4+ +WqRroLoPhXQj8mDyp26M4xHBBUhLMRc2HV4S+XH4uNZ/vTmb8vBg31XGHCY33gl7 +/KA54JNGxJdN8Dxv6yHYsm91ZfVrX39W0iYLUNhUCkolwuQmjDVfrExM8BTLIONb +f+erJoCm3A9ghZyDYRQ/e69/UEUqDa6XOzykr88INkQscEiAXCDS+EBPMpKo+t3l +PIA9r7kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAh/2mg4S03bdZy1OVtEAudBT9 +YZb9OF34hxPtNbkB/V04wSIg1d4TBr5KDhV7CdiUOxPZzHpS8LUCgfGX306FB6NX +zh/b67uTOPaE72AB4VIT/Np0fsM7k5WhG9k9NoprIGiqCz2lXcfpZiT+LtSO1vWS +YI87wR9KOSWjcw/5i5qZIAJuwvLCQj5JtUsmrhHK75222J3TJf4dS/gfN4xfY2rW +9vcXtH6//8WdWp/zx9V7Z1ZsDb8TDKtBCEGuFDgVeU5ScKtVq8qRoUKD3Ve76cZi +purO3KrRrVAuZP2EfLkZdHEHqe8GPigNnZ5kTn8V2VJ3iRAQ73hpJRR98tFd0A==</ds:X509Certificate> + </ds:X509Data> + <ds:X509Data> + <ds:X509Certificate>MIIBbTCCARKgAwIBAgIEXjF+qTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +HhcNMjAwMTI5MTI0NjMzWhcNMjcwMTI4MTI0NjMzWjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASRt7gZRrr4rSEE7Q922oKQJF+mlkwC +LZnv8ZzHtH54s4VdyQFIBjQF1PPf9PTn+5tid8QJehZPndcoeD7J8fPJMAoGCCqG +SM49BAMCA0kAMEYCIQDFUO0owvqMVRO2FmD+vb8mqJBpWCE6Cl5pEHaygTa5LwIh +ANsmjI2azWiTSFjb7Ou5fnCfbeiJUP0s66m8qS4rYl9L + </ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:KeyDescriptor use="encryption"> + <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> + <ds:X509Data> + <ds:X509Certificate>MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc=</ds:X509Certificate> + </ds:X509Data> + </ds:KeyInfo> + </md:KeyDescriptor> + <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/post" index="0" isDefault="true"/> + <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/redirect" index="1"/> + <md:AttributeConsumingService index="0" isDefault="true"> + <md:ServiceName xml:lang="en">Default Service</md:ServiceName> + <md:RequestedAttribute FriendlyName="BPK" Name="urn:oid:1.2.40.0.10.2.1.1.149" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="PRINCIPAL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.20" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.55" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="PVP-VERSION" Name="urn:oid:1.2.40.0.10.2.1.1.261.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="EID-ISSUING-NATION" Name="urn:oid:1.2.40.0.10.2.1.1.261.32" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.76" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-FULL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.84" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="MANDATE-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.68" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN" Name="urn:oid:1.2.40.0.10.2.1.1.261.100" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="GIVEN-NAME" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="EID-SECTOR-FOR-IDENTIFIER" Name="urn:oid:1.2.40.0.10.2.1.1.261.34" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + <md:RequestedAttribute FriendlyName="MANDATE-TYPE-OID" Name="urn:oid:1.2.40.0.10.2.1.1.261.106" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="EID-IDENTITY-LINK" Name="urn:oid:1.2.40.0.10.2.1.1.261.38" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/> + <md:RequestedAttribute FriendlyName="EID-CITIZEN-QAA-EIDAS-LEVEL" Name="urn:oid:1.2.40.0.10.2.1.1.261.108" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/> + </md:AttributeConsumingService> + </md:SPSSODescriptor> + <md:Organization> + <md:OrganizationName xml:lang="de">EGIZ</md:OrganizationName> + <md:OrganizationDisplayName xml:lang="de">E-Government Innovationszentrum</md:OrganizationDisplayName> + <md:OrganizationURL xml:lang="de">http://www.egiz.gv.at</md:OrganizationURL> + </md:Organization> + <md:ContactPerson contactType="technical"> + <md:Company>E-Government Innovationszentrum</md:Company> + <md:GivenName>Lenz</md:GivenName> + <md:SurName>Thomas</md:SurName> + <md:EmailAddress>thomas.lenz@egiz.gv.at</md:EmailAddress> + <md:TelephoneNumber>+43 316 873 5525</md:TelephoneNumber> + </md:ContactPerson> +</md:EntityDescriptor> diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_core.beans.xml b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_core.beans.xml new file mode 100644 index 00000000..375224bb --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_core.beans.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:aop="http://www.springframework.org/schema/aop" + xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> + + <bean id="dummyAuthConfig" + class="at.gv.egiz.eaaf.core.impl.idp.module.test.DummyAuthConfig" /> + + <bean id="dummyVelocityGuiBuilder" + class="at.gv.egiz.eaaf.core.impl.idp.module.gui.DummyVelocityGuiFormBuilder" /> + + <bean id="dummyGuiBuilderConfigFactory" + class="at.gv.egiz.eaaf.core.impl.idp.module.gui.DummyGuiBuilderConfigurationFactory" /> + + <bean id="httpClientFactory" + class="at.gv.egiz.eaaf.core.impl.utils.HttpClientFactory" /> + +</beans>
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_pvp.beans.xml b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_pvp.beans.xml new file mode 100644 index 00000000..aac94041 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_pvp.beans.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:aop="http://www.springframework.org/schema/aop" + xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> + + <import resource="test_eaaf_core.beans.xml"/> + <import resource="classpath:/eaaf_pvp.beans.xml"/> + + <bean id="dummyCredentialProvider" + class="at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider" /> + + +</beans>
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_sp/pom.xml b/eaaf_modules/eaaf_module_pvp2_sp/pom.xml index 51219563..5b16a151 100644 --- a/eaaf_modules/eaaf_module_pvp2_sp/pom.xml +++ b/eaaf_modules/eaaf_module_pvp2_sp/pom.xml @@ -54,21 +54,20 @@ </plugin> <!-- enable co-existence of testng and junit --> - <plugin> - <artifactId>maven-surefire-plugin</artifactId> - <version>${surefire.version}</version> - <configuration> - <threadCount>1</threadCount> - <argLine>--add-modules java.xml.bind</argLine> - </configuration> - <dependencies> - <dependency> - <groupId>org.apache.maven.surefire</groupId> - <artifactId>surefire-junit47</artifactId> - <version>${surefire.version}</version> - </dependency> - </dependencies> - </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>${surefire.version}</version> + <configuration> + <threadCount>1</threadCount> + </configuration> + <dependencies> + <dependency> + <groupId>org.apache.maven.surefire</groupId> + <artifactId>surefire-junit47</artifactId> + <version>${surefire.version}</version> + </dependency> + </dependencies> + </plugin> </plugins> </build> @@ -470,7 +470,13 @@ <scope>test</scope> <type>test-jar</type> </dependency> - + <dependency> + <groupId>at.gv.egiz.eaaf</groupId> + <artifactId>eaaf_module_pvp2_core</artifactId> + <version>${egiz.eaaf.version}</version> + <scope>test</scope> + <type>test-jar</type> + </dependency> </dependencies> </dependencyManagement> <dependencies> @@ -498,6 +504,21 @@ <version>2.7</version> </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>${surefire.version}</version> + <configuration> + <threadCount>1</threadCount> + </configuration> + <dependencies> + <dependency> + <groupId>org.apache.maven.surefire</groupId> + <artifactId>surefire-junit47</artifactId> + <version>${surefire.version}</version> + </dependency> + </dependencies> + </plugin> + <!-- Code quality checks --> <plugin> <groupId>org.apache.maven.plugins</groupId> |