diff options
author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-01-31 20:41:54 +0100 |
---|---|---|
committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-01-31 20:41:54 +0100 |
commit | d41afe91ee59daf6b5f5037cecac52900fe2ccb2 (patch) | |
tree | 3a19e1818d276d701574758ce6166b2f3a7e2030 /eaaf_modules/eaaf_module_pvp2_core | |
parent | 0cf9926282ba4aa46bad3f4e8020cec72683492f (diff) | |
download | EAAF-Components-d41afe91ee59daf6b5f5037cecac52900fe2ccb2.tar.gz EAAF-Components-d41afe91ee59daf6b5f5037cecac52900fe2ccb2.tar.bz2 EAAF-Components-d41afe91ee59daf6b5f5037cecac52900fe2ccb2.zip |
a lot of more OpenSAML3 refactoring staff
This version is also NOT stable!
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_core')
67 files changed, 3228 insertions, 1220 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_core/pom.xml b/eaaf_modules/eaaf_module_pvp2_core/pom.xml index abf2ebe5..62973ac5 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/pom.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/pom.xml @@ -49,10 +49,6 @@ </dependency> <dependency> - <groupId>org.owasp.esapi</groupId> - <artifactId>esapi</artifactId> - </dependency> - <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <scope>provided</scope> @@ -64,6 +60,18 @@ <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> + </dependencies> <build> 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 979a61d5..b1ac8e75 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 @@ -28,19 +28,33 @@ import javax.xml.namespace.QName; import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; import at.gv.egiz.eaaf.core.impl.data.Triple; +import org.apache.xml.security.algorithms.MessageDigestAlgorithm; +import org.apache.xml.security.signature.XMLSignature; import org.opensaml.xmlsec.encryption.support.EncryptionConstants; import org.opensaml.xmlsec.signature.support.SignatureConstants; +import com.google.common.collect.ImmutableMap; + public interface PvpConstants extends PvpAttributeDefinitions { + //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 DEFAULT_SIGNING_METHODE = + //Default values + String DEFAULT_SIGNING_METHODE_RSA = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256; + String DEFAULT_SIGNING_METHODE_EC = + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256; + 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_KEYTRANSPORT_RSAOAEP; + + //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"; @@ -136,4 +150,21 @@ public interface PvpConstants extends PvpAttributeDefinitions { QName EIDAS_REQUESTED_ATTRIBUTE_VALUE_TYPE = new QName(EIDAT10_SAML_NS, "AttributeValue", EIDAT10_PREFIX); + 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(); + } 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 57dd63bf..e8da499c 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 @@ -23,18 +23,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 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 org.opensaml.messaging.decoder.MessageDecodingException; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.security.SecurityException; - import net.shibboleth.utilities.java.support.net.URIComparator; public interface IDecoder { InboundMessageInterface decode(HttpServletRequest req, HttpServletResponse resp, - MetadataProvider metadataProvider, boolean isSpEndPoint, URIComparator comparator) - throws MessageDecodingException, SecurityException, Pvp2Exception; + IPvp2MetadataProvider metadataProvider, boolean isSpEndPoint, 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 01f541a9..691d6574 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 @@ -23,13 +23,12 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; -import org.opensaml.messaging.encoder.MessageEncodingException; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.StatusResponseType; import org.opensaml.security.SecurityException; -import org.opensaml.security.credential.Credential; public interface IEncoder { @@ -44,13 +43,11 @@ public interface IEncoder { * @param credentials Credential to sign the request object * @param pendingReq Internal MOA-ID request object that contains * session-state informations but never null - * @throws MessageEncodingException In case of an error - * @throws SecurityException In case of an error - * @throws Pvp2Exception In case of an error + * @throws Pvp2Exception In case of an error */ void encodeRequest(HttpServletRequest req, HttpServletResponse resp, - RequestAbstractType request, String targetLocation, String relayState, Credential credentials, - IRequest pendingReq) throws MessageEncodingException, SecurityException, Pvp2Exception; + RequestAbstractType request, String targetLocation, String relayState, EaafX509Credential credentials, + IRequest pendingReq) throws Pvp2Exception; /** * Encoder SAML Response. @@ -63,10 +60,9 @@ 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 MessageEncodingException In case of an error * @throws SecurityException In case of an error */ - void encodeRespone(HttpServletRequest req, HttpServletResponse resp, - StatusResponseType response, String targetLocation, String relayState, Credential credentials, - IRequest pendingReq) throws MessageEncodingException, SecurityException, Pvp2Exception; + void encodeResponse(HttpServletRequest req, HttpServletResponse resp, + StatusResponseType response, String targetLocation, String relayState, EaafX509Credential credentials, + IRequest pendingReq) throws Pvp2Exception; } 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 new file mode 100644 index 00000000..568b617d --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java @@ -0,0 +1,25 @@ +package at.gv.egiz.eaaf.modules.pvp2.api.credential; + +import javax.annotation.Nonnull; + +import org.opensaml.security.x509.X509Credential; + + +public interface EaafX509Credential extends X509Credential { + + /** + * Get the signature algorithm that has to be used with this credential. + * + * @return Signature-algorithm identifier + */ + @Nonnull + String getSignatureAlgorithmForSigning(); + + /** + * Set the signature algorithm that has to be used with this credential. + * + * @param sigAlg Signature-algorithm identifier + */ + void setSignatureAlgorithmForSigning(@Nonnull String sigAlg); + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvp2MetadataProvider.java index 25b2d250..e2ee0c9d 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvp2MetadataProvider.java @@ -23,42 +23,29 @@ import java.util.List; import javax.xml.namespace.QName; -import org.opensaml.saml2.metadata.EntitiesDescriptor; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.RoleDescriptor; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.saml2.metadata.provider.MetadataProviderException; -import org.opensaml.xml.XMLObject; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; -public interface IPvpMetadataProvider extends MetadataProvider { +import org.opensaml.core.xml.XMLObject; +import org.opensaml.saml.metadata.resolver.MetadataResolver; +import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.RoleDescriptor; - @Override - boolean requireValidMetadata(); +public interface IPvp2MetadataProvider extends MetadataResolver { - @Override - void setRequireValidMetadata(boolean requireValidMetadata); + XMLObject getMetadata() throws Pvp2MetadataException; - @Override - MetadataFilter getMetadataFilter(); - @Override - void setMetadataFilter(MetadataFilter newFilter) throws MetadataProviderException; + EntitiesDescriptor getEntitiesDescriptor(String entitiesID) throws Pvp2MetadataException; - @Override - XMLObject getMetadata() throws MetadataProviderException; - @Override - EntitiesDescriptor getEntitiesDescriptor(String entitiesID) throws MetadataProviderException; + EntityDescriptor getEntityDescriptor(String entityID) throws Pvp2MetadataException; - @Override - EntityDescriptor getEntityDescriptor(String entityID) throws MetadataProviderException; - @Override - List<RoleDescriptor> getRole(String entityID, QName roleName) throws MetadataProviderException; + List<RoleDescriptor> getRole(String entityID, QName roleName) throws Pvp2MetadataException; + - @Override RoleDescriptor getRole(String entityID, QName roleName, String supportedProtocol) - throws MetadataProviderException; + throws Pvp2MetadataException; } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlBindingException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlBindingException.java new file mode 100644 index 00000000..9f079584 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlBindingException.java @@ -0,0 +1,12 @@ +package at.gv.egiz.eaaf.modules.pvp2.exception; + +public class SamlBindingException extends Pvp2Exception { + + private static final long serialVersionUID = 7122051055002687486L; + + public SamlBindingException(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/SamlSigningException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlSigningException.java new file mode 100644 index 00000000..e1a5a9d9 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlSigningException.java @@ -0,0 +1,17 @@ +package at.gv.egiz.eaaf.modules.pvp2.exception; + +public class SamlSigningException extends Pvp2Exception { + + private static final long serialVersionUID = 1L; + + public SamlSigningException(String messageId, Object[] parameters, Throwable wrapped) { + super(messageId, parameters, wrapped); + + } + + public SamlSigningException(String messageId, Object[] parameters) { + super(messageId, parameters); + + } + +} 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 new file mode 100644 index 00000000..ae108c35 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java @@ -0,0 +1,108 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.binding; + +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.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; + +import org.opensaml.core.config.ConfigurationService; +import org.opensaml.messaging.context.BaseContext; +import org.opensaml.messaging.context.MessageContext; +import org.opensaml.saml.common.SAMLObject; +import org.opensaml.saml.common.SignableSAMLObject; +import org.opensaml.saml.common.binding.SAMLBindingSupport; +import org.opensaml.saml.common.binding.encoding.SAMLMessageEncoder; +import org.opensaml.saml.common.messaging.context.SAMLEndpointContext; +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.metadata.SingleSignOnService; +import org.opensaml.saml.saml2.metadata.impl.SingleSignOnServiceBuilder; +import org.opensaml.xmlsec.SignatureSigningParameters; +import org.opensaml.xmlsec.SignatureValidationConfiguration; +import org.opensaml.xmlsec.SignatureValidationParameters; +import org.opensaml.xmlsec.context.SecurityParametersContext; +import org.opensaml.xmlsec.signature.support.SignatureConstants; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Abstract Binding implements common code for SAML2 binding implementations. + * + * @author tlenz + * + */ +public abstract class AbstractBinding { + + @Autowired protected IConfiguration basicConfig; + + public abstract String getSaml2BindingName(); + + protected MessageContext<SAMLObject> buildBasicMessageContext( + SAMLMessageEncoder encoder, SignableSAMLObject response) { + final MessageContext<SAMLObject> messageContext = new MessageContext<SAMLObject>(); + messageContext.setMessage(response); + encoder.setMessageContext(messageContext); + return messageContext; + + } + + protected BaseContext injectSigningInfos(EaafX509Credential credentials) throws SamlSigningException { + final SecurityParametersContext securityParamContext = new SecurityParametersContext(); + final SignatureSigningParameters signingParams = new SignatureSigningParameters(); + securityParamContext.setSignatureSigningParameters(signingParams); + + signingParams.setSigningCredential(credentials); + signingParams.setSignatureCanonicalizationAlgorithm( + SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signingParams.setSignatureReferenceCanonicalizationAlgorithm( + SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signingParams.setSignatureAlgorithm(credentials.getSignatureAlgorithmForSigning()); + signingParams.setSignatureReferenceDigestMethod( + Saml2Utils.getDigestAlgorithm(signingParams.getSignatureAlgorithm())); + + signingParams.setKeyInfoGenerator(Saml2Utils.getKeyInfoGenerator(credentials, false)); + + return securityParamContext; + + } + + protected BaseContext injectEndpointInfos(final SignableSAMLObject response, String targetLocation) { + SAMLBindingSupport.setSAML2Destination(response, targetLocation); + final SingleSignOnService service = new SingleSignOnServiceBuilder().buildObject(); + service.setBinding(getSaml2BindingName()); + service.setLocation(targetLocation); + final SAMLPeerEntityContext peerEntityContext = new SAMLPeerEntityContext(); + final SAMLEndpointContext endpointContext = new SAMLEndpointContext(); + endpointContext.setEndpoint(service); + peerEntityContext.addSubcontext(endpointContext); + return peerEntityContext; + + } + + protected void injectInboundMessageContexts(MessageContext<SAMLObject> messageContext, + IPvp2MetadataProvider metadataProvider) { + messageContext.addSubcontext(new SAMLPeerEntityContext()); + 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); + messageContext.addSubcontext(securityParameterContext); + + sigValParameters.setBlacklistedAlgorithms( + ConfigurationService.get(SignatureValidationConfiguration.class) + .getBlacklistedAlgorithms()); + sigValParameters.setSignatureTrustEngine( + TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); + + } +} 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 251f6081..6f39392d 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 @@ -27,48 +27,37 @@ import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfigurationFactory; import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiBuilderConfiguration; import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiFormBuilder; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.impl.gui.velocity.VelocityProvider; import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; import at.gv.egiz.eaaf.modules.pvp2.api.binding.IDecoder; 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.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.opensaml.initialize.EaafDefaultSaml2Bootstrap; -import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; -import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSignedRequestPolicyRule; -import org.apache.commons.lang3.StringUtils; -import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.messaging.context.MessageContext; import org.opensaml.messaging.decoder.MessageDecodingException; -import org.opensaml.messaging.encoder.MessageEncodingException; import org.opensaml.saml.common.SAMLObject; +import org.opensaml.saml.common.binding.SAMLBindingSupport; +import org.opensaml.saml.common.messaging.SAMLMessageSecuritySupport; import org.opensaml.saml.common.xml.SAMLConstants; -import org.opensaml.saml.saml2.binding.decoding.impl.HTTPPostDecoder; +import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.StatusResponseType; -import org.opensaml.saml.saml2.metadata.IDPSSODescriptor; -import org.opensaml.saml.saml2.metadata.SPSSODescriptor; -import org.opensaml.saml.saml2.metadata.SingleSignOnService; -import org.opensaml.saml.saml2.metadata.impl.SingleSignOnServiceBuilder; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.security.credential.Credential; -import org.opensaml.ws.security.SecurityPolicyResolver; -import org.opensaml.ws.security.provider.BasicSecurityPolicy; -import org.opensaml.ws.security.provider.StaticSecurityPolicyResolver; -import org.opensaml.ws.transport.http.HttpServletRequestAdapter; -import org.opensaml.ws.transport.http.HttpServletResponseAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.net.URIComparator; -@Service("PVPPOSTBinding") -public class PostBinding implements IDecoder, IEncoder { - private static final Logger log = LoggerFactory.getLogger(PostBinding.class); +@Slf4j +public class PostBinding extends AbstractBinding implements IDecoder, IEncoder { @Autowired(required = true) IConfiguration authConfig; @@ -78,152 +67,160 @@ public class PostBinding implements IDecoder, IEncoder { IGuiBuilderConfigurationFactory guiConfigFactory; @Override - public void encodeRequest(final HttpServletRequest req, final HttpServletResponse resp, + public void encodeRequest(final HttpServletRequest httpReq, final HttpServletResponse httpResp, final RequestAbstractType request, final String targetLocation, final String relayState, - final Credential credentials, final IRequest pendingReq) - throws MessageEncodingException, SecurityException { + final EaafX509Credential credentials, final IRequest pendingReq) + throws Pvp2Exception { try { - // load default PVP security configurations - EaafDefaultSaml2Bootstrap.initializeDefaultPvpConfiguration(); - // initialize POST binding encoder with template decoration final IVelocityGuiBuilderConfiguration guiConfig = guiConfigFactory.getSpSpecificSaml2PostConfiguration(pendingReq, "pvp_postbinding_template.html", authConfig.getConfigurationRootDirectory()); - final HttpPostEncoderWithOwnTemplate encoder = new HttpPostEncoderWithOwnTemplate(guiConfig, - guiBuilder, VelocityProvider.getClassPathVelocityEngine()); + final HttpPostEncoderWithOwnTemplate encoder + = new HttpPostEncoderWithOwnTemplate(guiConfig, guiBuilder); + + encoder.setHttpServletResponse(httpResp); + + //inject message context + final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, request); + + //inject signing context + messageContext.addSubcontext(injectSigningInfos(credentials)); - // set OpenSAML2 process parameter into binding context dao - final HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(resp, true); - final BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = - new BasicSAMLMessageContext<>(); - final SingleSignOnService service = new SingleSignOnServiceBuilder().buildObject(); - service.setBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"); - service.setLocation(targetLocation); + //set endpoint url + messageContext.addSubcontext(injectEndpointInfos(request, targetLocation)); - context.setOutboundSAMLMessageSigningCredential(credentials); - context.setPeerEntityEndpoint(service); - context.setOutboundSAMLMessage(request); - context.setOutboundMessageTransport(responseAdapter); - context.setRelayState(relayState); - encoder.encode(context); + //set relayState of exists + SAMLBindingSupport.setRelayState(messageContext, relayState); + + //sign SAML2 message + SAMLMessageSecuritySupport.signMessage(messageContext); + + //encode message + encoder.initialize(); + encoder.encode(); } catch (final Exception e) { - log.warn("Can not encode SAML2 request", e); - throw new SecurityException(e); + log.warn("Can not encode SAML2 Post-Binding request", e); + throw new SamlBindingException("internal.pvp.95", + new Object[] {PvpConstants.POST, "encoding", e.getMessage()}, + e); } } @Override - public void encodeRespone(final HttpServletRequest req, final HttpServletResponse resp, + public void encodeResponse(final HttpServletRequest httpReq, final HttpServletResponse httpResp, final StatusResponseType response, final String targetLocation, final String relayState, - final Credential credentials, final IRequest pendingReq) - throws MessageEncodingException, SecurityException { + final EaafX509Credential credentials, final IRequest pendingReq) + throws Pvp2Exception { try { - // load default PVP security configurations - EaafDefaultSaml2Bootstrap.initializeDefaultPvpConfiguration(); - log.debug("create SAML POSTBinding response"); // initialize POST binding encoder with template decoration final IVelocityGuiBuilderConfiguration guiConfig = guiConfigFactory.getSpSpecificSaml2PostConfiguration(pendingReq, "pvp_postbinding_template.html", authConfig.getConfigurationRootDirectory()); - final HttpPostEncoderWithOwnTemplate encoder = new HttpPostEncoderWithOwnTemplate(guiConfig, - guiBuilder, VelocityProvider.getClassPathVelocityEngine()); - - // set OpenSAML2 process parameter into binding context dao - final HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(resp, true); - final BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = - new BasicSAMLMessageContext<>(); - final SingleSignOnService service = new SingleSignOnServiceBuilder().buildObject(); - service.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); - service.setLocation(targetLocation); - context.setOutboundSAMLMessageSigningCredential(credentials); - context.setPeerEntityEndpoint(service); - // context.setOutboundMessage(authReq); - context.setOutboundSAMLMessage(response); - context.setOutboundMessageTransport(responseAdapter); - context.setRelayState(relayState); - - encoder.encode(context); + final HttpPostEncoderWithOwnTemplate encoder = + new HttpPostEncoderWithOwnTemplate(guiConfig, guiBuilder); + + encoder.setHttpServletResponse(httpResp); + + //inject message context + final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, response); + + //inject signing context + messageContext.addSubcontext(injectSigningInfos(credentials)); + + //set endpoint url + messageContext.addSubcontext(injectEndpointInfos(response, targetLocation)); + + //set relayState of exists + SAMLBindingSupport.setRelayState(messageContext, relayState); + + //sign SAML2 message + SAMLMessageSecuritySupport.signMessage(messageContext); + + //encode message + encoder.initialize(); + encoder.encode(); } catch (final Exception e) { - log.warn("Can not encode SAML2 response", e); - throw new SecurityException(e); + log.warn("Can not encode SAML2 Post-Binding response", e); + throw new SamlBindingException("internal.pvp.95", + new Object[] {PvpConstants.POST, "encoding", e.getMessage()}, + e); } } + + + + @Override public InboundMessageInterface decode(final HttpServletRequest req, - final HttpServletResponse resp, final MetadataProvider metadataProvider, + final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider, final boolean isSpEndPoint, final URIComparator comparator) - throws MessageDecodingException, SecurityException { + throws Pvp2Exception { - final HTTPPostDecoder decode = new HTTPPostDecoder(); + //TODO: check, if we should re-implement HTTPPostDecoder to collect the last http parameter!!! + final EaafHttpPostDecoder decode = new EaafHttpPostDecoder(); decode.setHttpServletRequest(req); - 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); + //decode request + try { + decode.initialize(); + decode.decode(); - } else { - messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); - decode.setURIComparator(comparator); + } catch (MessageDecodingException | ComponentInitializationException e) { + throw new SamlBindingException("internal.pvp.95", + new Object[] {PvpConstants.POST, "decoding", e.getMessage()}, + e); } - messageContext.setMetadataProvider(metadataProvider); + final MessageContext<SAMLObject> messageContext = decode.getMessageContext(); + + if (SAMLBindingSupport.isSigningCapableBinding(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); + + + //TODO: add sig validation!!! - // set security policy context - final BasicSecurityPolicy policy = new BasicSecurityPolicy(); - policy.getPolicyRules() - .add(new PvpSignedRequestPolicyRule(metadataProvider, - TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider), - messageContext.getPeerEntityRole())); - final SecurityPolicyResolver secResolver = new StaticSecurityPolicyResolver(policy); - messageContext.setSecurityPolicyResolver(secResolver); - decode.decode(messageContext); InboundMessage msg = null; - if (messageContext.getInboundMessage() instanceof RequestAbstractType) { + + if (messageContext.getMessage() instanceof RequestAbstractType) { final RequestAbstractType inboundMessage = - (RequestAbstractType) messageContext.getInboundMessage(); + (RequestAbstractType) messageContext.getMessage(); msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName()); msg.setEntityID(inboundMessage.getIssuer().getValue()); - } else if (messageContext.getInboundMessage() instanceof StatusResponseType) { + } else if (messageContext.getMessage() instanceof StatusResponseType) { final StatusResponseType inboundMessage = - (StatusResponseType) messageContext.getInboundMessage(); + (StatusResponseType) messageContext.getMessage(); msg = new PvpSProfileResponse(inboundMessage); msg.setEntityID(inboundMessage.getIssuer().getValue()); } else { // create empty container if request type is unknown msg = new InboundMessage(); - } - if (messageContext.getPeerEntityMetadata() != null) { - msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID()); - } else { - if (StringUtils.isEmpty(msg.getEntityID())) { - log.info( - "No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer()); - } } - msg.setVerified(true); - msg.setRelayState(messageContext.getRelayState()); + msg.setVerified(false); + msg.setRelayState(SAMLBindingSupport.getRelayState(messageContext)); return msg; } @@ -231,6 +228,7 @@ public class PostBinding implements IDecoder, IEncoder { @Override public boolean handleDecode(final String action, final HttpServletRequest req) { return req.getMethod().equals("POST") && action.equals(PvpConstants.POST); + } @Override 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 559ee3b8..5f74053d 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 @@ -26,211 +26,315 @@ import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; import at.gv.egiz.eaaf.modules.pvp2.api.binding.IDecoder; 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.IRefreshableMetadataProvider; +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.initialize.EaafDefaultSaml2Bootstrap; -import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; -import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpAuthRequestSignedRole; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.EaafHttpRedirectDeflateDecoder; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain; -import org.apache.commons.lang3.StringUtils; -import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.messaging.context.MessageContext; import org.opensaml.messaging.decoder.MessageDecodingException; -import org.opensaml.messaging.encoder.MessageEncodingException; +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; +import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHandler; +import org.opensaml.saml.common.messaging.context.SAMLBindingContext; import org.opensaml.saml.common.xml.SAMLConstants; -import org.opensaml.saml.saml2.binding.decoding.impl.HTTPRedirectDeflateDecoder; 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.opensaml.saml.saml2.metadata.IDPSSODescriptor; -import org.opensaml.saml.saml2.metadata.SPSSODescriptor; -import org.opensaml.saml.saml2.metadata.SingleSignOnService; -import org.opensaml.saml.saml2.metadata.impl.SingleSignOnServiceBuilder; -import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.security.credential.Credential; -import org.opensaml.ws.security.SecurityPolicyResolver; -import org.opensaml.ws.security.provider.BasicSecurityPolicy; -import org.opensaml.ws.security.provider.StaticSecurityPolicyResolver; -import org.opensaml.ws.transport.http.HttpServletRequestAdapter; -import org.opensaml.ws.transport.http.HttpServletResponseAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.net.URIComparator; -import net.shibboleth.utilities.java.support.xml.BasicParserPool; -@Service("PVPRedirectBinding") -public class RedirectBinding implements IDecoder, IEncoder { +public class RedirectBinding extends AbstractBinding implements IDecoder, IEncoder { private static final Logger log = LoggerFactory.getLogger(RedirectBinding.class); @Override public void encodeRequest(final HttpServletRequest req, final HttpServletResponse resp, final RequestAbstractType request, final String targetLocation, final String relayState, - final Credential credentials, final IRequest pendingReq) - throws MessageEncodingException, SecurityException { - - // load default PVP security configurations - EaafDefaultSaml2Bootstrap.initializeDefaultPvpConfiguration(); - - log.debug("create SAML RedirectBinding response"); - - final HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); - final HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(resp, true); - final BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = - new BasicSAMLMessageContext<>(); - final SingleSignOnService service = new SingleSignOnServiceBuilder().buildObject(); - service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); - service.setLocation(targetLocation); - context.setOutboundSAMLMessageSigningCredential(credentials); - context.setPeerEntityEndpoint(service); - context.setOutboundSAMLMessage(request); - context.setOutboundMessageTransport(responseAdapter); - context.setRelayState(relayState); - - encoder.encode(context); + final EaafX509Credential credentials, final IRequest pendingReq) + throws Pvp2Exception { + + try { + log.debug("create SAML RedirectBinding response"); + final HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); + encoder.setHttpServletResponse(resp); + + final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, request); + + // set endpoint url + messageContext.addSubcontext(injectEndpointInfos(request, targetLocation)); + + // inject signing context + messageContext.addSubcontext(injectSigningInfos(credentials)); + + // set relayState of exists + SAMLBindingSupport.setRelayState(messageContext, relayState); + + // encode message + encoder.initialize(); + encoder.encode(); + + } catch (final Exception e) { + log.warn("Can not encode SAML2 Redirect-Binding request", e); + throw new SamlBindingException("internal.pvp.95", + new Object[] { PvpConstants.REDIRECT, "encoding", e.getMessage() }, + e); + + } + } @Override - public void encodeRespone(final HttpServletRequest req, final HttpServletResponse resp, + public void encodeResponse(final HttpServletRequest req, final HttpServletResponse resp, final StatusResponseType response, final String targetLocation, final String relayState, - final Credential credentials, final IRequest pendingReq) - throws MessageEncodingException, SecurityException { + final EaafX509Credential credentials, final IRequest pendingReq) + throws Pvp2Exception { + + try { + log.debug("create SAML RedirectBinding response"); + + final HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); + encoder.setHttpServletResponse(resp); + + final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, response); + + // set endpoint url + messageContext.addSubcontext(injectEndpointInfos(response, targetLocation)); - // load default PVP security configurations - EaafDefaultSaml2Bootstrap.initializeDefaultPvpConfiguration(); + // inject signing context + messageContext.addSubcontext(injectSigningInfos(credentials)); - log.debug("create SAML RedirectBinding response"); + // set relayState of exists + SAMLBindingSupport.setRelayState(messageContext, relayState); - final HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); - final HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(resp, true); - final BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = - new BasicSAMLMessageContext<>(); - final SingleSignOnService service = new SingleSignOnServiceBuilder().buildObject(); - service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); - service.setLocation(targetLocation); - context.setOutboundSAMLMessageSigningCredential(credentials); - context.setPeerEntityEndpoint(service); - context.setOutboundSAMLMessage(response); - context.setOutboundMessageTransport(responseAdapter); - context.setRelayState(relayState); + // encode message + encoder.initialize(); + encoder.encode(); - encoder.encode(context); + } catch (final Exception e) { + log.warn("Can not encode SAML2 Redirect-Binding request", e); + throw new SamlBindingException("internal.pvp.95", + new Object[] { PvpConstants.REDIRECT, "encoding", e.getMessage() }, + e); + + } } @Override public InboundMessageInterface decode(final HttpServletRequest req, - final HttpServletResponse resp, final MetadataProvider metadataProvider, + final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider, final boolean isSpEndPoint, final URIComparator comparator) - throws MessageDecodingException, SecurityException { - - final HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder(new BasicParserPool()); - - final BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = - new BasicSAMLMessageContext<>(); - messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(req)); + throws Pvp2Exception { - // set metadata descriptor type - if (isSpEndPoint) { - messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); - decode.setURIComparator(comparator); + // TODO: implement one flat decoder to get SAML2 request/response parametes as + // same as in SAML2HTTPRedirectDeflateSignatureSecurityHandler + final EaafHttpRedirectDeflateDecoder decode = new EaafHttpRedirectDeflateDecoder(); + decode.setHttpServletRequest(req); - } else { - messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); - decode.setURIComparator(comparator); - } + // decode request + try { + decode.initialize(); + decode.decode(); - 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); + } catch (MessageDecodingException | ComponentInitializationException e) { + throw new SamlBindingException("internal.pvp.95", + new Object[] { PvpConstants.REDIRECT, "decoding", e.getMessage() }, + e); } - try { - decode.decode(messageContext); - - // check signature - signatureRule.evaluate(messageContext); + final MessageContext<SAMLObject> messageContext = decode.getMessageContext(); - } catch (final SecurityException e) { - if (StringUtils.isEmpty(messageContext.getInboundMessageIssuer())) { - throw e; + final SAMLBindingContext bindingContext = messageContext.getSubcontext(SAMLBindingContext.class, true); + if (!bindingContext.hasBindingSignature()) { + log.info("SAML Redirect-Binding message contains no signature. Message will be rejected"); + throw new InvalidPvpRequestException("internal.pvp.02", null); - } + } - 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); + //inject informations into message context that are required for further processing + injectInboundMessageContexts(messageContext, 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); - // check signature - signatureRule.evaluate(messageContext); - } - log.trace("Second PVP2X message validation finished"); + try { + messageValidatorChain.initialize(); + messageValidatorChain.invoke(messageContext); - } else { - throw e; + } 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.getInboundMessage() instanceof RequestAbstractType) { + + if (messageContext.getMessage() instanceof RequestAbstractType) { final RequestAbstractType inboundMessage = - (RequestAbstractType) messageContext.getInboundMessage(); + (RequestAbstractType) messageContext.getMessage(); msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName()); + msg.setEntityID(inboundMessage.getIssuer().getValue()); - } else if (messageContext.getInboundMessage() instanceof StatusResponseType) { + } else if (messageContext.getMessage() instanceof StatusResponseType) { final StatusResponseType inboundMessage = - (StatusResponseType) messageContext.getInboundMessage(); + (StatusResponseType) messageContext.getMessage(); msg = new PvpSProfileResponse(inboundMessage); + msg.setEntityID(inboundMessage.getIssuer().getValue()); } 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()); + 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 public boolean handleDecode(final String action, final HttpServletRequest req) { - return action.equals(PvpConstants.REDIRECT) || action.equals(PvpConstants.SINGLELOGOUT) + return (action.equals(PvpConstants.REDIRECT) || action.equals(PvpConstants.SINGLELOGOUT)) && req.getMethod().equals("GET"); } 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 04266d37..e0df2d2a 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 @@ -19,8 +19,6 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.binding; -import java.util.List; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -28,99 +26,105 @@ import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; import at.gv.egiz.eaaf.modules.pvp2.api.binding.IDecoder; 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.Pvp2Exception; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafDefaultSaml2Bootstrap; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafMessageContextInitializationHandler; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain; -import org.apache.commons.lang3.StringUtils; -import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.messaging.context.MessageContext; import org.opensaml.messaging.decoder.MessageDecodingException; -import org.opensaml.messaging.encoder.MessageEncodingException; 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.saml.saml2.metadata.SPSSODescriptor; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.security.credential.Credential; -import org.opensaml.soap.soap11.Envelope; -import org.opensaml.ws.transport.http.HttpServletRequestAdapter; -import org.opensaml.ws.transport.http.HttpServletResponseAdapter; -import org.opensaml.xmlsec.signature.SignableXMLObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.net.URIComparator; -import net.shibboleth.utilities.java.support.xml.BasicParserPool; - -@Service("PVPSOAPBinding") -public class SoapBinding implements IDecoder, IEncoder { - private static final Logger log = LoggerFactory.getLogger(SoapBinding.class); +@Slf4j +public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder { @Override public InboundMessageInterface decode(final HttpServletRequest req, - final HttpServletResponse resp, final MetadataProvider metadataProvider, + final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider, final boolean isSpEndPoint, final URIComparator comparator) - throws MessageDecodingException, SecurityException, Pvp2Exception { - final HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder(new BasicParserPool()); - final BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = - new BasicSAMLMessageContext<>(); - messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(req)); - messageContext.setMetadataProvider(metadataProvider); - - // TODO: update in a futher version: - // requires a special SignedSOAPRequestPolicyRole because - // messageContext.getInboundMessage() is not directly signed - - // set security context - // BasicSecurityPolicy policy = new BasicSecurityPolicy(); - // policy.getPolicyRules().add( - // new MOAPVPSignedRequestPolicyRule( - // TrustEngineFactory.getSignatureKnownKeysTrustEngine(), - // SPSSODescriptor.DEFAULT_ELEMENT_NAME)); - // SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver( - // policy); - // messageContext.setSecurityPolicyResolver(resolver); - - // decode message - soapDecoder.decode(messageContext); - - final Envelope inboundMessage = (Envelope) messageContext.getInboundMessage(); - - 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; - - } + throws Pvp2Exception { + + try { + final HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder(); + + final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain(); + soapDecoder.setBodyHandler(messageValidatorChain); + + final SAMLProtocolMessageXMLSignatureSecurityHandler msgSignatureValidationHandler = + new SAMLProtocolMessageXMLSignatureSecurityHandler(); + + messageValidatorChain.addHandler(new EaafMessageContextInitializationHandler()); + messageValidatorChain.addHandler(new CheckMessageVersionHandler()); + messageValidatorChain.addHandler(new SAMLProtocolAndRoleHandler()); + messageValidatorChain.addHandler(msgSignatureValidationHandler); + messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler()); + messageValidatorChain.addHandler(new SAMLSOAPDecoderBodyHandler()); + + // decode message + soapDecoder.initialize(); + soapDecoder.decode(); + + final MessageContext<SAMLObject> messageContext = soapDecoder.getMessageContext(); + messageContext.getMessage(); + + } 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); } @@ -134,30 +138,47 @@ public class SoapBinding implements IDecoder, IEncoder { @Override public void encodeRequest(final HttpServletRequest req, final HttpServletResponse resp, final RequestAbstractType request, final String targetLocation, final String relayState, - final Credential credentials, final IRequest pendingReq) - throws MessageEncodingException, SecurityException, Pvp2Exception { + final EaafX509Credential credentials, final IRequest pendingReq) + throws Pvp2Exception { + throw new RuntimeException("Method not supported!!!"); } @Override - public void encodeRespone(final HttpServletRequest req, final HttpServletResponse resp, + public void encodeResponse(final HttpServletRequest req, final HttpServletResponse resp, final StatusResponseType response, final String targetLocation, final String relayState, - final Credential credentials, final IRequest pendingReq) - throws MessageEncodingException, SecurityException, Pvp2Exception { + final EaafX509Credential credentials, final IRequest pendingReq) + throws Pvp2Exception { + + try { + final HTTPSOAP11Encoder encoder = new HTTPSOAP11Encoder(); + encoder.setHttpServletResponse(resp); + + // inject message context + final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, response); - // load default PVP security configurations - EaafDefaultSaml2Bootstrap.initializeDefaultPvpConfiguration(); + // inject signing context + messageContext.addSubcontext(injectSigningInfos(credentials)); - final HTTPSOAP11Encoder encoder = new HTTPSOAP11Encoder(); - final HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(resp, true); - final BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = - new BasicSAMLMessageContext<>(); - context.setOutboundSAMLMessageSigningCredential(credentials); - context.setOutboundSAMLMessage(response); - context.setOutboundMessageTransport(responseAdapter); + // set endpoint url + messageContext.addSubcontext(injectEndpointInfos(response, targetLocation)); - encoder.encode(context); + // set relayState of exists + SAMLBindingSupport.setRelayState(messageContext, relayState); + // sign SAML2 message + SAMLMessageSecuritySupport.signMessage(messageContext); + + // 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", + new Object[] { PvpConstants.SOAP, "encoding", e.getMessage() }, + e); + + } } @Override 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 0bfd974e..1667a07d 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 @@ -21,8 +21,8 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; -import org.opensaml.core.config.Configuration; import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.schema.XSInteger; import org.opensaml.core.xml.schema.XSString; import org.opensaml.core.xml.schema.impl.XSIntegerBuilder; @@ -46,7 +46,7 @@ public class CitizenTokenBuilder { */ public static XMLObject buildAttributeStringValue(final String value) { final XSStringBuilder stringBuilder = - (XSStringBuilder) Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME); + (XSStringBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(XSString.TYPE_NAME); final XSString stringValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME); stringValue.setValue(value); @@ -61,7 +61,7 @@ public class CitizenTokenBuilder { */ public static XMLObject buildAttributeIntegerValue(final int value) { final XSIntegerBuilder integerBuilder = - (XSIntegerBuilder) Configuration.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 9645c2c8..42f69a57 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 @@ -36,13 +36,13 @@ import javax.xml.transform.stream.StreamResult; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; -import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafDefaultSaml2Bootstrap; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import org.apache.commons.httpclient.auth.CredentialsNotAvailableException; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.io.Marshaller; import org.opensaml.core.xml.io.MarshallingException; import org.opensaml.saml.common.xml.SAMLConstants; @@ -176,12 +176,11 @@ public class PvpMetadataBuilder { entitiesDescriptor.getEntityDescriptors().add(entityDescriptor); // load default PVP security configurations - EaafDefaultSaml2Bootstrap.initializeDefaultPvpConfiguration(); entitiesDescriptor.setSignature(signature); // marshall document final Marshaller out = - org.opensaml.xml.Configuration.getMarshallerFactory().getMarshaller(entitiesDescriptor); + XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(entitiesDescriptor); out.marshall(entitiesDescriptor, document); } else { @@ -192,7 +191,7 @@ public class PvpMetadataBuilder { // marshall document final Marshaller out = - org.opensaml.xml.Configuration.getMarshallerFactory().getMarshaller(entityDescriptor); + XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(entityDescriptor); out.marshall(entityDescriptor, document); } @@ -335,7 +334,8 @@ public class PvpMetadataBuilder { attributeService.setIndex(0); attributeService.setIsDefault(true); final ServiceName serviceName = Saml2Utils.createSamlObject(ServiceName.class); - serviceName.setName(new LocalizedString("Default Service", "en")); + serviceName.setValue("Default Service"); + serviceName.setXMLLang("en"); attributeService.getNames().add(serviceName); if (reqSpAttr != null && reqSpAttr.size() > 0) { 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 0499cffa..d37d6724 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 @@ -22,8 +22,8 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder; import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; -import org.opensaml.core.config.Configuration; import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.schema.XSInteger; import org.opensaml.core.xml.schema.XSString; import org.opensaml.core.xml.schema.impl.XSIntegerBuilder; @@ -35,7 +35,7 @@ public class SamlAttributeGenerator implements IAttributeGenerator<Attribute> { private XMLObject buildAttributeStringValue(final String value) { final XSStringBuilder stringBuilder = - (XSStringBuilder) Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME); + (XSStringBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(XSString.TYPE_NAME); final XSString stringValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME); stringValue.setValue(value); @@ -44,7 +44,7 @@ public class SamlAttributeGenerator implements IAttributeGenerator<Attribute> { private XMLObject buildAttributeIntegerValue(final int value) { final XSIntegerBuilder integerBuilder = - (XSIntegerBuilder) Configuration.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/reqattr/EaafExtensionImplementation.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafExtensionImplementation.java index e61f5e6e..726a2960 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafExtensionImplementation.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafExtensionImplementation.java @@ -19,7 +19,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr; -import org.opensaml.saml2.common.impl.ExtensionsImpl; +import org.opensaml.saml.saml2.core.impl.ExtensionsImpl; public class EaafExtensionImplementation extends ExtensionsImpl { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestExtensionBuilder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestExtensionBuilder.java index 25cbc6ef..c77193fd 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestExtensionBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestExtensionBuilder.java @@ -19,15 +19,15 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr; -import org.opensaml.common.impl.AbstractSAMLObjectBuilder; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.common.Extensions; +import org.opensaml.saml.common.AbstractSAMLObjectBuilder; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.Extensions; public class EaafRequestExtensionBuilder extends AbstractSAMLObjectBuilder<Extensions> { @Override public Extensions buildObject() { - return buildObject(SAMLConstants.SAML20P_NS, Extensions.LOCAL_NAME, + return buildObject(SAMLConstants.SAML20P_NS, Extensions.DEFAULT_ELEMENT_LOCAL_NAME, SAMLConstants.SAML20P_PREFIX); } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeBuilder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeBuilder.java index 81d8d192..fde79998 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeBuilder.java @@ -19,11 +19,11 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr; -import org.opensaml.common.impl.AbstractSAMLObjectBuilder; - import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; import at.gv.egiz.eaaf.modules.pvp2.impl.reqattr.EaafRequestedAttributeImpl; +import org.opensaml.saml.common.AbstractSAMLObjectBuilder; + public class EaafRequestedAttributeBuilder extends AbstractSAMLObjectBuilder<EaafRequestedAttribute> { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeMarshaller.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeMarshaller.java index 749310f2..4acee141 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeMarshaller.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeMarshaller.java @@ -23,14 +23,16 @@ import java.util.Map.Entry; import javax.xml.namespace.QName; -import org.opensaml.common.impl.AbstractSAMLObjectMarshaller; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.io.MarshallingException; -import org.opensaml.xml.util.XMLHelper; +import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; + +import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.saml.common.AbstractSAMLObjectMarshaller; import org.w3c.dom.Attr; import org.w3c.dom.Element; -import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; +import net.shibboleth.utilities.java.support.xml.AttributeSupport; public class EaafRequestedAttributeMarshaller extends AbstractSAMLObjectMarshaller { @Override @@ -60,10 +62,11 @@ public class EaafRequestedAttributeMarshaller extends AbstractSAMLObjectMarshall Attr attr; for (final Entry<QName, String> entry : requestedAttr.getUnknownAttributes().entrySet()) { - attr = XMLHelper.constructAttribute(domElement.getOwnerDocument(), entry.getKey()); + + attr = AttributeSupport.constructAttribute(domElement.getOwnerDocument(), entry.getKey()); attr.setValue(entry.getValue()); domElement.setAttributeNodeNS(attr); - if (org.opensaml.xml.Configuration.isIDAttribute(entry.getKey()) + if (XMLObjectProviderRegistrySupport.isIDAttribute(entry.getKey()) || requestedAttr.getUnknownAttributes().isIDAttribute(entry.getKey())) { attr.getOwnerElement().setIdAttributeNode(attr, true); } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeUnmarshaller.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeUnmarshaller.java index 35532e77..5313f340 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeUnmarshaller.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributeUnmarshaller.java @@ -21,15 +21,16 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr; import javax.xml.namespace.QName; -import org.opensaml.common.impl.AbstractSAMLObjectUnmarshaller; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.io.UnmarshallingException; -import org.opensaml.xml.util.XMLHelper; -import org.w3c.dom.Attr; - import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller; +import org.w3c.dom.Attr; + +import net.shibboleth.utilities.java.support.xml.QNameSupport; + public class EaafRequestedAttributeUnmarshaller extends AbstractSAMLObjectUnmarshaller { @Override protected final void processChildElement(final XMLObject parentSamlObject, @@ -64,7 +65,7 @@ public class EaafRequestedAttributeUnmarshaller extends AbstractSAMLObjectUnmars requestedAttr.setIsRequired(attribute.getValue()); } else { - final QName attribQName = XMLHelper.getNodeQName(attribute); + final QName attribQName = QNameSupport.getNodeQName(attribute); if (attribute.isId()) { requestedAttr.getUnknownAttributes().registerID(attribQName); } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesBuilder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesBuilder.java index db08f87f..2d2de292 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesBuilder.java @@ -19,11 +19,11 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr; -import org.opensaml.common.impl.AbstractSAMLObjectBuilder; - import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttributes; import at.gv.egiz.eaaf.modules.pvp2.impl.reqattr.EaafRequestedAttributesImpl; +import org.opensaml.saml.common.AbstractSAMLObjectBuilder; + public class EaafRequestedAttributesBuilder extends AbstractSAMLObjectBuilder<EaafRequestedAttributes> { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesMarshaller.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesMarshaller.java index 8aa70e5a..5d1e0679 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesMarshaller.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesMarshaller.java @@ -19,7 +19,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr; -import org.opensaml.common.impl.AbstractSAMLObjectMarshaller; +import org.opensaml.saml.common.AbstractSAMLObjectMarshaller; public class EaafRequestedAttributesMarshaller extends AbstractSAMLObjectMarshaller { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesUnmarshaller.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesUnmarshaller.java index f616bbb0..9934c502 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesUnmarshaller.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/reqattr/EaafRequestedAttributesUnmarshaller.java @@ -19,13 +19,13 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr; -import org.opensaml.common.impl.AbstractSAMLObjectUnmarshaller; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.io.UnmarshallingException; - import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttributes; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller; + public class EaafRequestedAttributesUnmarshaller extends AbstractSAMLObjectUnmarshaller { @Override protected final void processChildElement(final XMLObject parentObject, 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 new file mode 100644 index 00000000..961f29cb --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java @@ -0,0 +1,17 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.logging; + +import java.util.Arrays; +import java.util.List; + +import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation; + + +public class PvpModuleMessageSource implements IMessageSourceLocation { + + @Override + public List<String> getMessageSourceLocation() { + return Arrays.asList("classpath:messages/pvp_messages"); + + } + +} 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 002db86f..8a741b69 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,18 +25,18 @@ import java.io.Serializable; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.provider.MetadataProviderException; +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 at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; + +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.IPvpMetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; - public class InboundMessage implements InboundMessageInterface, Serializable { private static final Logger log = LoggerFactory.getLogger(InboundMessage.class); @@ -56,7 +56,7 @@ public class InboundMessage implements InboundMessageInterface, Serializable { * @return EntityDescriptor from metadata * @throws NoMetadataInformationException In case of an error */ - public EntityDescriptor getEntityMetadata(final IPvpMetadataProvider metadataProvider) + public EntityDescriptor getEntityMetadata(final IPvp2MetadataProvider metadataProvider) throws NoMetadataInformationException { try { if (metadataProvider == null) { @@ -65,7 +65,7 @@ public class InboundMessage implements InboundMessageInterface, Serializable { return metadataProvider.getEntityDescriptor(this.entityID); - } catch (final MetadataProviderException e) { + } catch (final Pvp2MetadataException 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/message/PvpSProfileRequest.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PvpSProfileRequest.java index 8a2cce3e..c6068769 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PvpSProfileRequest.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PvpSProfileRequest.java @@ -19,10 +19,11 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.message; -import org.opensaml.xml.io.Unmarshaller; -import org.opensaml.xml.io.UnmarshallerFactory; -import org.opensaml.xml.io.UnmarshallingException; -import org.opensaml.xml.signature.SignableXMLObject; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.Unmarshaller; +import org.opensaml.core.xml.io.UnmarshallerFactory; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.xmlsec.signature.SignableXMLObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,7 +57,7 @@ public class PvpSProfileRequest extends InboundMessage { */ public SignableXMLObject getSamlRequest() { final UnmarshallerFactory unmarshallerFactory = - org.opensaml.xml.Configuration.getUnmarshallerFactory(); + XMLObjectProviderRegistrySupport.getUnmarshallerFactory(); final Unmarshaller unmashaller = unmarshallerFactory.getUnmarshaller(getInboundMessage()); try { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PvpSProfileResponse.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PvpSProfileResponse.java index 8d1cbe8c..4ad21fbc 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PvpSProfileResponse.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PvpSProfileResponse.java @@ -19,10 +19,11 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.message; -import org.opensaml.saml2.core.StatusResponseType; -import org.opensaml.xml.io.Unmarshaller; -import org.opensaml.xml.io.UnmarshallerFactory; -import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.Unmarshaller; +import org.opensaml.core.xml.io.UnmarshallerFactory; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.saml.saml2.core.StatusResponseType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,7 +44,7 @@ public class PvpSProfileResponse extends InboundMessage { */ public StatusResponseType getResponse() { final UnmarshallerFactory unmarshallerFactory = - org.opensaml.xml.Configuration.getUnmarshallerFactory(); + XMLObjectProviderRegistrySupport.getUnmarshallerFactory(); final Unmarshaller unmashaller = unmarshallerFactory.getUnmarshaller(getInboundMessage()); try { 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 4a9bb89a..ec59b1df 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 @@ -21,48 +21,59 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.metadata; import java.io.IOException; import java.security.cert.CertificateException; -import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Timer; +import java.util.UUID; +import javax.annotation.Nonnull; +import javax.naming.ConfigurationException; import javax.xml.namespace.QName; -import org.apache.commons.lang3.StringUtils; -import org.opensaml.saml2.metadata.EntitiesDescriptor; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.RoleDescriptor; -import org.opensaml.saml2.metadata.provider.ChainingMetadataProvider; -import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.saml2.metadata.provider.MetadataProviderException; -import org.opensaml.saml2.metadata.provider.ObservableMetadataProvider; -import org.opensaml.xml.XMLObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - 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.IPvpMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; -public abstract class AbstractChainingMetadataProvider extends SimpleMetadataProvider - implements ObservableMetadataProvider, IGarbageCollectorProcessing, - IRefreshableMetadataProvider, IDestroyableObject, IPvpMetadataProvider { +import org.apache.commons.lang3.StringUtils; +import org.opensaml.core.criterion.EntityIdCriterion; +import org.opensaml.saml.metadata.resolver.ClearableMetadataResolver; +import org.opensaml.saml.metadata.resolver.MetadataResolver; +import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; +import org.opensaml.saml.metadata.resolver.impl.AbstractMetadataResolver; +import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.RoleDescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements; +import net.shibboleth.utilities.java.support.component.IdentifiedComponent; +import net.shibboleth.utilities.java.support.resolver.CriteriaSet; +import net.shibboleth.utilities.java.support.resolver.ResolverException; + +public abstract class AbstractChainingMetadataProvider extends SimpleMetadataResolver + implements IGarbageCollectorProcessing, IRefreshableMetadataProvider, IDestroyableObject, IPvp2MetadataProvider, + RefreshableMetadataResolver, ClearableMetadataResolver { private static final Logger log = LoggerFactory.getLogger(AbstractChainingMetadataProvider.class); - private MetadataProvider internalProvider = null; + @Nonnull @NonnullElements private final List<MetadataResolver> internalResolvers; private static Object mutex = new Object(); private Timer timer = null; + /** + * Build a chaining metadata resolver that requires valid metadata. + * + */ public AbstractChainingMetadataProvider() { - internalProvider = new ChainingMetadataProvider(); + internalResolvers = Collections.synchronizedList(Collections.emptyList()); } @@ -102,30 +113,34 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro } + + @Override - public synchronized boolean refreshMetadataProvider(final String entityID) { + public synchronized boolean refreshMetadataProvider(final String entityId) { try { // check if metadata provider is already loaded try { - if (internalProvider.getEntityDescriptor(entityID) != null) { + if (resolveEntityDescripor(entityId) != null) { return true; + } - } catch (final MetadataProviderException e) { - log.debug("Metadata for EntityId: {} is not valid. Starting refresh ... ", entityID); + } catch (final ResolverException e) { + log.debug("Metadata for EntityId: {} is not valid. Starting refresh ... ", entityId); } // reload metadata provider - final String metadataUrl = getMetadataUrl(entityID); + final String metadataUrl = getMetadataUrl(entityId); if (StringUtils.isNotEmpty(metadataUrl)) { - final Map<String, HTTPMetadataProvider> actuallyLoadedProviders = - getAllActuallyLoadedProviders(); + final Map<String, MetadataResolver> actuallyLoadedResolver = + getAllActuallyLoadedResolvers(); // check if MetadataProvider is actually loaded - if (actuallyLoadedProviders.containsKey(metadataUrl)) { - actuallyLoadedProviders.get(metadataUrl).refresh(); - log.info("SAML2 metadata for service provider: " + entityID + " is refreshed."); + final MetadataResolver loadedResover = actuallyLoadedResolver.get(metadataUrl); + if (loadedResover instanceof RefreshableMetadataResolver) { + ((RefreshableMetadataResolver)loadedResover).refresh(); + log.info("SAML2 metadata for service provider: " + entityId + " is refreshed."); return true; } else { @@ -134,32 +149,20 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro timer = new Timer(true); } - final ChainingMetadataProvider chainProvider = - (ChainingMetadataProvider) internalProvider; - chainProvider.addMetadataProvider(createNewMetadataProvider(entityID)); + internalResolvers.add(createNewMetadataProvider(metadataUrl)); - emitChangeEvent(); - log.info("SAML2 metadata for service provider: " + entityID + " is added."); + log.info("SAML2 metadata for service provider: " + entityId + " is added."); return true; } } else { log.debug( - "Can not refresh SAML2 metadata: NO SAML2 metadata URL for SP with Id: " + entityID); + "Can not refresh SAML2 metadata: NO SAML2 metadata URL for SP with Id: " + entityId); } - } catch (final MetadataProviderException e) { - log.warn("Refresh SAML2 metadata for service provider: " + entityID + " FAILED.", e); - - } catch (final IOException e) { - log.warn("Refresh SAML2 metadata for service provider: " + entityID + " FAILED.", e); - - } catch (final EaafConfigurationException e) { - log.warn("Refresh SAML2 metadata for service provider: " + entityID + " FAILED.", e); - - } catch (final CertificateException e) { - log.warn("Refresh SAML2 metadata for service provider: " + entityID + " FAILED.", e); + } catch (final IOException | ResolverException | EaafConfigurationException | CertificateException e) { + log.warn("Refresh SAML2 metadata for service provider: " + entityId + " FAILED.", e); } @@ -172,55 +175,20 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro * */ public void internalDestroy() { - if (internalProvider != null && internalProvider instanceof ChainingMetadataProvider) { - log.info("Destrorying PVP-Authentication MetaDataProvider."); - final ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; - - final List<MetadataProvider> providers = chainProvider.getProviders(); - for (final MetadataProvider provider : providers) { - if (provider instanceof HTTPMetadataProvider) { - final HTTPMetadataProvider httpprovider = (HTTPMetadataProvider) provider; - log.debug("Destroy HTTPMetadataProvider +" + httpprovider.getMetadataURI()); - httpprovider.destroy(); + log.info("Destroying chained metadata resolvers ..."); - } else { - log.warn("MetadataProvider can not be destroyed."); - } + for (final MetadataResolver resolver : internalResolvers) { + destroyMetadataResolver(resolver); } - internalProvider = new ChainingMetadataProvider(); + internalResolvers.clear(); if (timer != null) { timer.cancel(); } - } else { - log.warn( - "ReInitalize MOAMetaDataProvider is not possible! MOA-ID Instance has to be restarted manualy"); - } } - /* - * (non-Javadoc) - * - * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# - * requireValidMetadata() - */ - @Override - public boolean requireValidMetadata() { - return internalProvider.requireValidMetadata(); - } - - /* - * (non-Javadoc) - * - * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# - * setRequireValidMetadata (boolean) - */ - @Override - public void setRequireValidMetadata(final boolean requireValidMetadata) { - internalProvider.setRequireValidMetadata(requireValidMetadata); - } /* * (non-Javadoc) @@ -359,18 +327,6 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro return result; } - /* - * (non-Javadoc) - * - * @see - * org.opensaml.saml2.metadata.provider.ObservableMetadataProvider#getObservers( - * ) - */ - @Override - public List<Observer> getObservers() { - return ((ChainingMetadataProvider) internalProvider).getObservers(); - } - /** * Get the URL to metadata for a specific entityID. * @@ -384,13 +340,13 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro * Creates a new implementation specific SAML2 metadata provider. * * @param entityId EntityId - * @return MetadataProvider + * @return MetadataResolver * @throws EaafConfigurationException In case of an error * @throws IOException In case of an error * @throws CertificateException In case of an error * @throws ConfigurationException In case of an error */ - protected abstract MetadataProvider createNewMetadataProvider(String entityId) + protected abstract MetadataResolver createNewMetadataProvider(String entityId) throws EaafConfigurationException, IOException, CertificateException; /** @@ -398,33 +354,25 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro * * @throws EaafConfigurationException In case of an error */ + @Nonnull protected abstract List<String> getAllMetadataUrlsFromConfiguration() throws EaafConfigurationException; - protected void emitChangeEvent() { - if (getObservers() == null || getObservers().size() == 0) { - return; - } - - final List<Observer> tempObserverList = new ArrayList<>(getObservers()); - for (final ObservableMetadataProvider.Observer observer : tempObserverList) { - if (observer != null) { - observer.onEvent(this); - } - } - } - private Map<String, HTTPMetadataProvider> getAllActuallyLoadedProviders() { - final Map<String, HTTPMetadataProvider> loadedproviders = + private Map<String, MetadataResolver> getAllActuallyLoadedResolvers() { + final Map<String, MetadataResolver> loadedproviders = new HashMap<>(); - final ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; // make a Map of all actually loaded HTTPMetadataProvider - final List<MetadataProvider> providers = chainProvider.getProviders(); - for (final MetadataProvider provider : providers) { - if (provider instanceof HTTPMetadataProvider) { - final HTTPMetadataProvider httpprovider = (HTTPMetadataProvider) provider; - loadedproviders.put(httpprovider.getMetadataURI(), httpprovider); + 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); } } @@ -433,19 +381,17 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro } private void addAndRemoveMetadataProvider() throws EaafConfigurationException { - if (internalProvider != null && internalProvider instanceof ChainingMetadataProvider) { - log.info("Reload MOAMetaDataProvider."); + 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, MetadataProvider> providersinuse = new HashMap<>(); - final ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; + final Map<String, MetadataResolver> providersinuse = new HashMap<>(); // get all actually loaded metadata providers - final Map<String, HTTPMetadataProvider> loadedproviders = getAllActuallyLoadedProviders(); + final Map<String, MetadataResolver> loadedproviders = getAllActuallyLoadedResolvers(); /* * TODO: maybe add metadata provider destroy after timeout. But could be a @@ -460,7 +406,6 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro // compare actually loaded Providers with configured SAML2 SPs final List<String> allMetadataUrls = getAllMetadataUrlsFromConfiguration(); - if (allMetadataUrls != null) { final Iterator<String> metadataUrlInterator = allMetadataUrls.iterator(); while (metadataUrlInterator.hasNext()) { final String metadataurl = metadataUrlInterator.next(); @@ -477,15 +422,15 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro } } - } + // remove all actually loaded MetadataProviders with are not in ConfigurationDB // any more - final Collection<HTTPMetadataProvider> notusedproviders = loadedproviders.values(); - for (final HTTPMetadataProvider provider : notusedproviders) { - final String metadataurl = provider.getMetadataURI(); - try { - provider.destroy(); + 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 @@ -493,31 +438,43 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro * unmodifiableList to hold all registrated MetadataProviders. */ // chainProvider.removeMetadataProvider(provider); - log.info("Remove not used MetadataProvider with MetadataURL " + metadataurl); - } catch (final Throwable e) { - log.error("HTTPMetadataProvider with URL " + metadataurl - + " can not be removed from the list of actually loaded Providers.", e); - - } } + } + + private EntityDescriptor resolveEntityDescripor(String entityId) throws ResolverException { + final CriteriaSet criteria = new CriteriaSet(); + criteria.add(new EntityIdCriterion(entityId)); + for (final MetadataResolver resolver : internalResolvers) { try { - chainProvider.setProviders(new ArrayList<>(providersinuse.values())); - emitChangeEvent(); + final EntityDescriptor descriptors = resolver.resolveSingle(criteria); + if (descriptors != null) { + return descriptors; + } - } catch (final MetadataProviderException e) { - log.warn( - "ReInitalize AbstractMetaDataProvider is not possible! Service has to be restarted manualy", - e); + } catch (final ResolverException e) { + continue; } - } else { - log.warn( - "ReInitalize AbstractMetaDataProvider is not possible! Service has to be restarted manualy"); } + return null; + + } + + private void destroyMetadataResolver(MetadataResolver resolver) { + if (resolver instanceof AbstractMetadataResolver) { + final AbstractMetadataResolver httpprovider = (AbstractMetadataResolver) resolver; + log.debug("Destroy metadata resolver with id: {}", httpprovider.getId()); + httpprovider.destroy(); + + } else { + log.warn("Metadata resolver: {} can not be destroyed. Reason: unsupported type: {}", + resolver.getId(), resolver.getClass().getName()); + + } } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java deleted file mode 100644 index ebc057df..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a - * cooperation between EGIZ, A-SIT Plus, 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 "Licence"); You may not use this work except in - * compliance with the Licence. You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software distributed under the Licence - * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the Licence for the specific language governing permissions and limitations under - * the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text file for details on the - * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative - * works that you distribute must include a readable copy of the "NOTICE" text file. -*/ - -package at.gv.egiz.eaaf.modules.pvp2.impl.metadata; - -import java.util.ArrayList; -import java.util.List; - -import org.opensaml.saml2.metadata.provider.FilterException; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.xml.XMLObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Metadata filter-chain implementation. - * - * @author tlenz - * - */ -public class MetadataFilterChain implements MetadataFilter { - private static final Logger log = LoggerFactory.getLogger(MetadataFilterChain.class); - - private final List<MetadataFilter> filters = new ArrayList<>(); - - /** - * Return all actually used Metadata filters. - * - * @return List of Metadata filters - */ - public List<MetadataFilter> getFilters() { - return filters; - } - - /** - * Add a new Metadata filter to filterchain. - * - * @param filter add a metadata filter - */ - public void addFilter(final MetadataFilter filter) { - filters.add(filter); - } - - /* - * (non-Javadoc) - * - * @see - * org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml - * .XMLObject) - */ - @Override - public void doFilter(final XMLObject arg0) throws FilterException { - for (final MetadataFilter filter : filters) { - log.trace("Use EAAFMetadataFilter " + filter.getClass().getName()); - filter.doFilter(arg0); - } - - } - -} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java index d63950cb..35ad3f97 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java @@ -25,30 +25,29 @@ import java.util.Timer; import javax.net.ssl.SSLHandshakeException; -import org.apache.commons.httpclient.HttpClient; -import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; -import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.xml.parse.ParserPool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - 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.exception.SchemaValidationException; import at.gv.egiz.eaaf.modules.pvp2.exception.SignatureValidationException; +import org.apache.http.client.HttpClient; +import org.opensaml.saml.metadata.resolver.MetadataResolver; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; +import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver; +import org.opensaml.saml.metadata.resolver.impl.HTTPMetadataResolver; +import org.springframework.beans.factory.annotation.Autowired; + +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.xml.ParserPool; + /** * Simple SAML2 metadata provider. * * @author tlenz * */ -public abstract class SimpleMetadataProvider implements MetadataProvider { - private static final Logger log = LoggerFactory.getLogger(SimpleMetadataProvider.class); - +@Slf4j +public abstract class SimpleMetadataResolver implements MetadataResolver { private static final String URI_PREFIX_HTTP = "http:"; private static final String URI_PREFIX_HTTPS = "https:"; private static final String URI_PREFIX_FILE = "file:"; @@ -56,6 +55,21 @@ public abstract class SimpleMetadataProvider implements MetadataProvider { @Autowired protected IConfiguration authConfig; + @Override + public final boolean isRequireValidMetadata() { + return true; + + } + + @Override + public final void setRequireValidMetadata(final boolean requireValidMetadata) { + log.warn("EAAF {} requires always valid metadata. Setting will be ignored", + SimpleMetadataResolver.class.getSimpleName()); + + } + + + /** * Create a single SAML2 metadata provider. * @@ -74,7 +88,7 @@ public abstract class SimpleMetadataProvider implements MetadataProvider { * @return SAML2 Metadata Provider, or null if the metadata provider can not * initialized */ - protected MetadataProvider createNewSimpleMetadataProvider(final String metadataLocation, + protected MetadataResolver createNewSimpleMetadataProvider(final String metadataLocation, final MetadataFilter filter, final String idForLogging, final Timer timer, final ParserPool pool, final HttpClient httpClient) { if (metadataLocation.startsWith(URI_PREFIX_HTTP) @@ -130,24 +144,24 @@ public abstract class SimpleMetadataProvider implements MetadataProvider { * * @return SAML2 Metadata Provider */ - private MetadataProvider createNewFileSystemMetaDataProvider(final File metadataFile, + private MetadataResolver createNewFileSystemMetaDataProvider(final File metadataFile, final MetadataFilter filter, final String idForLogging, final Timer timer, final ParserPool pool) { - FilesystemMetadataProvider fileSystemProvider = null; + FilesystemMetadataResolver fileSystemResolver = null; try { - fileSystemProvider = new FilesystemMetadataProvider(timer, metadataFile); - fileSystemProvider.setParserPool(pool); - fileSystemProvider.setRequireValidMetadata(true); - fileSystemProvider.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes - fileSystemProvider.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours - // httpProvider.setRefreshDelayFactor(0.1F); + fileSystemResolver = new FilesystemMetadataResolver(timer, metadataFile); + fileSystemResolver.setParserPool(pool); + fileSystemResolver.setRequireValidMetadata(true); + fileSystemResolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes + fileSystemResolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours - fileSystemProvider.setMetadataFilter(filter); - fileSystemProvider.initialize(); + fileSystemResolver.setMetadataFilter(filter); + fileSystemResolver.initialize(); + fileSystemResolver.setId(metadataFile.getAbsolutePath()); - fileSystemProvider.setRequireValidMetadata(true); + fileSystemResolver.setRequireValidMetadata(true); - return fileSystemProvider; + return fileSystemResolver; } catch (final Exception e) { log.warn("Failed to load Metadata file for " + idForLogging + "[ " + "File: " @@ -156,8 +170,9 @@ public abstract class SimpleMetadataProvider implements MetadataProvider { log.warn("Can not initialize SAML2 metadata provider from filesystem: " + metadataFile.getAbsolutePath() + " Reason: " + e.getMessage(), e); - if (fileSystemProvider != null) { - fileSystemProvider.destroy(); + if (fileSystemResolver != null) { + fileSystemResolver.destroy(); + } } @@ -178,24 +193,25 @@ public abstract class SimpleMetadataProvider implements MetadataProvider { * * @return SAML2 Metadata Provider */ - private MetadataProvider createNewHttpMetaDataProvider(final String metadataUrl, + private MetadataResolver createNewHttpMetaDataProvider(final String metadataUrl, final MetadataFilter filter, final String idForLogging, final Timer timer, final ParserPool pool, final HttpClient httpClient) { - HTTPMetadataProvider httpProvider = null; + HTTPMetadataResolver httpMetadataResolver = null; try { - httpProvider = new HTTPMetadataProvider(timer, httpClient, metadataUrl); - httpProvider.setParserPool(pool); - httpProvider.setRequireValidMetadata(true); - httpProvider.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes - httpProvider.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours + 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); - httpProvider.setMetadataFilter(filter); - httpProvider.initialize(); + httpMetadataResolver.setMetadataFilter(filter); + httpMetadataResolver.setId(metadataUrl); + httpMetadataResolver.initialize(); - httpProvider.setRequireValidMetadata(true); + httpMetadataResolver.setRequireValidMetadata(true); - return httpProvider; + return httpMetadataResolver; } catch (final Throwable e) { if (e.getCause() != null && e.getCause().getCause() instanceof SSLHandshakeException) { @@ -213,15 +229,11 @@ public abstract class SimpleMetadataProvider implements MetadataProvider { log.warn("Failed to load Metadata file for " + idForLogging + "[ " + e.getMessage() + " ]", e); - if (httpProvider != null) { + if (httpMetadataResolver != null) { log.debug("Destroy failed Metadata provider"); - httpProvider.destroy(); - } + httpMetadataResolver.destroy(); - // if (timer != null) { - // log.debug("Destroy Timer."); - // timer.cancel(); - // } + } } 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 new file mode 100644 index 00000000..dc60019a --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java @@ -0,0 +1,77 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; + +import org.opensaml.messaging.decoder.MessageDecodingException; +import org.opensaml.saml.saml2.binding.decoding.impl.HTTPPostDecoder; + +import com.google.common.base.Strings; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.codec.Base64Support; + +/** + * SAML2 Post-Binding decoder with same EAAF specific hardening regarding http + * request-parameter processing. + * + * @author tlenz + * + */ +@Slf4j +public class EaafHttpPostDecoder extends HTTPPostDecoder { + + @Override + protected InputStream getBase64DecodedMessage(final HttpServletRequest request) + throws MessageDecodingException { + + log.debug("Getting Base64 encoded message from request"); + String encodedMessage = getLastParameterFromRequest(request, "SAMLRequest"); + if (Strings.isNullOrEmpty(encodedMessage)) { + encodedMessage = getLastParameterFromRequest(request, "SAMLResponse"); + } + + + + if (Strings.isNullOrEmpty(encodedMessage)) { + log.info("Request did not contain either a SAMLRequest or " + + "SAMLResponse paramter. Invalid request for SAML 2 HTTP POST binding."); + throw new MessageDecodingException("No SAML message present in request"); + } + + log.trace("Base64 decoding SAML message:\n{}", 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"); + } + + log.trace("Decoded SAML message:\n{}", new String(decodedBytes)); + return new ByteArrayInputStream(decodedBytes); + } + + /** + * 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; + + } +} 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 new file mode 100644 index 00000000..e9140f26 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java @@ -0,0 +1,71 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml; + +import java.io.InputStream; + +import javax.servlet.http.HttpServletRequest; + +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.xml.SAMLConstants; +import org.opensaml.saml.saml2.binding.decoding.impl.HTTPRedirectDeflateDecoder; + +import com.google.common.base.Strings; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.net.URISupport; +import net.shibboleth.utilities.java.support.primitive.StringSupport; + +/** + * SAML2 Redirect-Binding deflate decoder with same EAAF specific hardening + * regarding http request-parameter processing. + * + * @author tlenz + * + */ +@Slf4j +public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder { + + @Override + protected void doDecode() throws MessageDecodingException { + final MessageContext<SAMLObject> messageContext = new MessageContext<>(); + final HttpServletRequest request = getHttpServletRequest(); + + if (!"GET".equalsIgnoreCase(request.getMethod())) { + throw new MessageDecodingException("This message decoder only supports the HTTP GET method"); + } + + final String samlEncoding = StringSupport.trimOrNull(request.getParameter("SAMLEncoding")); + if (samlEncoding != null && !SAMLConstants.SAML2_BINDING_URL_ENCODING_DEFLATE_URI.equals(samlEncoding)) { + throw new MessageDecodingException("Request indicated an unsupported SAMLEncoding: " + samlEncoding); + + } + + final String relayState = request.getParameter("RelayState"); + log.debug("Decoded RelayState: {}", relayState); + SAMLBindingSupport.setRelayState(messageContext, relayState); + + final InputStream samlMessageIns; + + // 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")); + } 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"); + + populateBindingContext(messageContext); + + setMessageContext(messageContext); + } + +} 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 92d8f4b9..7c433c1c 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 @@ -21,7 +21,19 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml; import java.security.KeyStore; -import org.opensaml.xml.security.x509.X509Credential; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +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.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; + +import org.opensaml.security.x509.X509Credential; +import org.opensaml.security.x509.impl.KeyStoreX509CredentialAdapter; + +import lombok.extern.slf4j.Slf4j; /** * OpenSAML2 KeyStore adapter. @@ -29,8 +41,11 @@ import org.opensaml.xml.security.x509.X509Credential; * @author tlenz * */ -public class EaafKeyStoreX509CredentialAdapter - extends org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter { +@Slf4j +public class EaafKeyStoreX509CredentialAdapter extends KeyStoreX509CredentialAdapter + implements EaafX509Credential { + + private String signatureAlgorithmtToUse; /** * Get an OpenSAML2 keystore. @@ -38,10 +53,31 @@ public class EaafKeyStoreX509CredentialAdapter * @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(final KeyStore store, final String alias, - final char[] password) { + public EaafKeyStoreX509CredentialAdapter(@Nonnull final KeyStore store, @Nonnull final String alias, + @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}); + + } + + try { + setSignatureAlgorithmForSigning(Saml2Utils.getSignatureAlgorithm(this, + PvpConstants.DEFAULT_SIGNING_METHODE_RSA, + PvpConstants.DEFAULT_SIGNING_METHODE_EC)); + + } catch (final SamlSigningException e) { + throw new CredentialsNotAvailableException("internal.pvp.01", new Object[] {keyStoreFriendlyName, alias}, e); + + } + } @Override @@ -49,4 +85,16 @@ public class EaafKeyStoreX509CredentialAdapter return X509Credential.class; } + @Override + public String getSignatureAlgorithmForSigning() { + return this.signatureAlgorithmtToUse; + + } + + @Override + public void setSignatureAlgorithmForSigning(String sigAlg) { + this.signatureAlgorithmtToUse = sigAlg; + + } + } 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 404b4e8e..3650e617 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,6 +19,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -26,18 +27,21 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Writer; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; -import org.opensaml.common.binding.SAMLMessageContext; -import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; -import org.opensaml.ws.message.encoder.MessageEncodingException; -import org.opensaml.ws.transport.http.HTTPOutTransport; -import org.opensaml.ws.transport.http.HTTPTransportUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import javax.servlet.http.HttpServletResponse; import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiBuilderConfiguration; import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiFormBuilder; +import at.gv.egiz.eaaf.core.impl.gui.velocity.VelocityProvider; + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +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.HTTPPostEncoder; + +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.net.HttpServletSupport; /** * OpenSAML2 Post-Binding encoder that uses dynamic loaded templates. @@ -45,10 +49,9 @@ import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiFormBuilder; * @author tlenz * */ +@Slf4j public class HttpPostEncoderWithOwnTemplate extends HTTPPostEncoder { - private static final Logger log = LoggerFactory.getLogger(HttpPostEncoderWithOwnTemplate.class); - private final VelocityEngine velocityEngine; private final IVelocityGuiBuilderConfiguration guiConfig; private final IVelocityGuiFormBuilder guiBuilder; @@ -57,29 +60,28 @@ public class HttpPostEncoderWithOwnTemplate extends HTTPPostEncoder { * * @param guiConfig GUI configuration * @param guiBuilder GUI builder implementation - * @param engine velocity engine + * @throws Exception In case of a {@link Velocity} initialization error */ public HttpPostEncoderWithOwnTemplate(final IVelocityGuiBuilderConfiguration guiConfig, - final IVelocityGuiFormBuilder guiBuilder, final VelocityEngine engine) { - super(engine, null); - this.velocityEngine = engine; + final IVelocityGuiFormBuilder guiBuilder) throws Exception { this.guiConfig = guiConfig; this.guiBuilder = guiBuilder; + setVelocityEngine(VelocityProvider.getClassPathVelocityEngine()); + } /** - * Base64 and POST encodes the outbound message and writes it to the outbound + * Base64 and POST encodes the out-bound message and writes it to the out-bound * transport. * * @param messageContext current message context - * @param endpointUrl endpoint URL to which to encode message * * @throws MessageEncodingException thrown if there is a problem encoding the * message */ @Override - protected void postEncode(final SAMLMessageContext messageContext, final String endpointUrl) + protected void postEncode(final MessageContext<SAMLObject> messageContext, final String endpointUrl) throws MessageEncodingException { log.debug("Invoking Velocity template to create POST body"); InputStream is = null; @@ -91,19 +93,16 @@ public class HttpPostEncoderWithOwnTemplate extends HTTPPostEncoder { // load template is = guiBuilder.getTemplateInputStream(guiConfig); - // populate velocity context with SAML2 parameters populateVelocityContext(context, messageContext, endpointUrl); - // populate transport parameter - final HTTPOutTransport outTransport = - (HTTPOutTransport) messageContext.getOutboundMessageTransport(); - HTTPTransportUtils.addNoCacheHeaders(outTransport); - HTTPTransportUtils.setUTF8Encoding(outTransport); - HTTPTransportUtils.setContentType(outTransport, "text/html"); + final HttpServletResponse response = getHttpServletResponse(); - // evaluate template and write content to response - final Writer out = new OutputStreamWriter(outTransport.getOutgoingStream(), "UTF-8"); - velocityEngine.evaluate(context, out, "SAML2_POST_BINDING", + HttpServletSupport.addNoCacheHeaders(response); + HttpServletSupport.setUTF8Encoding(response); + HttpServletSupport.setContentType(response, "text/html"); + + final Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8"); + getVelocityEngine().evaluate(context, out, "SAML2_POST_BINDING", new BufferedReader(new InputStreamReader(is, "UTF-8"))); out.flush(); @@ -123,4 +122,5 @@ public class HttpPostEncoderWithOwnTemplate extends HTTPPostEncoder { } } + } 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 8838daec..bd450518 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 @@ -19,15 +19,13 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml; -import org.opensaml.common.binding.SAMLMessageContext; -import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder; -import org.opensaml.ws.message.MessageContext; -import org.opensaml.ws.message.encoder.MessageEncodingException; +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 at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafDefaultSaml2Bootstrap; - /** * Create deflate encoded SAML2 redirect-binding informations. * @@ -40,27 +38,18 @@ public class StringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder { private String redirectUrl = null; @Override - public void encode(final MessageContext messageContext) throws MessageEncodingException { - if (!(messageContext instanceof SAMLMessageContext)) { - log.error("Invalid message context type, this encoder only support SAMLMessageContext"); - throw new MessageEncodingException( - "Invalid message context type, this encoder only support SAMLMessageContext"); - } - - // load default PVP security configurations - EaafDefaultSaml2Bootstrap.initializeDefaultPvpConfiguration(); - - final SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext; + protected void doEncode() throws MessageEncodingException { + final MessageContext<SAMLObject> messageContext = getMessageContext(); + final SAMLObject outboundMessage = messageContext.getMessage(); - final String endpointUrl = getEndpointURL(samlMsgCtx).buildURL(); + final String endpointUrl = getEndpointURL(messageContext).toString(); - setResponseDestination(samlMsgCtx.getOutboundSAMLMessage(), endpointUrl); + removeSignature(outboundMessage); - removeSignature(samlMsgCtx); + final String encodedMessage = deflateAndBase64Encode(outboundMessage); - final String encodedMessage = deflateAndBase64Encode(samlMsgCtx.getOutboundSAMLMessage()); + redirectUrl = buildRedirectURL(messageContext, endpointUrl, encodedMessage); - redirectUrl = buildRedirectURL(samlMsgCtx, endpointUrl, encodedMessage); } /** diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafDefaultSaml2Bootstrap.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafDefaultSaml2Bootstrap.java deleted file mode 100644 index 9625b591..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafDefaultSaml2Bootstrap.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a - * cooperation between EGIZ, A-SIT Plus, 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 "Licence"); You may not use this work except in - * compliance with the Licence. You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software distributed under the Licence - * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the Licence for the specific language governing permissions and limitations under - * the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text file for details on the - * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative - * works that you distribute must include a readable copy of the "NOTICE" text file. -*/ - -package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize; - -import org.opensaml.DefaultBootstrap; -import org.opensaml.xml.ConfigurationException; - -import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; -import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttributes; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributeBuilder; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributeMarshaller; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributeUnmarshaller; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributesBuilder; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributesMarshaller; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributesUnmarshaller; - -/** - * EAAF specific OpenSAML Initializer. - * - * @author tlenz - * - */ -public class EaafDefaultSaml2Bootstrap extends DefaultBootstrap { - - /** - * OpenSAML2 bootstrap. - * - * @throws ConfigurationException In case of an error - */ - public static synchronized void bootstrap() throws ConfigurationException { - - initializeXMLSecurity(); - - initializeXMLTooling(); - - initializeArtifactBuilderFactories(); - - initializeGlobalSecurityConfiguration(); - - initializeParserPool(); - - initializeESAPI(); - - initializeExtenstions(); - - } - - private static void initializeExtenstions() { - org.opensaml.xml.Configuration.registerObjectProvider( - EaafRequestedAttribute.DEFAULT_ELEMENT_NAME, new EaafRequestedAttributeBuilder(), - new EaafRequestedAttributeMarshaller(), new EaafRequestedAttributeUnmarshaller()); - - org.opensaml.xml.Configuration.registerObjectProvider( - EaafRequestedAttributes.DEFAULT_ELEMENT_NAME, new EaafRequestedAttributesBuilder(), - new EaafRequestedAttributesMarshaller(), new EaafRequestedAttributesUnmarshaller()); - - } - - public static void initializeDefaultPvpConfiguration() { - initializeGlobalSecurityConfiguration(); - - } - - /** - * Initializes the default global security configuration. - */ - protected static void initializeGlobalSecurityConfiguration() { - org.opensaml.xml.Configuration.setGlobalSecurityConfiguration( - EaafDefaultSecurityConfigurationBootstrap.buildDefaultConfig()); - } -} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafDefaultSecurityConfigurationBootstrap.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafDefaultSecurityConfigurationBootstrap.java index f3e50e4e..97f0f225 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafDefaultSecurityConfigurationBootstrap.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafDefaultSecurityConfigurationBootstrap.java @@ -19,14 +19,17 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize; -import org.opensaml.xml.encryption.EncryptionConstants; -import org.opensaml.xml.security.BasicSecurityConfiguration; -import org.opensaml.xml.security.DefaultSecurityConfigurationBootstrap; -import org.opensaml.xml.security.credential.BasicKeyInfoGeneratorFactory; -import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorManager; -import org.opensaml.xml.security.keyinfo.NamedKeyInfoGeneratorManager; -import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; -import org.opensaml.xml.signature.SignatureConstants; +import java.util.Arrays; +import java.util.Collections; + +import org.opensaml.xmlsec.config.impl.DefaultSecurityConfigurationBootstrap; +import org.opensaml.xmlsec.encryption.support.EncryptionConstants; +import org.opensaml.xmlsec.encryption.support.RSAOAEPParameters; +import org.opensaml.xmlsec.impl.BasicDecryptionConfiguration; +import org.opensaml.xmlsec.impl.BasicEncryptionConfiguration; +import org.opensaml.xmlsec.impl.BasicSignatureSigningConfiguration; +import org.opensaml.xmlsec.impl.BasicSignatureValidationConfiguration; +import org.opensaml.xmlsec.signature.support.SignatureConstants; /** * EAAF specific OpenSAML2 security configuration. @@ -38,102 +41,137 @@ public class EaafDefaultSecurityConfigurationBootstrap extends DefaultSecurityConfigurationBootstrap { /** - * Build EAAF security configuration for OpenSAML2. + * Set EAAF specific encryption configuration to OpenSAML 3.x. * * @return */ - public static BasicSecurityConfiguration buildDefaultConfig() { - final BasicSecurityConfiguration config = new BasicSecurityConfiguration(); - - populateSignatureParams(config); - populateEncryptionParams(config); - populateKeyInfoCredentialResolverParams(config); - populateKeyInfoGeneratorManager(config); - populateKeyParams(config); + public static BasicEncryptionConfiguration buildEaafEncryptionConfiguration() { + final BasicEncryptionConfiguration config = new BasicEncryptionConfiguration(); + + config.setBlacklistedAlgorithms(Arrays.asList( + EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSA15, + EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES, + EncryptionConstants.ALGO_ID_KEYWRAP_TRIPLEDES)); + + config.setDataEncryptionAlgorithms(Arrays.asList( + // The order of these is significant. + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128, + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192, + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256, + + // register GCM algorithms + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192_GCM, + EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM)); + + config.setKeyTransportEncryptionAlgorithms(Arrays.asList( + // The order of the RSA algos is significant. + EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP, + EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP11, + + // The order of these is not significant. + // These aren't really "preferences" per se. They just need to be registered + // so that they can be used if a credential with a key of that type and size is + // seen. + EncryptionConstants.ALGO_ID_KEYWRAP_AES128, + EncryptionConstants.ALGO_ID_KEYWRAP_AES192, + EncryptionConstants.ALGO_ID_KEYWRAP_AES256)); + + config.setRSAOAEPParameters(new RSAOAEPParameters( + SignatureConstants.ALGO_ID_DIGEST_SHA1, + EncryptionConstants.ALGO_ID_MGF1_SHA1, + null)); + + config.setDataKeyInfoGeneratorManager(buildDataEncryptionKeyInfoGeneratorManager()); + config.setKeyTransportKeyInfoGeneratorManager(buildKeyTransportEncryptionKeyInfoGeneratorManager()); return config; } - protected static void populateKeyInfoGeneratorManager(final BasicSecurityConfiguration config) { - final NamedKeyInfoGeneratorManager namedManager = new NamedKeyInfoGeneratorManager(); - config.setKeyInfoGeneratorManager(namedManager); - - namedManager.setUseDefaultManager(true); - final KeyInfoGeneratorManager defaultManager = namedManager.getDefaultManager(); + /** + * Set EAAF specific decryption configuration to OpenSAML 3.x. + * + * @return + */ + public static BasicDecryptionConfiguration buildEaaftDecryptionConfiguration() { + final BasicDecryptionConfiguration config = new BasicDecryptionConfiguration(); - final BasicKeyInfoGeneratorFactory basicFactory = new BasicKeyInfoGeneratorFactory(); - basicFactory.setEmitPublicKeyValue(true); + config.setBlacklistedAlgorithms(Collections.singletonList( + EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSA15)); - final X509KeyInfoGeneratorFactory x509Factory = new X509KeyInfoGeneratorFactory(); - x509Factory.setEmitEntityCertificate(true); + config.setEncryptedKeyResolver(buildBasicEncryptedKeyResolver()); - defaultManager.registerFactory(basicFactory); - defaultManager.registerFactory(x509Factory); + return config; } - protected static void populateSignatureParams(final BasicSecurityConfiguration config) { - - // use SHA256 instead of SHA1 - config.registerSignatureAlgorithmURI("RSA", SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); - - config.registerSignatureAlgorithmURI("DSA", "http://www.w3.org/2000/09/xmldsig#dsa-sha1"); - - // use SHA256 instead of SHA1 - config.registerSignatureAlgorithmURI("EC", SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256); - - // use SHA256 instead of SHA1 - config.registerSignatureAlgorithmURI("AES", SignatureConstants.ALGO_ID_MAC_HMAC_SHA256); - - config.registerSignatureAlgorithmURI("DESede", SignatureConstants.ALGO_ID_MAC_HMAC_SHA256); - - config.setSignatureCanonicalizationAlgorithm("http://www.w3.org/2001/10/xml-exc-c14n#"); - config.setSignatureHMACOutputLength(null); + /** + * Set EAAF specific signature-creation configuration to OpenSAML 3.x. + * + * @return + */ + public static BasicSignatureSigningConfiguration buildEaafSignatureSigningConfiguration() { + final BasicSignatureSigningConfiguration config = new BasicSignatureSigningConfiguration(); + + config.setBlacklistedAlgorithms(Arrays.asList( + SignatureConstants.ALGO_ID_DIGEST_NOT_RECOMMENDED_MD5, + SignatureConstants.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5, + SignatureConstants.ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5, + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1, + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA1, + SignatureConstants.ALGO_ID_SIGNATURE_DSA_SHA1, + SignatureConstants.ALGO_ID_DIGEST_SHA1)); + + config.setSignatureAlgorithms(Arrays.asList( + // The order within each key group is significant. + // The order of the key groups themselves is not significant. + + // RSA + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA384, + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512, + + // ECDSA + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256, + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA384, + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA512 + + // HMAC (all symmetric keys) + // SignatureConstants.ALGO_ID_MAC_HMAC_SHA256, + // SignatureConstants.ALGO_ID_MAC_HMAC_SHA384, + // SignatureConstants.ALGO_ID_MAC_HMAC_SHA512, + // SignatureConstants.ALGO_ID_MAC_HMAC_SHA1 + )); + + config.setSignatureReferenceDigestMethods(Arrays.asList( + // The order of these is significant. + SignatureConstants.ALGO_ID_DIGEST_SHA256, + SignatureConstants.ALGO_ID_DIGEST_SHA384, + SignatureConstants.ALGO_ID_DIGEST_SHA512)); + + config.setSignatureCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + + config.setKeyInfoGeneratorManager(buildSignatureKeyInfoGeneratorManager()); - // use SHA256 instead of SHA1 - config.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256); + return config; } - protected static void populateEncryptionParams(final BasicSecurityConfiguration config) { - config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(128), - "http://www.w3.org/2001/04/xmlenc#aes128-cbc"); - config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(192), - "http://www.w3.org/2001/04/xmlenc#aes192-cbc"); - config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(256), - "http://www.w3.org/2001/04/xmlenc#aes256-cbc"); - - // support GCM mode - config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(128), - EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM); - - config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(192), - EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192_GCM); - - config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(256), - EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM); - - config.registerDataEncryptionAlgorithmURI("DESede", Integer.valueOf(168), - "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"); - config.registerDataEncryptionAlgorithmURI("DESede", Integer.valueOf(192), - "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"); - - config.registerKeyTransportEncryptionAlgorithmURI("RSA", null, "AES", - "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"); - - config.registerKeyTransportEncryptionAlgorithmURI("RSA", null, "DESede", - "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"); - - config.registerKeyTransportEncryptionAlgorithmURI("AES", Integer.valueOf(128), null, - "http://www.w3.org/2001/04/xmlenc#kw-aes128"); - config.registerKeyTransportEncryptionAlgorithmURI("AES", Integer.valueOf(192), null, - "http://www.w3.org/2001/04/xmlenc#kw-aes192"); - config.registerKeyTransportEncryptionAlgorithmURI("AES", Integer.valueOf(256), null, - "http://www.w3.org/2001/04/xmlenc#kw-aes256"); - config.registerKeyTransportEncryptionAlgorithmURI("DESede", Integer.valueOf(168), null, - "http://www.w3.org/2001/04/xmlenc#kw-tripledes"); - config.registerKeyTransportEncryptionAlgorithmURI("DESede", Integer.valueOf(192), null, - "http://www.w3.org/2001/04/xmlenc#kw-tripledes"); - - config.setAutoGeneratedDataEncryptionKeyAlgorithmURI( - "http://www.w3.org/2001/04/xmlenc#aes128-cbc"); + /** + * Set EAAF specific signature-verification configuration to OpenSAML 3.x. + * + * @return + */ + public static BasicSignatureValidationConfiguration buildEaafSignatureValidationConfiguration() { + final BasicSignatureValidationConfiguration config = new BasicSignatureValidationConfiguration(); + + config.setBlacklistedAlgorithms(Arrays.asList( + SignatureConstants.ALGO_ID_DIGEST_NOT_RECOMMENDED_MD5, + SignatureConstants.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5, + SignatureConstants.ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5, + SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1, + SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA1, + SignatureConstants.ALGO_ID_SIGNATURE_DSA_SHA1, + SignatureConstants.ALGO_ID_DIGEST_SHA1)); + + return config; } } 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 new file mode 100644 index 00000000..42d4d736 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java @@ -0,0 +1,156 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, 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 "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize; + +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.xml.XMLConstants; + +import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; +import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttributes; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributeBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributeMarshaller; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributeUnmarshaller; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributesBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributesMarshaller; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.reqattr.EaafRequestedAttributesUnmarshaller; + +import org.opensaml.core.config.ConfigurationService; +import org.opensaml.core.config.InitializationException; +import org.opensaml.core.config.InitializationService; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.xmlsec.DecryptionConfiguration; +import org.opensaml.xmlsec.EncryptionConfiguration; +import org.opensaml.xmlsec.SignatureSigningConfiguration; +import org.opensaml.xmlsec.SignatureValidationConfiguration; + +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; +import net.shibboleth.utilities.java.support.xml.BasicParserPool; +import net.shibboleth.utilities.java.support.xml.ParserPool; + +/** + * EAAF specific OpenSAML Initializer. + * + * @author tlenz + * + */ +@Slf4j +public class EaafOpenSaml3xInitializer extends InitializationService { + + /** + * EAAF specific OpenSAML3.x initialization. + * + * @throws InitializationException In case of an error + * @throws ComponentInitializationException + */ + public static synchronized void eaafInitialize() throws InitializationException, ComponentInitializationException { + log.debug("Initializing OpenSAML 3.x ... "); + initialize(); + + log.debug("Injecting EAAF-specific configuration into OpenSAML 3.x ... "); + injectEaafSecurityProperty(); + injectEaafExtenstions(); + + XMLObjectProviderRegistrySupport.setParserPool(eaafSecuredBasicParserPool()); + + log.info("OpenSAML3.x with EAAF extensions initialized"); + + } + + private static void injectEaafSecurityProperty() { + ConfigurationService.register(EncryptionConfiguration.class, + EaafDefaultSecurityConfigurationBootstrap.buildEaafEncryptionConfiguration()); + + ConfigurationService.register(DecryptionConfiguration.class, + EaafDefaultSecurityConfigurationBootstrap.buildEaaftDecryptionConfiguration()); + + ConfigurationService.register(SignatureSigningConfiguration.class, + EaafDefaultSecurityConfigurationBootstrap.buildEaafSignatureSigningConfiguration()); + + ConfigurationService.register(SignatureValidationConfiguration.class, + EaafDefaultSecurityConfigurationBootstrap.buildEaafSignatureValidationConfiguration()); + + } + + private static void injectEaafExtenstions() { + XMLObjectProviderRegistrySupport.registerObjectProvider( + EaafRequestedAttribute.DEFAULT_ELEMENT_NAME, new EaafRequestedAttributeBuilder(), + new EaafRequestedAttributeMarshaller(), new EaafRequestedAttributeUnmarshaller()); + + XMLObjectProviderRegistrySupport.registerObjectProvider( + EaafRequestedAttributes.DEFAULT_ELEMENT_NAME, new EaafRequestedAttributesBuilder(), + new EaafRequestedAttributesMarshaller(), new EaafRequestedAttributesUnmarshaller()); + + } + + /** + * Build a secured OpenSAML 3.x XML parser-pool. + * + * @return {@link ParserPool} + * @throws ComponentInitializationException In case of an initialization error + */ + @Nonnull + private static ParserPool eaafSecuredBasicParserPool() throws ComponentInitializationException { + // Get parser pool manager + final BasicParserPool ppMgr = new BasicParserPool(); + // Note: this is necessary due to an unresolved Xerces deferred DOM issue/bug + ppMgr.setBuilderFeatures(getSecureDocumentBuilderFeatures()); + ppMgr.setNamespaceAware(true); + ppMgr.setIgnoreComments(true); + ppMgr.setExpandEntityReferences(false); + ppMgr.setXincludeAware(false); + ppMgr.initialize(); + return ppMgr; + } + + @Nonnull + private static Map<String, Boolean> getSecureDocumentBuilderFeatures() { + final Map<String, Boolean> features = new HashMap<>(); + features.put(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); + + // Ignore the external DTD completely + // Note: this is for Xerces only: + features.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", Boolean.FALSE); + // This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all + // XML entity attacks are prevented + // Xerces 2 only - + // http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl + features.put("http://apache.org/xml/features/disallow-doctype-decl", Boolean.TRUE); + + // If you can't completely disable DTDs, then at least do the following: + // Xerces 1 - + // http://xerces.apache.org/xerces-j/features.html#external-general-entities + // Xerces 2 - + // http://xerces.apache.org/xerces2-j/features.html#external-general-entities + features.put("http://xml.org/sax/features/external-general-entities", Boolean.FALSE); + + // Xerces 1 - + // http://xerces.apache.org/xerces-j/features.html#external-parameter-entities + // Xerces 2 - + // http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities + features.put("http://xml.org/sax/features/external-parameter-entities", Boolean.FALSE); + + return features; + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/reqattr/EaafRequestedAttributeImpl.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/reqattr/EaafRequestedAttributeImpl.java index e91ee19c..e391bb31 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/reqattr/EaafRequestedAttributeImpl.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/reqattr/EaafRequestedAttributeImpl.java @@ -23,14 +23,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.opensaml.common.impl.AbstractSAMLObject; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.schema.XSBooleanValue; -import org.opensaml.xml.util.AttributeMap; -import org.opensaml.xml.util.XMLObjectChildrenList; - import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.schema.XSBooleanValue; +import org.opensaml.core.xml.util.AttributeMap; +import org.opensaml.core.xml.util.XMLObjectChildrenList; +import org.opensaml.saml.common.AbstractSAMLObject; + public class EaafRequestedAttributeImpl extends AbstractSAMLObject implements EaafRequestedAttribute { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/reqattr/EaafRequestedAttributesImpl.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/reqattr/EaafRequestedAttributesImpl.java index eefc166b..9c251233 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/reqattr/EaafRequestedAttributesImpl.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/reqattr/EaafRequestedAttributesImpl.java @@ -23,13 +23,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.opensaml.common.impl.AbstractSAMLObject; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.util.IndexedXMLObjectChildrenList; - import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttributes; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.saml.common.AbstractSAMLObject; + public class EaafRequestedAttributesImpl extends AbstractSAMLObject implements EaafRequestedAttributes { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java index c0b015be..336741a0 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java @@ -29,18 +29,21 @@ import java.security.interfaces.RSAPrivateKey; import javax.annotation.PostConstruct; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; +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.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.EaafKeyStoreX509CredentialAdapter; import org.apache.commons.lang3.StringUtils; -import org.opensaml.xml.security.credential.Credential; -import org.opensaml.xml.security.credential.UsageType; -import org.opensaml.xml.security.x509.X509Credential; -import org.opensaml.xml.signature.Signature; -import org.opensaml.xml.signature.SignatureConstants; +import org.opensaml.security.credential.Credential; +import org.opensaml.security.credential.UsageType; +import org.opensaml.xmlsec.signature.Signature; +import org.opensaml.xmlsec.signature.support.SignatureConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -50,7 +53,10 @@ import org.springframework.core.io.ResourceLoader; public abstract class AbstractCredentialProvider { - @Autowired protected ResourceLoader resourceLoader; + @Autowired + protected ResourceLoader resourceLoader; + @Autowired + protected IConfiguration basicConfig; private static final Logger log = LoggerFactory.getLogger(AbstractCredentialProvider.class); @@ -127,24 +133,26 @@ public abstract class AbstractCredentialProvider { * @return Credentials * @throws CredentialsNotAvailableException In case of a credential error */ - public X509Credential getIdpMetaDataSigningCredential() throws CredentialsNotAvailableException { + public EaafX509Credential getIdpMetaDataSigningCredential() throws CredentialsNotAvailableException { try { final EaafKeyStoreX509CredentialAdapter credentials = new EaafKeyStoreX509CredentialAdapter(keyStore, - getMetadataKeyAlias(), getMetadataKeyPassword().toCharArray()); + getMetadataKeyAlias(), getMetadataKeyPassword().toCharArray(), getFriendlyName()); credentials.setUsageType(UsageType.SIGNING); - if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { - log.error(getFriendlyName() - + " Metadata Signing credentials is not found or contains no PrivateKey."); - throw new CredentialsNotAvailableException("config.27", - new Object[] { getFriendlyName() + " Assertion Signing credentials (Alias: " - + getMetadataKeyAlias() + ") is not found or contains no PrivateKey." }); - - } + credentials.setSignatureAlgorithmForSigning(Saml2Utils.getSignatureAlgorithm( + credentials, + basicConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_SIGNING_RSA_ALG, + PvpConstants.DEFAULT_SIGNING_METHODE_RSA), + basicConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_SIGNING_RSA_ALG, + PvpConstants.DEFAULT_SIGNING_METHODE_EC))); return credentials; - } catch (final Exception e) { - log.error("Failed to generate " + getFriendlyName() + " Metadata Signing credentials", e); - throw new CredentialsNotAvailableException("config.27", new Object[] { e.getMessage() }, e); + + } catch (final SamlSigningException e) { + throw new CredentialsNotAvailableException("internal.pvp.01", + new Object[] { getFriendlyName(), getMetadataKeyAlias() }, e); + } } @@ -154,25 +162,27 @@ public abstract class AbstractCredentialProvider { * @return Credentials * @throws CredentialsNotAvailableException In case of a credential error */ - public X509Credential getIdpAssertionSigningCredential() throws CredentialsNotAvailableException { + public EaafX509Credential getIdpAssertionSigningCredential() throws CredentialsNotAvailableException { try { final EaafKeyStoreX509CredentialAdapter credentials = new EaafKeyStoreX509CredentialAdapter(keyStore, - getSignatureKeyAlias(), getSignatureKeyPassword().toCharArray()); + getSignatureKeyAlias(), getSignatureKeyPassword().toCharArray(), getFriendlyName()); credentials.setUsageType(UsageType.SIGNING); - if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { - log.error(getFriendlyName() - + " Assertion Signing credentials is not found or contains no PrivateKey."); - throw new CredentialsNotAvailableException("config.27", - new Object[] { getFriendlyName() + " Assertion Signing credentials (Alias: " - + getSignatureKeyAlias() + ") is not found or contains no PrivateKey." }); - - } + credentials.setSignatureAlgorithmForSigning(Saml2Utils.getSignatureAlgorithm( + credentials, + basicConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_SIGNING_RSA_ALG, + PvpConstants.DEFAULT_SIGNING_METHODE_RSA), + basicConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_SIGNING_RSA_ALG, + PvpConstants.DEFAULT_SIGNING_METHODE_EC))); return credentials; + } catch (final Exception e) { - log.error("Failed to generate " + getFriendlyName() + " Assertion Signing credentials", e); - throw new CredentialsNotAvailableException("config.27", new Object[] { e.getMessage() }, e); + throw new CredentialsNotAvailableException("internal.pvp.01", + new Object[] { getFriendlyName(), getSignatureKeyAlias() }, e); + } } @@ -182,34 +192,18 @@ public abstract class AbstractCredentialProvider { * @return Credentials * @throws CredentialsNotAvailableException In case of a credential error */ - public X509Credential getIdpAssertionEncryptionCredential() + public EaafX509Credential getIdpAssertionEncryptionCredential() throws CredentialsNotAvailableException { - try { - // if no encryption key is configured return null - if (StringUtils.isEmpty(getEncryptionKeyAlias())) { - return null; - } - - final EaafKeyStoreX509CredentialAdapter credentials = new EaafKeyStoreX509CredentialAdapter(keyStore, - getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray()); - - credentials.setUsageType(UsageType.ENCRYPTION); - - if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { - log.error(getFriendlyName() - + " Assertion Encryption credentials is not found or contains no PrivateKey."); - throw new CredentialsNotAvailableException("config.27", - new Object[] { getFriendlyName() + " Assertion Encryption credentials (Alias: " - + getEncryptionKeyAlias() + ") is not found or contains no PrivateKey." }); - - } + // if no encryption key is configured return null + if (StringUtils.isEmpty(getEncryptionKeyAlias())) { + return null; + } - return credentials; + final EaafKeyStoreX509CredentialAdapter credentials = new EaafKeyStoreX509CredentialAdapter(keyStore, + getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray(), getFriendlyName()); + credentials.setUsageType(UsageType.ENCRYPTION); + return credentials; - } catch (final Exception e) { - log.error("Failed to generate " + getFriendlyName() + " Assertion Encryption credentials", e); - throw new CredentialsNotAvailableException("config.27", new Object[] { e.getMessage() }, e); - } } /** @@ -218,6 +212,7 @@ public abstract class AbstractCredentialProvider { * @param credentials Credentials for signing * @return OpenSAML Signature object */ + @Deprecated public static Signature getIdpSignature(final Credential credentials) { final PrivateKey privatekey = credentials.getPrivateKey(); final Signature signer = Saml2Utils.createSamlObject(Signature.class); @@ -250,7 +245,7 @@ public abstract class AbstractCredentialProvider { if (keyStore == null) { throw new EaafConfigurationException("module.00", - new Object[] {getFriendlyName(), "KeyStore initialization failed. Maybe wrong password"}); + new Object[] { getFriendlyName(), "KeyStore initialization failed. Maybe wrong password" }); } 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 1a282b55..8b1b041b 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 @@ -20,8 +20,13 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.utils; import java.io.IOException; +import java.security.PrivateKey; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateKey; import java.util.List; +import javax.annotation.Nonnull; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -31,35 +36,60 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.Validator; +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 org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.opensaml.common.xml.SAMLSchemaBuilder; -import org.opensaml.saml2.core.Attribute; -import org.opensaml.saml2.core.Status; -import org.opensaml.saml2.core.StatusCode; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.ws.soap.soap11.Body; -import org.opensaml.ws.soap.soap11.Envelope; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.XMLObjectBuilderFactory; -import org.opensaml.xml.io.Marshaller; -import org.opensaml.xml.io.MarshallingException; -import org.opensaml.xml.schema.XSString; -import org.opensaml.xml.schema.impl.XSStringBuilder; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.XMLObjectBuilderFactory; +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.schema.XSString; +import org.opensaml.core.xml.schema.impl.XSStringBuilder; +import org.opensaml.saml.common.SAMLObjectContentReference; +import org.opensaml.saml.common.xml.SAMLSchemaBuilder; +import org.opensaml.saml.common.xml.SAMLSchemaBuilder.SAML1Version; +import org.opensaml.saml.saml2.core.Attribute; +import org.opensaml.saml.saml2.core.Status; +import org.opensaml.saml.saml2.core.StatusCode; +import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.opensaml.security.SecurityException; +import org.opensaml.security.x509.X509Credential; +import org.opensaml.soap.soap11.Body; +import org.opensaml.soap.soap11.Envelope; +import org.opensaml.xmlsec.SecurityConfigurationSupport; +import org.opensaml.xmlsec.SignatureSigningConfiguration; +import org.opensaml.xmlsec.keyinfo.KeyInfoGenerator; +import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorFactory; +import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorManager; +import org.opensaml.xmlsec.keyinfo.NamedKeyInfoGeneratorManager; +import org.opensaml.xmlsec.keyinfo.impl.BasicKeyInfoGeneratorFactory; +import org.opensaml.xmlsec.signature.KeyInfo; +import org.opensaml.xmlsec.signature.SignableXMLObject; +import org.opensaml.xmlsec.signature.Signature; +import org.opensaml.xmlsec.signature.support.ContentReference; +import org.opensaml.xmlsec.signature.support.SignatureConstants; +import org.opensaml.xmlsec.signature.support.SignatureException; +import org.opensaml.xmlsec.signature.support.Signer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -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.reqattr.EaafRequestedAttribute; - public class Saml2Utils { private static final Logger log = LoggerFactory.getLogger(Saml2Utils.class); private static DocumentBuilder builder; + private static SAMLSchemaBuilder schemaBuilder; static { + schemaBuilder = new SAMLSchemaBuilder(SAML1Version.SAML_11); + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); @@ -73,16 +103,144 @@ 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> + * + * @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 + * @throws SamlSigningException In case of a signing error + */ + public static <T extends SignableXMLObject> T signSamlObject(@Nonnull T toSign, + @Nonnull EaafX509Credential signingCredential, boolean injectCertificate) throws SamlSigningException { + + try { + final String usedSigAlg = getSignatureAlgorithm(signingCredential, + PvpConstants.DEFAULT_SIGNING_METHODE_RSA, + PvpConstants.DEFAULT_SIGNING_METHODE_EC); + + final Signature signature = createSignature(signingCredential, usedSigAlg, injectCertificate); + toSign.setSignature(signature); + + final String digestAlgorithm = getDigestAlgorithm(usedSigAlg); + final List<ContentReference> contentReferences = signature.getContentReferences(); + if (!CollectionUtils.isEmpty(contentReferences)) { + ((SAMLObjectContentReference) contentReferences.get(0)).setDigestAlgorithm(digestAlgorithm); + + } else { + log.error("Unable to set DigestMethodAlgorithm - algorithm {} not set", digestAlgorithm); + + } + + log.trace("Marshall samlToken."); + XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(toSign).marshall(toSign); + + log.trace("Sign samlToken."); + Signer.signObject(signature); + + return toSign; + + } catch (final SignatureException | MarshallingException | SecurityException e) { + throw new SamlSigningException("internal.pvp.96", + new Object[] {signingCredential.getEntityId(), e.getMessage()}, 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 + * @return either the rsaSigAlgorithm or the ecSigAlgorithm + * @throws SamlSigningException In case of an unsupported credential + */ + public static String getSignatureAlgorithm(X509Credential credentials, + String rsaSigAlgorithm, String ecSigAlgorithm) throws SamlSigningException { + final PrivateKey privatekey = credentials.getPrivateKey(); + if (privatekey instanceof RSAPrivateKey) { + return rsaSigAlgorithm; + + } else if (privatekey instanceof ECPrivateKey) { + return ecSigAlgorithm; + + } else { + 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()}); + + } + } + + /** + * Select a digest algorithm for a already selected signing algorithm. + * + * @param signatureAlgorithmName Signing algorithm that will be used + * @return Digest algorithm identifier + */ + public static String getDigestAlgorithm(String signatureAlgorithmName) { + if (StringUtils.isBlank(signatureAlgorithmName)) { + return PvpConstants.DEFAULT_DIGESTMETHODE; + } + + final String canonicalAlgorithm = signatureAlgorithmName.trim(); + final String digestAlgorithm = PvpConstants.SIGNATURE_TO_DIGEST_ALGORITHM_MAP.get(canonicalAlgorithm); + if (null != digestAlgorithm) { + return digestAlgorithm; + + } + + log.warn("Signing algorithm: {} does not contain a known digist algorithm. Use: {} as default", + signatureAlgorithmName, PvpConstants.DEFAULT_DIGESTMETHODE); + return PvpConstants.DEFAULT_DIGESTMETHODE; + + } + + /** + * 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 + * @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 + KeyInfoGeneratorFactory keyInfoGenFac = null; + if (injectCertificate || credential.getPublicKey() instanceof ECPublicKey) { + final SignatureSigningConfiguration secConfiguration = SecurityConfigurationSupport + .getGlobalSignatureSigningConfiguration(); + final NamedKeyInfoGeneratorManager keyInfoManager = secConfiguration.getKeyInfoGeneratorManager(); + final KeyInfoGeneratorManager keyInfoGenManager = keyInfoManager.getDefaultManager(); + keyInfoGenFac = keyInfoGenManager.getFactory(credential); + + } else { + keyInfoGenFac = createKeyInfoWithoutCertificate(credential); + + } + + return keyInfoGenFac.newInstance(); + + } + + + /** * Create a SAML2 object. * - * @param <T> SAML2 object class + * @param <T> SAML2 object class * @param clazz object class * @return SAML2 object */ public static <T> T createSamlObject(final Class<T> clazz) { try { final XMLObjectBuilderFactory builderFactory = - org.opensaml.xml.Configuration.getBuilderFactory(); + XMLObjectProviderRegistrySupport.getBuilderFactory(); final QName defaultElementName = (QName) clazz.getDeclaredField("DEFAULT_ELEMENT_NAME").get(null); @@ -119,7 +277,7 @@ public class Saml2Utils { throws IOException, MarshallingException, TransformerException { final Document document = builder.newDocument(); final Marshaller out = - org.opensaml.xml.Configuration.getMarshallerFactory().getMarshaller(object); + XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(object); out.marshall(object, document); return document; } @@ -132,7 +290,7 @@ public class Saml2Utils { public static Status getSuccessStatus() { final Status status = Saml2Utils.createSamlObject(Status.class); final StatusCode statusCode = Saml2Utils.createSamlObject(StatusCode.class); - statusCode.setValue(StatusCode.SUCCESS_URI); + statusCode.setValue(StatusCode.SUCCESS); status.setStatusCode(statusCode); return status; } @@ -165,7 +323,7 @@ public class Saml2Utils { * @return */ public static Envelope buildSoap11Envelope(final XMLObject payload) { - final XMLObjectBuilderFactory bf = org.opensaml.xml.Configuration.getBuilderFactory(); + final XMLObjectBuilderFactory bf = XMLObjectProviderRegistrySupport.getBuilderFactory(); final Envelope envelope = (Envelope) bf.getBuilder(Envelope.DEFAULT_ELEMENT_NAME) .buildObject(Envelope.DEFAULT_ELEMENT_NAME); final Body body = @@ -211,7 +369,8 @@ public class Saml2Utils { */ public static void schemeValidation(final XMLObject xmlObject) throws Exception { try { - final Schema test = SAMLSchemaBuilder.getSAML11Schema(); + + final Schema test = schemaBuilder.getSAMLSchema(); final Validator val = test.newValidator(); final DOMSource source = new DOMSource(xmlObject.getDOM()); val.validate(source); @@ -227,11 +386,37 @@ public class Saml2Utils { private static XMLObject createAttributeValue(final QName attributeValueType, final String value) { - final XSStringBuilder stringBuilder = (XSStringBuilder) org.opensaml.xml.Configuration + final XSStringBuilder stringBuilder = (XSStringBuilder) XMLObjectProviderRegistrySupport .getBuilderFactory().getBuilder(XSString.TYPE_NAME); final XSString stringValue = stringBuilder.buildObject(attributeValueType, XSString.TYPE_NAME); stringValue.setValue(value); return stringValue; } + + private static Signature createSignature(X509Credential signingCredential, + String usedSigAlg, boolean injectCertificate) + throws SecurityException, SamlSigningException { + log.trace("Generating OpenSAML signature object ... "); + final Signature signature = (Signature) XMLObjectProviderRegistrySupport.getBuilderFactory() + .getBuilder(Signature.DEFAULT_ELEMENT_NAME) + .buildObject(Signature.DEFAULT_ELEMENT_NAME); + signature.setSigningCredential(signingCredential); + signature.setSignatureAlgorithm(usedSigAlg); + 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) { + final KeyInfoGeneratorFactory keyInfoGenFac = new BasicKeyInfoGeneratorFactory(); + ((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/validation/EaafUriCompare.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/EaafUriCompare.java index ca37d6e5..9015c40b 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/EaafUriCompare.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/EaafUriCompare.java @@ -19,10 +19,11 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.validation; -import org.opensaml.common.binding.decoding.URIComparator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import net.shibboleth.utilities.java.support.net.URIComparator; + public class EaafUriCompare implements URIComparator { private static final Logger log = LoggerFactory.getLogger(EaafUriCompare.class); 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 6497ce06..1591198c 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 @@ -22,41 +22,39 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.validation; import java.util.ArrayList; import java.util.List; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.security.MetadataCredentialResolver; -import org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver; -import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; -import org.opensaml.xml.security.keyinfo.KeyInfoProvider; -import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider; -import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider; -import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider; -import org.opensaml.xml.signature.SignatureTrustEngine; -import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; + +import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver; +import org.opensaml.saml.security.impl.MetadataCredentialResolver; +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.SignatureTrustEngine; +import org.opensaml.xmlsec.signature.support.impl.ExplicitKeySignatureTrustEngine; public class TrustEngineFactory { /** * Get OpenSAML2 TrustEngine. * - * @param provider Metadata provider + * @param mdResolver Metadata provider * @return */ public static SignatureTrustEngine getSignatureKnownKeysTrustEngine( - final MetadataProvider provider) { - MetadataCredentialResolver resolver; - - resolver = new MetadataCredentialResolver(provider); + final IPvp2MetadataProvider mdResolver) { + final MetadataCredentialResolver resolver = new MetadataCredentialResolver(); + resolver.setRoleDescriptorResolver(new PredicateRoleDescriptorResolver(mdResolver)); final List<KeyInfoProvider> keyInfoProvider = new ArrayList<>(); keyInfoProvider.add(new DSAKeyValueProvider()); keyInfoProvider.add(new RSAKeyValueProvider()); keyInfoProvider.add(new InlineX509DataProvider()); - final KeyInfoCredentialResolver keyInfoResolver = - new BasicProviderKeyInfoCredentialResolver(keyInfoProvider); - final ExplicitKeySignatureTrustEngine engine = - new ExplicitKeySignatureTrustEngine(resolver, keyInfoResolver); + new ExplicitKeySignatureTrustEngine(resolver, + new BasicProviderKeyInfoCredentialResolver(keyInfoProvider)); return engine; diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/AbstractMetadataSignatureFilter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/AbstractMetadataSignatureFilter.java index d1eb66a3..c28dd7fb 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/AbstractMetadataSignatureFilter.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/AbstractMetadataSignatureFilter.java @@ -23,22 +23,24 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import org.opensaml.saml2.metadata.EntitiesDescriptor; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.xml.XMLObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; 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.SignatureValidationException; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; +import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public abstract class AbstractMetadataSignatureFilter implements MetadataFilter { private static final Logger log = LoggerFactory.getLogger(AbstractMetadataSignatureFilter.class); @Override - public void doFilter(final XMLObject metadata) throws SignatureValidationException { + public XMLObject filter(@Nullable final XMLObject metadata) throws SignatureValidationException { try { if (metadata instanceof EntitiesDescriptor) { final EntitiesDescriptor entitiesDescriptor = (EntitiesDescriptor) metadata; @@ -68,6 +70,9 @@ public abstract class AbstractMetadataSignatureFilter implements MetadataFilter throw new SignatureValidationException(e); } + + return metadata; + } /** diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/PvpEntityCategoryFilter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/PvpEntityCategoryFilter.java index 66c3fb9e..efbeb7e5 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/PvpEntityCategoryFilter.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/PvpEntityCategoryFilter.java @@ -22,29 +22,28 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata; import java.util.ArrayList; import java.util.List; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.common.Extensions; -import org.opensaml.saml2.core.Attribute; -import org.opensaml.saml2.metadata.AttributeConsumingService; -import org.opensaml.saml2.metadata.EntitiesDescriptor; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.LocalizedString; -import org.opensaml.saml2.metadata.RequestedAttribute; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.saml2.metadata.ServiceName; -import org.opensaml.saml2.metadata.provider.FilterException; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.samlext.saml2mdattr.EntityAttributes; -import org.opensaml.xml.XMLObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import at.gv.egiz.eaaf.core.impl.data.Triple; import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpAttributeBuilder; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.ext.saml2mdattr.EntityAttributes; +import org.opensaml.saml.metadata.resolver.filter.FilterException; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; +import org.opensaml.saml.saml2.core.Attribute; +import org.opensaml.saml.saml2.metadata.AttributeConsumingService; +import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.Extensions; +import org.opensaml.saml.saml2.metadata.RequestedAttribute; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml.saml2.metadata.ServiceName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Metadata filter that inject requested attributes based on Metadata * EntityCategories. @@ -76,7 +75,7 @@ public class PvpEntityCategoryFilter implements MetadataFilter { * .XMLObject) */ @Override - public void doFilter(final XMLObject metadata) throws FilterException { + public XMLObject filter(final XMLObject metadata) throws FilterException { if (isUsed) { log.trace("Map PVP EntityCategory to single PVP Attributes ... "); @@ -109,8 +108,11 @@ public class PvpEntityCategoryFilter implements MetadataFilter { } else { log.trace("Filter to map PVP EntityCategory to single PVP Attributes is deactivated"); + } + return metadata; + } private void resolveEntityCategoriesToAttributes(final EntityDescriptor metadata) { @@ -190,7 +192,8 @@ public class PvpEntityCategoryFilter implements MetadataFilter { attributeService.setIndex(0); attributeService.setIsDefault(true); final ServiceName serviceName = Saml2Utils.createSamlObject(ServiceName.class); - serviceName.setName(new LocalizedString("Default Service", "en")); + serviceName.setValue("Default Service"); + serviceName.setXMLLang("en"); attributeService.getNames().add(serviceName); if (attrList != null && !attrList.isEmpty()) { 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 6dcc3234..73a11c49 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 @@ -23,20 +23,23 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.Validator; -import org.opensaml.common.xml.SAMLSchemaBuilder; -import org.opensaml.saml2.metadata.provider.FilterException; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.xml.XMLObject; +import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; + +import org.opensaml.core.xml.XMLObject; +import org.opensaml.saml.common.xml.SAMLSchemaBuilder; +import org.opensaml.saml.common.xml.SAMLSchemaBuilder.SAML1Version; +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; -import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; - public class SchemaValidationFilter implements MetadataFilter { private static final Logger log = LoggerFactory.getLogger(SchemaValidationFilter.class); private boolean isActive = true; + private static SAMLSchemaBuilder schemaBuilder = new SAMLSchemaBuilder(SAML1Version.SAML_11); + public SchemaValidationFilter() { } @@ -53,18 +56,17 @@ public class SchemaValidationFilter implements MetadataFilter { * .XMLObject) */ @Override - public void doFilter(final XMLObject arg0) throws FilterException { + public XMLObject filter(final XMLObject arg0) throws FilterException { String errString = null; if (isActive) { try { - final Schema test = SAMLSchemaBuilder.getSAML11Schema(); + final Schema test = schemaBuilder.getSAMLSchema(); final Validator val = test.newValidator(); final DOMSource source = new DOMSource(arg0.getDOM()); val.validate(source); log.info("Metadata Schema validation check done OK"); - return; } catch (final SAXException e) { if (log.isDebugEnabled() || log.isTraceEnabled()) { @@ -91,8 +93,10 @@ public class SchemaValidationFilter implements MetadataFilter { } else { log.info("Metadata Schema validation check is DEACTIVATED!"); + } + return arg0; } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java index 6d78b775..380e735c 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java @@ -24,28 +24,27 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.Validator; +import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; + import org.apache.commons.lang3.StringUtils; -import org.opensaml.common.SignableSAMLObject; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.common.xml.SAMLSchemaBuilder; +import org.opensaml.core.criterion.EntityIdCriterion; +import org.opensaml.saml.common.SignableSAMLObject; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.common.xml.SAMLSchemaBuilder; +import org.opensaml.saml.common.xml.SAMLSchemaBuilder.SAML1Version; +import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator; import org.opensaml.security.MetadataCriteria; -import org.opensaml.security.SAMLSignatureProfileValidator; -import org.opensaml.ws.message.MessageContext; +import org.opensaml.security.credential.UsageType; +import org.opensaml.security.criteria.UsageCriterion; import org.opensaml.ws.security.SecurityPolicyException; import org.opensaml.ws.security.SecurityPolicyRule; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.security.CriteriaSet; -import org.opensaml.xml.security.credential.UsageType; -import org.opensaml.xml.security.criteria.EntityIDCriteria; -import org.opensaml.xml.security.criteria.UsageCriteria; -import org.opensaml.xml.signature.SignatureTrustEngine; -import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; +import net.shibboleth.utilities.java.support.resolver.CriteriaSet; /** * Signature Policy for SAML2 redirect-binding. @@ -58,6 +57,8 @@ public abstract class AbstractRequestSignedSecurityPolicyRule implements Securit private static final Logger log = LoggerFactory.getLogger(AbstractRequestSignedSecurityPolicyRule.class); + private static SAMLSchemaBuilder schemaBuilder = new SAMLSchemaBuilder(SAML1Version.SAML_11); + private SignatureTrustEngine trustEngine = null; private QName peerEntityRole = null; @@ -136,9 +137,9 @@ public abstract class AbstractRequestSignedSecurityPolicyRule implements Securit } final CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add(new EntityIDCriteria(context.getInboundMessageIssuer())); + criteriaSet.add(new EntityIdCriterion(context.getInboundMessageIssuer())); criteriaSet.add(new MetadataCriteria(peerEntityRole, SAMLConstants.SAML20P_NS)); - criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + criteriaSet.add(new UsageCriterion(UsageType.SIGNING)); try { if (!trustEngine.validate(samlObj.getSignature(), criteriaSet)) { @@ -164,7 +165,7 @@ public abstract class AbstractRequestSignedSecurityPolicyRule implements Securit String err = null; try { - final Schema test = SAMLSchemaBuilder.getSAML11Schema(); + final Schema test = schemaBuilder.getSAMLSchema(); final Validator val = test.newValidator(); val.validate(new DOMSource(source)); log.debug("Schema validation check done OK"); 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 new file mode 100644 index 00000000..2672bef2 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java @@ -0,0 +1,23 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.verification; + +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 lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EaafMessageContextInitializationHandler extends AbstractMessageHandler<SAMLObject> { + + @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()); + + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpAuthRequestSignedRole.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpAuthRequestSignedRole.java deleted file mode 100644 index 42d7d6a1..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpAuthRequestSignedRole.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a - * cooperation between EGIZ, A-SIT Plus, 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 "Licence"); You may not use this work except in - * compliance with the Licence. You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software distributed under the Licence - * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the Licence for the specific language governing permissions and limitations under - * the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text file for details on the - * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative - * works that you distribute must include a readable copy of the "NOTICE" text file. -*/ - -package at.gv.egiz.eaaf.modules.pvp2.impl.verification; - -import java.util.List; - -import org.opensaml.common.binding.SAMLMessageContext; -import org.opensaml.saml2.binding.security.SAML2AuthnRequestsSignedRule; -import org.opensaml.ws.transport.http.HTTPInTransport; -import org.opensaml.xml.util.DatatypeHelper; - -public class PvpAuthRequestSignedRole extends SAML2AuthnRequestsSignedRule { - - @Override - protected boolean isMessageSigned(final SAMLMessageContext messageContext) { - // This handles HTTP-Redirect and HTTP-POST-SimpleSign bindings. - final HTTPInTransport inTransport = - (HTTPInTransport) messageContext.getInboundMessageTransport(); - - // Check signature parameter exists only once and is not empty - final List<String> sigParam = inTransport.getParameterValues("Signature"); - final boolean isValidSigned = sigParam.size() == 1 && !DatatypeHelper.isEmpty(sigParam.get(0)); - - // Check signature-algorithm parameter exists only once and is not empty - final List<String> sigAlgParam = inTransport.getParameterValues("SigAlg"); - final boolean isValidSigAlgExists = - sigAlgParam.size() == 1 && !DatatypeHelper.isEmpty(sigAlgParam.get(0)); - - // Check signature-content parameter exists only once and is not empty - final List<String> samlReqParam = inTransport.getParameterValues("SAMLRequest"); - final List<String> samlRespParam = inTransport.getParameterValues("SAMLResponse"); - final boolean isValidContent = - (samlReqParam.size() == 1 && !DatatypeHelper.isEmpty(samlReqParam.get(0)) - || samlRespParam.size() == 1 && !DatatypeHelper.isEmpty(samlRespParam.get(0))) - && !(samlReqParam.size() == 1 && samlRespParam.size() == 1); - - return isValidSigned && isValidSigAlgExists && isValidContent; - - } -} 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 new file mode 100644 index 00000000..e43d0423 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java @@ -0,0 +1,71 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.verification; + +import java.util.ArrayList; +import java.util.List; + +import org.opensaml.messaging.context.MessageContext; +import org.opensaml.messaging.handler.MessageHandler; +import org.opensaml.messaging.handler.MessageHandlerChain; +import org.opensaml.messaging.handler.MessageHandlerException; +import org.opensaml.saml.common.SAMLObject; + +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; + +@Slf4j +public class PvpSamlMessageHandlerChain implements MessageHandlerChain<SAMLObject> { + private final List<MessageHandler<SAMLObject>> handlers = new ArrayList<>(); + private boolean isInitialized = false; + + @Override + public void invoke(MessageContext<SAMLObject> messageContext) throws MessageHandlerException { + if (!isInitialized) { + throw new RuntimeException("Component: " + + PvpSamlMessageHandlerChain.class.getName() + " not initialized"); + + } + for (final MessageHandler<SAMLObject> handler : getHandlers()) { + log.trace("Initializing SAML message handler: {}", handler.getClass().getName()); + handler.invoke(messageContext); + + } + + } + + @Override + public boolean isInitialized() { + return isInitialized; + + } + + @Override + public void initialize() throws ComponentInitializationException { + if (!isInitialized) { + for (final MessageHandler<SAMLObject> handler : getHandlers()) { + log.trace("Initializing SAML message handler: {}", handler.getClass().getName()); + handler.initialize(); + + } + + isInitialized = true; + } + + } + + @Override + public List<MessageHandler<SAMLObject>> getHandlers() { + return handlers; + + } + + public void addHandler(MessageHandler<SAMLObject> handler) { + handlers.add(handler); + + } + + public void addHandlers(List<MessageHandler<SAMLObject>> handlerList) { + handlers.addAll(handlerList); + + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java index c7a43b0b..9c02221c 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java @@ -21,13 +21,12 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.verification; import javax.xml.namespace.QName; -import org.opensaml.common.SignableSAMLObject; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.signature.SignatureTrustEngine; - import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; +import org.opensaml.saml.common.SignableSAMLObject; +import org.opensaml.saml2.metadata.provider.MetadataProvider; +import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; + public class PvpSignedRequestPolicyRule extends AbstractRequestSignedSecurityPolicyRule { private IRefreshableMetadataProvider metadataProvider = null; 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 df91ce53..658dfe16 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 @@ -24,43 +24,44 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.Validator; -import org.apache.commons.lang3.StringUtils; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.common.xml.SAMLSchemaBuilder; -import org.opensaml.saml2.core.RequestAbstractType; -import org.opensaml.saml2.core.StatusResponseType; -import org.opensaml.saml2.metadata.IDPSSODescriptor; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.security.MetadataCriteria; -import org.opensaml.security.SAMLSignatureProfileValidator; -import org.opensaml.xml.security.CriteriaSet; -import org.opensaml.xml.security.credential.UsageType; -import org.opensaml.xml.security.criteria.EntityIDCriteria; -import org.opensaml.xml.security.criteria.UsageCriteria; -import org.opensaml.xml.signature.SignatureTrustEngine; -import org.opensaml.xml.validation.ValidationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - import at.gv.egiz.eaaf.core.exceptions.EaafProtocolException; import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataProvider; +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.SchemaValidationException; 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; -@Service("SAMLVerificationEngine") +import org.apache.commons.lang3.StringUtils; +import org.opensaml.core.criterion.EntityIdCriterion; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.common.xml.SAMLSchemaBuilder; +import org.opensaml.saml.common.xml.SAMLSchemaBuilder.SAML1Version; +import org.opensaml.saml.criterion.EntityRoleCriterion; +import org.opensaml.saml.criterion.ProtocolCriterion; +import org.opensaml.saml.saml2.core.RequestAbstractType; +import org.opensaml.saml.saml2.core.StatusResponseType; +import org.opensaml.saml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator; +import org.opensaml.security.credential.UsageType; +import org.opensaml.security.criteria.UsageCriterion; +import org.opensaml.xmlsec.signature.support.SignatureException; +import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; +import org.springframework.beans.factory.annotation.Autowired; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.resolver.CriteriaSet; + +@Slf4j public class SamlVerificationEngine { - private static final Logger log = LoggerFactory.getLogger(SamlVerificationEngine.class); + private static SAMLSchemaBuilder schemaBuilder = new SAMLSchemaBuilder(SAML1Version.SAML_11); @Autowired(required = true) - IPvpMetadataProvider metadataProvider; + IPvp2MetadataProvider metadataProvider; /** * Verify signature of a signed SAML2 object. @@ -72,7 +73,7 @@ public class SamlVerificationEngine { * @throws Exception In case of a general error */ public void verify(final InboundMessage msg, final SignatureTrustEngine sigTrustEngine) - throws org.opensaml.xml.security.SecurityException, Exception { + throws SecurityException, Exception { try { if (msg instanceof PvpSProfileRequest && ((PvpSProfileRequest) msg).getSamlRequest() instanceof RequestAbstractType) { @@ -135,7 +136,7 @@ public class SamlVerificationEngine { profileValidator.validate(samlObj.getSignature()); performSchemaValidation(samlObj.getDOM()); - } catch (final ValidationException e) { + } catch (final SignatureException e) { log.warn("Signature is not conform to SAML signature profile", e); throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); @@ -145,15 +146,16 @@ public class SamlVerificationEngine { } final CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add(new EntityIDCriteria(samlObj.getIssuer().getValue())); - criteriaSet.add(new MetadataCriteria(defaultElementName, SAMLConstants.SAML20P_NS)); - criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + criteriaSet.add(new EntityIdCriterion(samlObj.getIssuer().getValue())); + criteriaSet.add(new ProtocolCriterion(SAMLConstants.SAML20P_NS)); + criteriaSet.add(new EntityRoleCriterion(defaultElementName)); + criteriaSet.add(new UsageCriterion(UsageType.SIGNING)); try { if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) { throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); } - } catch (final org.opensaml.xml.security.SecurityException e) { + } catch (final org.opensaml.security.SecurityException e) { log.warn("PVP2x message signature validation FAILED.", e); throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); } @@ -166,7 +168,7 @@ public class SamlVerificationEngine { profileValidator.validate(samlObj.getSignature()); performSchemaValidation(samlObj.getDOM()); - } catch (final ValidationException e) { + } catch (final SignatureException e) { log.warn("Signature is not conform to SAML signature profile", e); throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); @@ -176,16 +178,16 @@ public class SamlVerificationEngine { } final CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add(new EntityIDCriteria(samlObj.getIssuer().getValue())); - criteriaSet - .add(new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); - criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + criteriaSet.add(new EntityIdCriterion(samlObj.getIssuer().getValue())); + criteriaSet.add(new ProtocolCriterion(SAMLConstants.SAML20P_NS)); + criteriaSet.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME)); + criteriaSet.add(new UsageCriterion(UsageType.SIGNING)); try { if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) { throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); } - } catch (final org.opensaml.xml.security.SecurityException e) { + } catch (final org.opensaml.security.SecurityException e) { log.warn("PVP2x message signature validation FAILED.", e); throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); } @@ -195,7 +197,7 @@ public class SamlVerificationEngine { String err = null; try { - final Schema test = SAMLSchemaBuilder.getSAML11Schema(); + final Schema test = schemaBuilder.getSAMLSchema(); final Validator val = test.newValidator(); val.validate(new DOMSource(source)); log.debug("Schema validation check done OK"); diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml index ee4d3864..2d5dc6ea 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml @@ -10,16 +10,19 @@ 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="PVPMetadataBuilder" - class="at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder" /> - - <bean id="PVPPOSTBinding" - class="at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding" /> + <bean id="pvpLogMessageSource" + class="at.gv.egiz.eaaf.modules.pvp2.impl.logging.PvpModuleMessageSource" /> - <bean id="PVPRedirectBinding" - class="at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding" /> + <bean id="PVPMetadataBuilder" + class="at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder" /> - <bean id="PVPSOAPBinding" - class="at.gv.egiz.eaaf.modules.pvp2.impl.binding.SoapBinding" /> + <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_core/src/main/resources/messages/pvp_messages.properties b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties new file mode 100644 index 00000000..6e647bd0 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties @@ -0,0 +1,12 @@ +internal.pvp.00=KeyStore: {0} Key with alias: {0} not found or contains no PrivateKey. +internal.pvp.01=KeyStore: {0} contains an unsupported key with alias: {1} +internal.pvp.02=PVP message contains no signature. + +internal.pvp.95=OpenSAML {0}-binding message {1} failed. Reason: {2} +internal.pvp.96=OpenSAML signing FAILED with key: {0}. Reason: {1} +internal.pvp.97=Key with EntityIdentifier: {0} has an unsupported type: {1} +internal.pvp.98=PVP module has an internal error. Reason: {0} +internal.pvp.99=PVP module has an generic internal error. + + + 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 new file mode 100644 index 00000000..6adce26e --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/PostBindingTest.java @@ -0,0 +1,448 @@ +package at.gv.egiz.eaaf.modules.pvp2.test.binding; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Base64; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; + +import at.gv.egiz.eaaf.core.api.IRequest; +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.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.PostBinding; +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 org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; +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; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.messaging.decoder.MessageDecodingException; +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.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 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; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({"/spring/test_eaaf_pvp.beans.xml"}) +@TestPropertySource(locations = {"/config/config_1.props"}) +public class PostBindingTest { + + public static final String HTTP_FORM_RELAYSTATE = "RelayState="; + public static final String HTTP_FORM_SAMLREQ = "SAMLRequest="; + public static final String HTTP_FORM_SAMLRESP = "SAMLResponse="; + + @Autowired private PostBinding bindingImpl; + @Autowired private DummyCredentialProvider credentialProvider; + @Autowired private DummyGuiBuilderConfigurationFactory guiBuilderFactory; + + protected MockHttpServletRequest httpReq; + protected MockHttpServletResponse httpResp; + protected IRequest pendingReq; + + @BeforeClass + public static void classInitializer() throws InitializationException, ComponentInitializationException { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * Test initializer. + * + */ + @Before + public void initialize() { + httpReq = new MockHttpServletRequest(); + httpResp = new MockHttpServletResponse(); + + pendingReq = new TestRequestImpl(); + + } + + @Test + public void checkCanHandle() { + httpReq.setMethod("POST"); + Assert.assertTrue("Wrong canHandle result", bindingImpl.handleDecode("Post", httpReq)); + Assert.assertFalse("Wrong canHandle result", bindingImpl.handleDecode("Redirect", httpReq)); + + httpReq.setMethod("GET"); + Assert.assertFalse("Wrong canHandle result", bindingImpl.handleDecode("Post", httpReq)); + Assert.assertFalse("Wrong canHandle result", bindingImpl.handleDecode("Redirect", httpReq)); + } + + @Test + public void decodeRequestSuccess() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + 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/AuthRequest_with_sig_1.xml"))); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); + + + final InboundMessageInterface msg = + bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, 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()); + + } + + @Test + public void decodeRequestSuccessWithRelayState() throws MessageDecodingException, SecurityException, + IOException, Pvp2Exception { + 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"))); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); + httpReq.addParameter("RelayState", relayState); + + final IPvp2MetadataProvider metadataProvider = null; + + final boolean isSpEndPoint = false; + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + + final InboundMessageInterface msg = + bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, 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.assertFalse("Wrong isVerified flag", msg.isVerified()); + + } + + @Test + public void decodeResponseSuccess() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + 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"))); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); + + + final InboundMessageInterface msg = + bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, 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()); + + } + + @Test + public void decodeResponseSuccessWithRelayState() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + 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 = null; + + final boolean isSpEndPoint = false; + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + + final InboundMessageInterface msg = + bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, 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("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()); + + } + + @Test + public void encodeRequestSuccess() throws MessageDecodingException, SecurityException, + MessageEncodingException, XMLParserException, UnmarshallingException, + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = null; + guiBuilderFactory.setVelocityBuilderConfig(createDummyGuiConfig()); + final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + + bindingImpl.encodeRequest(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); + + //validate + Assert.assertEquals("http StatusCode", 200, httpResp.getStatus()); + Assert.assertNotNull("PVP msg is null", httpResp.getContentLength()); + + Assert.assertEquals("ContentType", "text/html", 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()); + + Assert.assertFalse("RelayState parameter", http.contains(HTTP_FORM_RELAYSTATE)); + + Assert.assertTrue("SAMLRequest parameter", http.contains(HTTP_FORM_SAMLREQ)); + final String httpSamlReq = extractParamFromHttpForm(http, HTTP_FORM_SAMLREQ); + checkSamlMessageSigned(httpSamlReq); + + } + + @Test + public void encodeRequestSuccessEcdsa() throws MessageDecodingException, SecurityException, + MessageEncodingException, XMLParserException, UnmarshallingException, + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = null; + guiBuilderFactory.setVelocityBuilderConfig(createDummyGuiConfig()); + final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + + bindingImpl.encodeRequest(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpAssertionSigningCredential(), pendingReq); + + //validate + Assert.assertEquals("http StatusCode", 200, httpResp.getStatus()); + Assert.assertNotNull("PVP msg is null", httpResp.getContentLength()); + + Assert.assertEquals("ContentType", "text/html", 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()); + + Assert.assertFalse("RelayState parameter", http.contains(HTTP_FORM_RELAYSTATE)); + + Assert.assertTrue("SAMLRequest parameter", http.contains(HTTP_FORM_SAMLREQ)); + final String httpSamlReq = extractParamFromHttpForm(http, HTTP_FORM_SAMLREQ); + checkSamlMessageSigned(httpSamlReq); + + } + + @Test + public void encodeRequestSuccessWithRelayState() throws MessageDecodingException, SecurityException, + MessageEncodingException, XMLParserException, UnmarshallingException, + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = RandomStringUtils.randomAlphabetic(10); + guiBuilderFactory.setVelocityBuilderConfig(createDummyGuiConfig()); + final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + + bindingImpl.encodeRequest(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); + + + //validate + Assert.assertEquals("http StatusCode", 200, httpResp.getStatus()); + Assert.assertNotNull("PVP msg is null", httpResp.getContentLength()); + + Assert.assertEquals("ContentType", "text/html", 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()); + + Assert.assertTrue("RelayState parameter", http.contains(HTTP_FORM_RELAYSTATE)); + final String httpRelayState = extractParamFromHttpForm(http, HTTP_FORM_RELAYSTATE); + Assert.assertEquals("Wrong RelayState", relayState, httpRelayState); + + Assert.assertTrue("SAMLRequest parameter", http.contains(HTTP_FORM_SAMLREQ)); + final String httpSamlReq = extractParamFromHttpForm(http, HTTP_FORM_SAMLREQ); + checkSamlMessageSigned(httpSamlReq); + + } + + @Test + public void encodeResponseSuccessWithRelayState() throws MessageDecodingException, SecurityException, + MessageEncodingException, XMLParserException, UnmarshallingException, + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = RandomStringUtils.randomAlphabetic(10); + guiBuilderFactory.setVelocityBuilderConfig(createDummyGuiConfig()); + final StatusResponseType authnReq = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/Response_without_sig_1.xml")); + + bindingImpl.encodeResponse(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); + + + //validate + Assert.assertEquals("http StatusCode", 200, httpResp.getStatus()); + Assert.assertNotNull("PVP msg is null", httpResp.getContentLength()); + + Assert.assertEquals("ContentType", "text/html", 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()); + + Assert.assertTrue("RelayState parameter", http.contains(HTTP_FORM_RELAYSTATE)); + final String httpRelayState = extractParamFromHttpForm(http, HTTP_FORM_RELAYSTATE); + Assert.assertEquals("Wrong RelayState", relayState, httpRelayState); + + Assert.assertTrue("SAMLRequest parameter", http.contains(HTTP_FORM_SAMLRESP)); + final String httpSamlReq = extractParamFromHttpForm(http, HTTP_FORM_SAMLRESP); + checkSamlMessageSigned(httpSamlReq); + + } + + @Test + public void encodeResponseSuccess() throws MessageDecodingException, SecurityException, + MessageEncodingException, XMLParserException, UnmarshallingException, + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = null; + guiBuilderFactory.setVelocityBuilderConfig(createDummyGuiConfig()); + final StatusResponseType authnReq = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + PostBindingTest.class.getResourceAsStream("/data/Response_without_sig_1.xml")); + + bindingImpl.encodeResponse(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); + + + //validate + Assert.assertEquals("http StatusCode", 200, httpResp.getStatus()); + Assert.assertNotNull("PVP msg is null", httpResp.getContentLength()); + + Assert.assertEquals("ContentType", "text/html", 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()); + + Assert.assertFalse("RelayState parameter", http.contains(HTTP_FORM_RELAYSTATE)); + + Assert.assertTrue("SAMLRequest parameter", http.contains(HTTP_FORM_SAMLRESP)); + final String httpSamlReq = extractParamFromHttpForm(http, HTTP_FORM_SAMLRESP); + checkSamlMessageSigned(httpSamlReq); + + } + + private IVelocityGuiBuilderConfiguration createDummyGuiConfig() { + return new IVelocityGuiBuilderConfiguration() { + + @Override + public Map<String, Object> getViewParameters() { + return null; + } + + @Override + public String getViewName() { + return "SAML2 Post-Binding"; + } + + @Override + public String getDefaultContentType() { + return null; + } + + @Override + public InputStream getTemplate(String viewName) { + return PostBindingTest.class.getResourceAsStream("/data/pvp_postbinding_template.html"); + } + + @Override + public String getClasspathTemplateDir() { + return null; + + } + }; + } + + private void checkSamlMessageSigned(String b64Msg) throws ParserConfigurationException, + SAXException, IOException, UnmarshallingException { + final Element httpSamlReqElment = DomUtils.parseXmlNonValidating( + new ByteArrayInputStream(Base64.getDecoder().decode(b64Msg))); + + final UnmarshallerFactory unmarshallerFactory = XMLObjectProviderRegistrySupport.getUnmarshallerFactory(); + final Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(httpSamlReqElment); + final SignableSAMLObject msg = (SignableSAMLObject) unmarshaller.unmarshall(httpSamlReqElment); + Assert.assertTrue("SAML msg not signed", msg.isSigned()); + + } + + private String extractParamFromHttpForm(String http, String httpFormRelaystate) { + final int startIndex = http.indexOf(httpFormRelaystate) + httpFormRelaystate.length(); + final int endIndex = http.indexOf("\"", startIndex); + return http.substring(startIndex, endIndex); + + } + +} 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 new file mode 100644 index 00000000..80dfc400 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java @@ -0,0 +1,490 @@ +package at.gv.egiz.eaaf.modules.pvp2.test.binding; + +import java.io.IOException; +import java.net.URLDecoder; +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.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.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare; +import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; +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; +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.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 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; + +@RunWith(SpringJUnit4ClassRunner.class) +@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_REDIRECT_SIGALG = "SigAlg="; + public static final String HTTP_REDIRECT_SIGNATURE = "Signature="; + + @Autowired private RedirectBinding bindingImpl; + @Autowired private DummyCredentialProvider credentialProvider; + + protected MockHttpServletRequest httpReq; + protected MockHttpServletResponse httpResp; + protected IRequest pendingReq; + + @BeforeClass + public static void classInitializer() throws InitializationException, ComponentInitializationException { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * Test initializer. + * + */ + @Before + public void initialize() { + httpReq = new MockHttpServletRequest(); + httpResp = new MockHttpServletResponse(); + + pendingReq = new TestRequestImpl(); + + } + + @Test + public void checkCanHandle() { + httpReq.setMethod("POST"); + Assert.assertFalse("Wrong canHandle result", bindingImpl.handleDecode("Post", httpReq)); + Assert.assertFalse("Wrong canHandle result", bindingImpl.handleDecode("Redirect", httpReq)); + + httpReq.setMethod("GET"); + Assert.assertFalse("Wrong canHandle result", bindingImpl.handleDecode("Post", httpReq)); + Assert.assertTrue("Wrong canHandle result", bindingImpl.handleDecode("Redirect", httpReq)); + } + + @Test + public void decodeRequestSuccess() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + final String serviceUrl = "http://testservice.org"; + + final IPvp2MetadataProvider metadataProvider = 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=="); + + + + + final InboundMessageInterface msg = + bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, 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()); + + } + + @Ignore + @Test + public void decodeRequestSuccessWithRelayState() throws MessageDecodingException, + SecurityException, IOException, Pvp2Exception { + final String serviceUrl = "http://testservice.org"; + final String relayState = RandomStringUtils.randomAlphanumeric(10); + + final String b64AuthnReq = Base64.getEncoder().encodeToString(IOUtils.toByteArray( + RedirectBindingTest.class.getResourceAsStream("/data/AuthRequest_with_sig_1.xml"))); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); + httpReq.addParameter("RelayState", relayState); + + final IPvp2MetadataProvider metadataProvider = null; + + final boolean isSpEndPoint = false; + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + + final InboundMessageInterface msg = + bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, 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.assertFalse("Wrong isVerified flag", msg.isVerified()); + + } + + @Ignore + @Test + public void decodeResponseSuccess() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception { + 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( + RedirectBindingTest.class.getResourceAsStream("/data/Response_with_sig_1.xml"))); + httpReq.setMethod("POST"); + httpReq.addParameter("SAMLRequest", b64AuthnReq); + + + final InboundMessageInterface msg = + bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, 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()); + + } + + @Ignore + @Test + public void decodeResponseSuccessWithRelayState() throws MessageDecodingException, SecurityException, + IOException, Pvp2Exception { + 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); + + final IPvp2MetadataProvider metadataProvider = null; + + final boolean isSpEndPoint = false; + final URIComparator comparator = new EaafUriCompare(serviceUrl); + + + final InboundMessageInterface msg = + bindingImpl.decode(httpReq, httpResp, metadataProvider, isSpEndPoint, 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("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()); + + } + + @Test + public void encodeRequestSuccess() throws MessageDecodingException, SecurityException, + MessageEncodingException, XMLParserException, UnmarshallingException, + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = null; + final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + RedirectBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + + bindingImpl.encodeRequest(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); + + //validate + Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); + Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); + + Assert.assertNull("ContentType", httpResp.getContentType()); + Assert.assertEquals("Encoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String locationHeader = httpResp.getHeader("Location"); + Assert.assertNotNull("Location header is null", locationHeader); + Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); + + Assert.assertTrue("Wrong redirect URL", + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLREQ)); + + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLREQ, 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); + 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); + Assert.assertNotNull("Saml signature null", samlSig); + Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); + + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, false); + Assert.assertNull("RelayState parameter", respRelayState); + + } + + + @Test + public void encodeRequestSuccessEcdsa() throws MessageDecodingException, SecurityException, + MessageEncodingException, XMLParserException, UnmarshallingException, + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = null; + final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + RedirectBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + + bindingImpl.encodeRequest(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpAssertionSigningCredential(), pendingReq); + + //validate + //validate + Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); + Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); + + Assert.assertNull("ContentType", httpResp.getContentType()); + Assert.assertEquals("Encoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String locationHeader = httpResp.getHeader("Location"); + Assert.assertNotNull("Location header is null", locationHeader); + Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); + + Assert.assertTrue("Wrong redirect URL", + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLREQ)); + + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLREQ, 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); + 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); + Assert.assertNotNull("Saml signature null", samlSig); + Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); + + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, false); + Assert.assertNull("RelayState parameter", respRelayState); + + + } + + @Test + public void encodeRequestSuccessWithRelayState() throws MessageDecodingException, SecurityException, + MessageEncodingException, XMLParserException, UnmarshallingException, + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = RandomStringUtils.randomAlphabetic(10); + final RequestAbstractType authnReq = (RequestAbstractType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + RedirectBindingTest.class.getResourceAsStream("/data/AuthRequest_without_sig_1.xml")); + + bindingImpl.encodeRequest(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); + + + //validate + Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); + Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); + + Assert.assertNull("ContentType", httpResp.getContentType()); + Assert.assertEquals("Encoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String locationHeader = httpResp.getHeader("Location"); + Assert.assertNotNull("Location header is null", locationHeader); + Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); + + Assert.assertTrue("Wrong redirect URL", + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLREQ)); + + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLREQ, 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); + 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); + Assert.assertNotNull("Saml signature null", samlSig); + Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); + + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, 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 { + + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = RandomStringUtils.randomAlphabetic(10); + final StatusResponseType authnReq = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + RedirectBindingTest.class.getResourceAsStream("/data/Response_without_sig_1.xml")); + + bindingImpl.encodeResponse(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); + + + //validate + Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); + Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); + + Assert.assertNull("ContentType", httpResp.getContentType()); + Assert.assertEquals("Encoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String locationHeader = httpResp.getHeader("Location"); + Assert.assertNotNull("Location header is null", locationHeader); + Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); + + Assert.assertTrue("Wrong redirect URL", + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLRESP)); + + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLRESP, 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); + 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); + Assert.assertNotNull("Saml signature null", samlSig); + Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); + + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, false); + Assert.assertNotNull("RelayState parameter", respRelayState); + Assert.assertEquals("RelayState not match", relayState, + URLDecoder.decode(respRelayState, "UTF-8")); + + } + + @Test + public void encodeResponseSuccess() throws MessageDecodingException, SecurityException, + MessageEncodingException, XMLParserException, UnmarshallingException, + CredentialsNotAvailableException, ParserConfigurationException, SAXException, IOException, Pvp2Exception { + + //build test data + final String serviceUrl = "http://testservice.org"; + final String relayState = null; + final StatusResponseType authnReq = (StatusResponseType) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + RedirectBindingTest.class.getResourceAsStream("/data/Response_without_sig_1.xml")); + + bindingImpl.encodeResponse(httpReq, httpResp, authnReq, serviceUrl, relayState, + credentialProvider.getIdpMetaDataSigningCredential(), pendingReq); + + + //validate + Assert.assertEquals("http StatusCode", 302, httpResp.getStatus()); + Assert.assertEquals("PVP msg is null", 0, httpResp.getContentLength()); + + Assert.assertNull("ContentType", httpResp.getContentType()); + Assert.assertEquals("Encoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String locationHeader = httpResp.getHeader("Location"); + Assert.assertNotNull("Location header is null", locationHeader); + Assert.assertFalse("Location header is empty", locationHeader.isEmpty()); + + Assert.assertTrue("Wrong redirect URL", + locationHeader.startsWith(serviceUrl + "?" + HTTP_FORM_SAMLRESP)); + + final String respSamlMsg = checkMessagePart(locationHeader, HTTP_FORM_SAMLRESP, 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); + 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); + Assert.assertNotNull("Saml signature null", samlSig); + Assert.assertFalse("Saml signature is empty", samlSig.isEmpty()); + + final String respRelayState = checkMessagePart(locationHeader, HTTP_FORM_RELAYSTATE, false); + Assert.assertNull("RelayState parameter", respRelayState); + + } + + private String checkMessagePart(String locationHeader, String httpFormSamlreq, boolean isRequired) { + final int startIndex = locationHeader.indexOf(httpFormSamlreq); + int endIndex = locationHeader.indexOf("&", startIndex); + + if (isRequired && startIndex == -1) { + Assert.fail("Element: " + httpFormSamlreq + " NOT found"); + + } else if (startIndex == -1) { + return null; + + } + + if (endIndex == -1) { + endIndex = locationHeader.length(); + + } + + return locationHeader.substring(startIndex + httpFormSamlreq.length(), endIndex); + + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/dummy/DummyCredentialProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/dummy/DummyCredentialProvider.java new file mode 100644 index 00000000..6930790d --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/dummy/DummyCredentialProvider.java @@ -0,0 +1,70 @@ +package at.gv.egiz.eaaf.modules.pvp2.test.dummy; + +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; + +import org.springframework.beans.factory.annotation.Autowired; + +public class DummyCredentialProvider extends AbstractCredentialProvider { + + @Autowired IConfiguration basicConfig; + + public static final String KEYSTORE_PATH = "keystore.path"; + public static final String KEYSTORE_PASSWORD = "keystore.pass"; + + public static final String KEY_METADATA_ALIAS = "key.metadata.alias"; + public static final String KEY_METADATA_PASSWORD = "key.metadata.pass"; + + public static final String KEY_SIGNING_ALIAS = "key.sig.alias"; + public static final String KEY_SIGNING_PASSWORD = "key.sig.pass"; + + public static final String KEY_ENCRYPTION_ALIAS = "key.enc.alias"; + public static final String KEY_ENCRYPTION_PASSWORD = "key.enc.pass"; + + @Override + public String getFriendlyName() { + return "jUnit test credential provider"; + } + + @Override + public String getKeyStoreFilePath() throws EaafException { + return basicConfig.getBasicConfiguration(KEYSTORE_PATH); + } + + @Override + public String getKeyStorePassword() { + return basicConfig.getBasicConfiguration(KEYSTORE_PASSWORD); + } + + @Override + public String getMetadataKeyAlias() { + return basicConfig.getBasicConfiguration(KEY_METADATA_ALIAS); + } + + @Override + public String getMetadataKeyPassword() { + return basicConfig.getBasicConfiguration(KEY_METADATA_PASSWORD); + } + + @Override + public String getSignatureKeyAlias() { + return basicConfig.getBasicConfiguration(KEY_SIGNING_ALIAS); + } + + @Override + public String getSignatureKeyPassword() { + return basicConfig.getBasicConfiguration(KEY_SIGNING_PASSWORD); + } + + @Override + public String getEncryptionKeyAlias() { + return basicConfig.getBasicConfiguration(KEY_ENCRYPTION_ALIAS); + } + + @Override + public String getEncryptionKeyPassword() { + return basicConfig.getBasicConfiguration(KEY_ENCRYPTION_PASSWORD); + } + +} 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 new file mode 100644 index 00000000..74b805ba --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/config/config_1.props @@ -0,0 +1,8 @@ +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=
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/AuthRequest_with_sig_1.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/AuthRequest_with_sig_1.xml new file mode 100644 index 00000000..f9de11c4 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/AuthRequest_with_sig_1.xml @@ -0,0 +1,38 @@ +<?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> + <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/2000/09/xmldsig#rsa-sha1"/> + <ds:Reference URI="#_aeebfae3ce681fe3ddcaf213a42f01d3"> + <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/2000/09/xmldsig#sha1"/> + <ds:DigestValue>sBVJQf9b+QIxRfH8YuTbF6hBrf4=</ds:DigestValue> + </ds:Reference> + </ds:SignedInfo> + <ds:SignatureValue>JK68H5XqmD2OEA8O/UCZFenVj0TrvauPhaKJt73pbHbi//hO1hBcRQbV2Qg3gQ11EcJ9Q+TM3TCe9nT6tdU/z7ry3qdZvlOfrkMF13fY4HOIuvB9AcySdxq2yKA3V5O9sLhf5S9qCyx9lMnTARC7wkVs4j2Pv00R6P/iROOHD5ryGF2J0FdtMp9VqhvQJ9yRGM2lTduF98MqxWA2EMk6AMo7qij0Bvha1B2OyFSU9HM3fyfRQpXDeiLnKHcjLpzu5TDNkKrP75c7vv85DDr7s2I0p74nAOVLMuLau5tEQ91Crk9QoqoqqEecKWcNJDXTO9MahCQw77hUDL1WOEMFFg==</ds:SignatureValue> + <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:Signature> + <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_core/src/test/resources/data/AuthRequest_without_sig_1.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/AuthRequest_without_sig_1.xml new file mode 100644 index 00000000..ef35ea92 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/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_core/src/test/resources/data/Response_with_sig_1.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/Response_with_sig_1.xml new file mode 100644 index 00000000..2654f2e8 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/Response_with_sig_1.xml @@ -0,0 +1,81 @@ +<?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> + <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=""> + <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#"> + <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/> + </ds:Transform> + </ds:Transforms> + <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> + <ds:DigestValue>fCE31ZeXZybQLOuNQBePLjFrCtKdvCmeyJ1tUW/ghtA=</ds:DigestValue> + </ds:Reference> + </ds:SignedInfo> + <ds:SignatureValue>vUFR3YPk5wiBJnrLh6Er7V46FNDMuB5Jcu73Rw7tipgr+bnV0reRNcZ5TGT+VMjNhtKJMcqgjrQWJ6tACe1r0mzhpRSVQkw7yFkTvIhQHX1a08yqJ4yy3qiN13ctDo4VgP9qHUim7b797oOKNhRXFk+2GJA5hRcpRliUjhBlzTYrxpkY5NcYDRhDPlvMx+l11oa1iDGuAylN+ty4h3P4fIoIgL9Tz1m3l65LqkV5RBc6avSeHw9OASMigPsjd5b0IBvhvJ611xLgzC1BOtJshiw1k/p8alv8TaUmYZ/kJbRN1tuTBL129edbS0Rz0faT0tniF42QHteJ214brK3rCg==</ds:SignatureValue> + <ds:KeyInfo> + <ds:KeyValue> + <ds:RSAKeyValue> + <ds:Modulus>xRE83dJy1dj+KVBp5Syo91fjGeG1MmJDSuTZ5MwdDzvIZrbK3YPh0jbJz4lOSrw9urRacavZX4m2 +XAKfSRxaowP3GqTh3Ew4WJE7yXEnWiic7bUz8uMIr020bsvqHCvY48+oPARbz/cEOf5NgMBWqo9E +nibdIyU5+AmfFzDaMwNocJEANoXrjLTpduCHvT0Qt/wH+7rVdgjX1djMrBhyMWs7GQyIBRfuf58m +8kdcoiMSm9AWA4d4GzXch+bi1QRzj+Ib80DeWdcXP3Hc6pcyp/+L+hya2jZ9NMS8yup6xuoAeh7w +6JNpfE9QnO3/CPrDZTtmjPK2OIRkhgn4Yi+iBQ==</ds:Modulus> + <ds:Exponent>AQAB</ds:Exponent> + </ds:RSAKeyValue> + </ds:KeyValue> + </ds:KeyInfo> + </ds:Signature> + <saml2p:Status> + <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> + </saml2p:Status> + <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> +</saml2p:Response> 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 new file mode 100644 index 00000000..3607cbc4 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/Response_without_sig_1.xml @@ -0,0 +1,52 @@ +<?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> + <saml2p:Status> + <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> + </saml2p:Status> + <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> +</saml2p:Response> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/junit.jks b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/junit.jks Binary files differnew file mode 100644 index 00000000..b5262cb8 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/junit.jks diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_postbinding_template.html b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_postbinding_template.html new file mode 100644 index 00000000..a0d31907 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_postbinding_template.html @@ -0,0 +1,3 @@ +#if($RelayState)RelayState=${RelayState}"}#end +#if($SAMLRequest)SAMLRequest=${SAMLRequest}"}#end +#if($SAMLResponse)SAMLResponse=${SAMLResponse}"}#end
\ No newline at end of file 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 new file mode 100644 index 00000000..de3cfbd1 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml @@ -0,0 +1,22 @@ +<?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" /> + +</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 new file mode 100644 index 00000000..f261e893 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_pvp.beans.xml @@ -0,0 +1,29 @@ +<?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"/> + + <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 |