From d41afe91ee59daf6b5f5037cecac52900fe2ccb2 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 31 Jan 2020 20:41:54 +0100 Subject: a lot of more OpenSAML3 refactoring staff This version is also NOT stable! --- eaaf_modules/eaaf_module_pvp2_core/pom.xml | 16 +- .../at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java | 33 +- .../eaaf/modules/pvp2/api/binding/IDecoder.java | 9 +- .../eaaf/modules/pvp2/api/binding/IEncoder.java | 18 +- .../pvp2/api/credential/EaafX509Credential.java | 25 ++ .../pvp2/api/metadata/IPvp2MetadataProvider.java | 51 +++ .../pvp2/api/metadata/IPvpMetadataProvider.java | 64 --- .../pvp2/exception/SamlBindingException.java | 12 + .../pvp2/exception/SamlSigningException.java | 17 + .../modules/pvp2/impl/binding/AbstractBinding.java | 108 +++++ .../modules/pvp2/impl/binding/PostBinding.java | 220 +++++---- .../modules/pvp2/impl/binding/RedirectBinding.java | 376 ++++++++++------ .../modules/pvp2/impl/binding/SoapBinding.java | 203 +++++---- .../pvp2/impl/builder/CitizenTokenBuilder.java | 6 +- .../pvp2/impl/builder/PvpMetadataBuilder.java | 10 +- .../pvp2/impl/builder/SamlAttributeGenerator.java | 6 +- .../reqattr/EaafExtensionImplementation.java | 2 +- .../reqattr/EaafRequestExtensionBuilder.java | 8 +- .../reqattr/EaafRequestedAttributeBuilder.java | 4 +- .../reqattr/EaafRequestedAttributeMarshaller.java | 17 +- .../EaafRequestedAttributeUnmarshaller.java | 15 +- .../reqattr/EaafRequestedAttributesBuilder.java | 4 +- .../reqattr/EaafRequestedAttributesMarshaller.java | 2 +- .../EaafRequestedAttributesUnmarshaller.java | 8 +- .../pvp2/impl/logging/PvpModuleMessageSource.java | 17 + .../modules/pvp2/impl/message/InboundMessage.java | 18 +- .../pvp2/impl/message/PvpSProfileRequest.java | 11 +- .../pvp2/impl/message/PvpSProfileResponse.java | 11 +- .../metadata/AbstractChainingMetadataProvider.java | 253 +++++------ .../pvp2/impl/metadata/MetadataFilterChain.java | 76 ---- .../pvp2/impl/metadata/SimpleMetadataProvider.java | 231 ---------- .../pvp2/impl/metadata/SimpleMetadataResolver.java | 243 ++++++++++ .../pvp2/impl/opensaml/EaafHttpPostDecoder.java | 77 ++++ .../opensaml/EaafHttpRedirectDeflateDecoder.java | 71 +++ .../EaafKeyStoreX509CredentialAdapter.java | 58 ++- .../opensaml/HttpPostEncoderWithOwnTemplate.java | 56 +-- .../opensaml/StringRedirectDeflateEncoder.java | 33 +- .../initialize/EaafDefaultSaml2Bootstrap.java | 88 ---- .../EaafDefaultSecurityConfigurationBootstrap.java | 218 +++++---- .../initialize/EaafOpenSaml3xInitializer.java | 156 +++++++ .../impl/reqattr/EaafRequestedAttributeImpl.java | 12 +- .../impl/reqattr/EaafRequestedAttributesImpl.java | 8 +- .../impl/utils/AbstractCredentialProvider.java | 109 +++-- .../eaaf/modules/pvp2/impl/utils/Saml2Utils.java | 235 ++++++++-- .../pvp2/impl/validation/EaafUriCompare.java | 3 +- .../pvp2/impl/validation/TrustEngineFactory.java | 36 +- .../metadata/AbstractMetadataSignatureFilter.java | 19 +- .../metadata/PvpEntityCategoryFilter.java | 41 +- .../metadata/SchemaValidationFilter.java | 22 +- .../AbstractRequestSignedSecurityPolicyRule.java | 33 +- .../EaafMessageContextInitializationHandler.java | 23 + .../verification/PvpAuthRequestSignedRole.java | 57 --- .../verification/PvpSamlMessageHandlerChain.java | 71 +++ .../verification/PvpSignedRequestPolicyRule.java | 9 +- .../impl/verification/SamlVerificationEngine.java | 80 ++-- .../src/main/resources/eaaf_pvp.beans.xml | 21 +- .../resources/messages/pvp_messages.properties | 12 + .../modules/pvp2/test/binding/PostBindingTest.java | 448 +++++++++++++++++++ .../pvp2/test/binding/RedirectBindingTest.java | 490 +++++++++++++++++++++ .../pvp2/test/dummy/DummyCredentialProvider.java | 70 +++ .../src/test/resources/config/config_1.props | 8 + .../test/resources/data/AuthRequest_with_sig_1.xml | 38 ++ .../resources/data/AuthRequest_without_sig_1.xml | 11 + .../test/resources/data/Response_with_sig_1.xml | 81 ++++ .../test/resources/data/Response_without_sig_1.xml | 52 +++ .../src/test/resources/data/junit.jks | Bin 0 -> 2733 bytes .../resources/data/pvp_postbinding_template.html | 3 + .../test/resources/spring/test_eaaf_core.beans.xml | 22 + .../test/resources/spring/test_eaaf_pvp.beans.xml | 29 ++ .../InvalidAssertionConsumerServiceException.java | 7 +- .../InvalidAssertionEncryptionException.java | 5 +- .../pvp2/idp/exception/RequestDeniedException.java | 5 +- .../idp/exception/ResponderErrorException.java | 7 +- .../exception/SamlRequestNotSignedException.java | 7 +- .../idp/exception/SamlRequestNotSupported.java | 10 +- .../exception/UnprovideableAttributeException.java | 5 +- .../pvp2/idp/impl/AbstractPvp2XProtocol.java | 40 +- .../pvp2/idp/impl/AuthenticationAction.java | 23 +- .../pvp2/idp/impl/builder/AuthResponseBuilder.java | 46 +- .../idp/impl/builder/Pvp2AssertionBuilder.java | 52 +-- .../api/IPvpAuthnRequestBuilderConfiguruation.java | 12 +- .../pvp2/sp/impl/PvpAuthnRequestBuilder.java | 58 +-- .../sp/impl/utils/AssertionAttributeExtractor.java | 24 +- 83 files changed, 3606 insertions(+), 1589 deletions(-) create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvp2MetadataProvider.java delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataProvider.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlBindingException.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlSigningException.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafDefaultSaml2Bootstrap.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpAuthRequestSignedRole.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/PostBindingTest.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/dummy/DummyCredentialProvider.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/resources/config/config_1.props create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/AuthRequest_with_sig_1.xml create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/AuthRequest_without_sig_1.xml create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/Response_with_sig_1.xml create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/Response_without_sig_1.xml create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/junit.jks create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/pvp_postbinding_template.html create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_pvp.beans.xml (limited to 'eaaf_modules') 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 @@ -48,10 +48,6 @@ bcprov-jdk15on - - org.owasp.esapi - esapi - javax.servlet javax.servlet-api @@ -64,6 +60,18 @@ junit test + + org.springframework + spring-test + test + + + at.gv.egiz.eaaf + eaaf-core + test + test-jar + + 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 SIGNATURE_TO_DIGEST_ALGORITHM_MAP = + ImmutableMap.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/IPvp2MetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvp2MetadataProvider.java new file mode 100644 index 00000000..e2ee0c9d --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvp2MetadataProvider.java @@ -0,0 +1,51 @@ +/* + * 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.api.metadata; + +import java.util.List; + +import javax.xml.namespace.QName; + +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; + +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; + +public interface IPvp2MetadataProvider extends MetadataResolver { + + XMLObject getMetadata() throws Pvp2MetadataException; + + + EntitiesDescriptor getEntitiesDescriptor(String entitiesID) throws Pvp2MetadataException; + + + EntityDescriptor getEntityDescriptor(String entityID) throws Pvp2MetadataException; + + + List getRole(String entityID, QName roleName) throws Pvp2MetadataException; + + + RoleDescriptor getRole(String entityID, QName roleName, String supportedProtocol) + throws Pvp2MetadataException; + +} 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/IPvpMetadataProvider.java deleted file mode 100644 index 25b2d250..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataProvider.java +++ /dev/null @@ -1,64 +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.api.metadata; - -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; - -public interface IPvpMetadataProvider extends MetadataProvider { - - @Override - boolean requireValidMetadata(); - - @Override - void setRequireValidMetadata(boolean requireValidMetadata); - - @Override - MetadataFilter getMetadataFilter(); - - @Override - void setMetadataFilter(MetadataFilter newFilter) throws MetadataProviderException; - - @Override - XMLObject getMetadata() throws MetadataProviderException; - - @Override - EntitiesDescriptor getEntitiesDescriptor(String entitiesID) throws MetadataProviderException; - - @Override - EntityDescriptor getEntityDescriptor(String entityID) throws MetadataProviderException; - - @Override - List getRole(String entityID, QName roleName) throws MetadataProviderException; - - @Override - RoleDescriptor getRole(String entityID, QName roleName, String supportedProtocol) - throws MetadataProviderException; - -} 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 buildBasicMessageContext( + SAMLMessageEncoder encoder, SignableSAMLObject response) { + final MessageContext messageContext = new MessageContext(); + 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 { 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 { 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 { @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 { 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 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 { 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 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 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 actuallyLoadedProviders = - getAllActuallyLoadedProviders(); + final Map 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 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 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 getAllMetadataUrlsFromConfiguration() throws EaafConfigurationException; - protected void emitChangeEvent() { - if (getObservers() == null || getObservers().size() == 0) { - return; - } - - final List tempObserverList = new ArrayList<>(getObservers()); - for (final ObservableMetadataProvider.Observer observer : tempObserverList) { - if (observer != null) { - observer.onEvent(this); - } - } - } - private Map getAllActuallyLoadedProviders() { - final Map loadedproviders = + private Map getAllActuallyLoadedResolvers() { + final Map loadedproviders = new HashMap<>(); - final ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; // make a Map of all actually loaded HTTPMetadataProvider - final List 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 providersinuse = new HashMap<>(); - final ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; + final Map providersinuse = new HashMap<>(); // get all actually loaded metadata providers - final Map loadedproviders = getAllActuallyLoadedProviders(); + final Map 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 allMetadataUrls = getAllMetadataUrlsFromConfiguration(); - if (allMetadataUrls != null) { final Iterator 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 notusedproviders = loadedproviders.values(); - for (final HTTPMetadataProvider provider : notusedproviders) { - final String metadataurl = provider.getMetadataURI(); - try { - provider.destroy(); + final Collection 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 filters = new ArrayList<>(); - - /** - * Return all actually used Metadata filters. - * - * @return List of Metadata filters - */ - public List 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/SimpleMetadataProvider.java deleted file mode 100644 index d63950cb..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java +++ /dev/null @@ -1,231 +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.io.File; -import java.net.MalformedURLException; -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; - -/** - * Simple SAML2 metadata provider. - * - * @author tlenz - * - */ -public abstract class SimpleMetadataProvider implements MetadataProvider { - private static final Logger log = LoggerFactory.getLogger(SimpleMetadataProvider.class); - - private static final String URI_PREFIX_HTTP = "http:"; - private static final String URI_PREFIX_HTTPS = "https:"; - private static final String URI_PREFIX_FILE = "file:"; - - @Autowired - protected IConfiguration authConfig; - - /** - * Create a single SAML2 metadata provider. - * - * @param metadataLocation where the metadata should be loaded, but never null. - * If the location starts with http(s):, than a http - * based metadata provider is used. If the location - * starts with file:, than a filesystem based metadata - * provider is used - * @param filter Filters, which should be used to validate the - * metadata - * @param idForLogging Id, which is used for Logging - * @param timer {@link Timer} which is used to schedule metadata - * refresh operations - * @param httpClient Apache commons 3.x http client - * - * @return SAML2 Metadata Provider, or null if the metadata provider can not - * initialized - */ - protected MetadataProvider 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) - || metadataLocation.startsWith(URI_PREFIX_HTTPS)) { - if (httpClient != null) { - return createNewHttpMetaDataProvider(metadataLocation, filter, idForLogging, timer, pool, - httpClient); - } else { - log.warn("Can not load http(s) based SAML2 metadata without a HTTP client"); - return null; - } - - } else { - String absoluteMetadataLocation; - try { - absoluteMetadataLocation = - FileUtils.makeAbsoluteUrl(metadataLocation, authConfig.getConfigurationRootDirectory()); - - if (absoluteMetadataLocation.startsWith(URI_PREFIX_FILE)) { - final File metadataFile = new File(absoluteMetadataLocation); - if (metadataFile.exists()) { - return createNewFileSystemMetaDataProvider(metadataFile, filter, idForLogging, timer, - pool); - } else { - log.warn( - "SAML2 metadata file: " + absoluteMetadataLocation + " not found or not exist"); - return null; - } - - } - - } catch (final MalformedURLException e) { - log.warn("SAML2 metadata URL is invalid: " + metadataLocation, e); - - } - - } - - log.warn("SAML2 metadata has an unsupported metadata location prefix: " + metadataLocation); - return null; - - } - - /** - * Create a single SAML2 filesystem based metadata provider. - * - * @param metadataFile File, where the metadata should be loaded - * @param filter Filters, which should be used to validate the metadata - * @param idForLogging Id, which is used for Logging - * @param timer {@link Timer} which is used to schedule metadata refresh - * operations - * @param pool - * - * @return SAML2 Metadata Provider - */ - private MetadataProvider createNewFileSystemMetaDataProvider(final File metadataFile, - final MetadataFilter filter, final String idForLogging, final Timer timer, - final ParserPool pool) { - FilesystemMetadataProvider fileSystemProvider = 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); - - fileSystemProvider.setMetadataFilter(filter); - fileSystemProvider.initialize(); - - fileSystemProvider.setRequireValidMetadata(true); - - return fileSystemProvider; - - } catch (final Exception e) { - log.warn("Failed to load Metadata file for " + idForLogging + "[ " + "File: " - + metadataFile.getAbsolutePath() + " Msg: " + e.getMessage() + " ]", e); - - log.warn("Can not initialize SAML2 metadata provider from filesystem: " - + metadataFile.getAbsolutePath() + " Reason: " + e.getMessage(), e); - - if (fileSystemProvider != null) { - fileSystemProvider.destroy(); - } - - } - - return null; - - } - - /** - * Create a single SAML2 HTTP metadata provider. - * - * @param metadataUrl URL, where the metadata should be loaded - * @param filter Filters, which should be used to validate the metadata - * @param idForLogging Id, which is used for Logging - * @param timer {@link Timer} which is used to schedule metadata refresh - * operations - * @param pool - * - * @return SAML2 Metadata Provider - */ - private MetadataProvider createNewHttpMetaDataProvider(final String metadataUrl, - final MetadataFilter filter, final String idForLogging, final Timer timer, - final ParserPool pool, final HttpClient httpClient) { - HTTPMetadataProvider httpProvider = 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 - // httpProvider.setRefreshDelayFactor(0.1F); - - httpProvider.setMetadataFilter(filter); - httpProvider.initialize(); - - httpProvider.setRequireValidMetadata(true); - - return httpProvider; - - } catch (final Throwable e) { - if (e.getCause() != null && e.getCause().getCause() instanceof SSLHandshakeException) { - log.warn("SSL-Server certificate for metadata " + metadataUrl + " not trusted.", e); - - } - if (e.getCause() != null && e.getCause().getCause() instanceof SignatureValidationException) { - log.warn("Signature verification for metadata" + metadataUrl + " FAILED.", e); - - } - if (e.getCause() != null && e.getCause().getCause() instanceof SchemaValidationException) { - log.warn("Schema validation for metadata " + metadataUrl + " FAILED.", e); - } - - log.warn("Failed to load Metadata file for " + idForLogging + "[ " + e.getMessage() + " ]", - e); - - if (httpProvider != null) { - log.debug("Destroy failed Metadata provider"); - httpProvider.destroy(); - } - - // if (timer != null) { - // log.debug("Destroy Timer."); - // timer.cancel(); - // } - - } - - return null; - } - -} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java new file mode 100644 index 00000000..35ad3f97 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java @@ -0,0 +1,243 @@ +/* + * 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.io.File; +import java.net.MalformedURLException; +import java.util.Timer; + +import javax.net.ssl.SSLHandshakeException; + +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 + * + */ +@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:"; + + @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. + * + * @param metadataLocation where the metadata should be loaded, but never null. + * If the location starts with http(s):, than a http + * based metadata provider is used. If the location + * starts with file:, than a filesystem based metadata + * provider is used + * @param filter Filters, which should be used to validate the + * metadata + * @param idForLogging Id, which is used for Logging + * @param timer {@link Timer} which is used to schedule metadata + * refresh operations + * @param httpClient Apache commons 3.x http client + * + * @return SAML2 Metadata Provider, or null if the metadata provider can not + * initialized + */ + 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) + || metadataLocation.startsWith(URI_PREFIX_HTTPS)) { + if (httpClient != null) { + return createNewHttpMetaDataProvider(metadataLocation, filter, idForLogging, timer, pool, + httpClient); + } else { + log.warn("Can not load http(s) based SAML2 metadata without a HTTP client"); + return null; + } + + } else { + String absoluteMetadataLocation; + try { + absoluteMetadataLocation = + FileUtils.makeAbsoluteUrl(metadataLocation, authConfig.getConfigurationRootDirectory()); + + if (absoluteMetadataLocation.startsWith(URI_PREFIX_FILE)) { + final File metadataFile = new File(absoluteMetadataLocation); + if (metadataFile.exists()) { + return createNewFileSystemMetaDataProvider(metadataFile, filter, idForLogging, timer, + pool); + } else { + log.warn( + "SAML2 metadata file: " + absoluteMetadataLocation + " not found or not exist"); + return null; + } + + } + + } catch (final MalformedURLException e) { + log.warn("SAML2 metadata URL is invalid: " + metadataLocation, e); + + } + + } + + log.warn("SAML2 metadata has an unsupported metadata location prefix: " + metadataLocation); + return null; + + } + + /** + * Create a single SAML2 filesystem based metadata provider. + * + * @param metadataFile File, where the metadata should be loaded + * @param filter Filters, which should be used to validate the metadata + * @param idForLogging Id, which is used for Logging + * @param timer {@link Timer} which is used to schedule metadata refresh + * operations + * @param pool + * + * @return SAML2 Metadata Provider + */ + private MetadataResolver createNewFileSystemMetaDataProvider(final File metadataFile, + final MetadataFilter filter, final String idForLogging, final Timer timer, + final ParserPool pool) { + FilesystemMetadataResolver fileSystemResolver = null; + try { + 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 + + fileSystemResolver.setMetadataFilter(filter); + fileSystemResolver.initialize(); + fileSystemResolver.setId(metadataFile.getAbsolutePath()); + + fileSystemResolver.setRequireValidMetadata(true); + + return fileSystemResolver; + + } catch (final Exception e) { + log.warn("Failed to load Metadata file for " + idForLogging + "[ " + "File: " + + metadataFile.getAbsolutePath() + " Msg: " + e.getMessage() + " ]", e); + + log.warn("Can not initialize SAML2 metadata provider from filesystem: " + + metadataFile.getAbsolutePath() + " Reason: " + e.getMessage(), e); + + if (fileSystemResolver != null) { + fileSystemResolver.destroy(); + + } + + } + + return null; + + } + + /** + * Create a single SAML2 HTTP metadata provider. + * + * @param metadataUrl URL, where the metadata should be loaded + * @param filter Filters, which should be used to validate the metadata + * @param idForLogging Id, which is used for Logging + * @param timer {@link Timer} which is used to schedule metadata refresh + * operations + * @param pool + * + * @return SAML2 Metadata Provider + */ + private MetadataResolver createNewHttpMetaDataProvider(final String metadataUrl, + final MetadataFilter filter, final String idForLogging, final Timer timer, + final ParserPool pool, final HttpClient httpClient) { + HTTPMetadataResolver httpMetadataResolver = null; + try { + httpMetadataResolver = new HTTPMetadataResolver(timer, httpClient, metadataUrl); + httpMetadataResolver.setParserPool(pool); + httpMetadataResolver.setRequireValidMetadata(true); + httpMetadataResolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes + httpMetadataResolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours + // httpProvider.setRefreshDelayFactor(0.1F); + + httpMetadataResolver.setMetadataFilter(filter); + httpMetadataResolver.setId(metadataUrl); + httpMetadataResolver.initialize(); + + httpMetadataResolver.setRequireValidMetadata(true); + + return httpMetadataResolver; + + } catch (final Throwable e) { + if (e.getCause() != null && e.getCause().getCause() instanceof SSLHandshakeException) { + log.warn("SSL-Server certificate for metadata " + metadataUrl + " not trusted.", e); + + } + if (e.getCause() != null && e.getCause().getCause() instanceof SignatureValidationException) { + log.warn("Signature verification for metadata" + metadataUrl + " FAILED.", e); + + } + if (e.getCause() != null && e.getCause().getCause() instanceof SchemaValidationException) { + log.warn("Schema validation for metadata " + metadataUrl + " FAILED.", e); + } + + log.warn("Failed to load Metadata file for " + idForLogging + "[ " + e.getMessage() + " ]", + e); + + if (httpMetadataResolver != null) { + log.debug("Destroy failed Metadata provider"); + httpMetadataResolver.destroy(); + + } + + } + + return null; + } + +} 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. + *

+ * If more than one parameters with the same name exists, + * this method always select the last parameter value. + * + * @param request Incoming http request + * @param paramName Name of the http parameter + * @return the last parameter value with this name, or null 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 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 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 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 getSecureDocumentBuilderFeatures() { + final Map 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); @@ -72,17 +102,145 @@ public class Saml2Utils { } } + /** + * Sign a OpenSAML 3.x object with a {@link X509Credential}. + *
+ *

This method used {@link PvpConstants.DEFAULT_SIGNING_METHODE_RSA} + * or {@link PvpConstants.DEFAULT_SIGNING_METHODE_EC} as algorithm

+ * + * @param {@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 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 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 true 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 SAML2 object class + * @param SAML2 object class * @param clazz object class * @return SAML2 object */ public static T createSamlObject(final Class 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 = 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 { + + @Override + protected void doInvoke(MessageContext 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 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 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 samlReqParam = inTransport.getParameterValues("SAMLRequest"); - final List 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 { + private final List> handlers = new ArrayList<>(); + private boolean isInitialized = false; + + @Override + public void invoke(MessageContext messageContext) throws MessageHandlerException { + if (!isInitialized) { + throw new RuntimeException("Component: " + + PvpSamlMessageHandlerChain.class.getName() + " not initialized"); + + } + for (final MessageHandler 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 handler : getHandlers()) { + log.trace("Initializing SAML message handler: {}", handler.getClass().getName()); + handler.initialize(); + + } + + isInitialized = true; + } + + } + + @Override + public List> getHandlers() { + return handlers; + + } + + public void addHandler(MessageHandler handler) { + handlers.add(handler); + + } + + public void addHandlers(List> 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"> - - - + - + - + + + + + \ 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 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 @@ + + + https://demo.egiz.gv.at/demoportal_demologin/ + + + + + + + + + + + sBVJQf9b+QIxRfH8YuTbF6hBrf4= + + + JK68H5XqmD2OEA8O/UCZFenVj0TrvauPhaKJt73pbHbi//hO1hBcRQbV2Qg3gQ11EcJ9Q+TM3TCe9nT6tdU/z7ry3qdZvlOfrkMF13fY4HOIuvB9AcySdxq2yKA3V5O9sLhf5S9qCyx9lMnTARC7wkVs4j2Pv00R6P/iROOHD5ryGF2J0FdtMp9VqhvQJ9yRGM2lTduF98MqxWA2EMk6AMo7qij0Bvha1B2OyFSU9HM3fyfRQpXDeiLnKHcjLpzu5TDNkKrP75c7vv85DDr7s2I0p74nAOVLMuLau5tEQ91Crk9QoqoqqEecKWcNJDXTO9MahCQw77hUDL1WOEMFFg== + + + + nEPzKMh3TovnfBnTyv+TMYFsGep8Uil7iNbfVyfLoBfqRdeGDOk4es2qWkgB6az+kM/9Js2H06m4 +pjEY7/RIjd0lMWqgi8eqdjilMmbFQykkYYQhlZbvi8KqoBcCKzj5N3GY4qh8A5qN4y85Q3sZj23T +iiIY1rphE+ZTOHCm6CKeRso9jj409YHP1xAXfPvtIYx2TA1uuagxOmL75OC/hr7gcUm0tmuKiSeq ++TO4VZw2Q7K7YESZ1WkiBoG2i4cHdcBFKnVrGNtyxl6UkjWxXRJSU9aNLs5QxsE6iFwCvFoIO+IU +cVWxfFHqOGbRtAcRUb4fk+KFHE2o1DLmfwZaUQ== + AQAB + + + + + + https://demo.egiz.gv.at/demoportal_demologin/ + + + + http://www.stork.gov.eu/1.0/citizenQAALevel/4 + + 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 @@ + + + https://demo.egiz.gv.at/demoportal_demologin/ + + https://demo.egiz.gv.at/demoportal_demologin/ + + + + http://www.stork.gov.eu/1.0/citizenQAALevel/4 + + 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 @@ + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + + + + + + + + + + + + fCE31ZeXZybQLOuNQBePLjFrCtKdvCmeyJ1tUW/ghtA= + + + vUFR3YPk5wiBJnrLh6Er7V46FNDMuB5Jcu73Rw7tipgr+bnV0reRNcZ5TGT+VMjNhtKJMcqgjrQWJ6tACe1r0mzhpRSVQkw7yFkTvIhQHX1a08yqJ4yy3qiN13ctDo4VgP9qHUim7b797oOKNhRXFk+2GJA5hRcpRliUjhBlzTYrxpkY5NcYDRhDPlvMx+l11oa1iDGuAylN+ty4h3P4fIoIgL9Tz1m3l65LqkV5RBc6avSeHw9OASMigPsjd5b0IBvhvJ611xLgzC1BOtJshiw1k/p8alv8TaUmYZ/kJbRN1tuTBL129edbS0Rz0faT0tniF42QHteJ214brK3rCg== + + + + xRE83dJy1dj+KVBp5Syo91fjGeG1MmJDSuTZ5MwdDzvIZrbK3YPh0jbJz4lOSrw9urRacavZX4m2 +XAKfSRxaowP3GqTh3Ew4WJE7yXEnWiic7bUz8uMIr020bsvqHCvY48+oPARbz/cEOf5NgMBWqo9E +nibdIyU5+AmfFzDaMwNocJEANoXrjLTpduCHvT0Qt/wH+7rVdgjX1djMrBhyMWs7GQyIBRfuf58m +8kdcoiMSm9AWA4d4GzXch+bi1QRzj+Ib80DeWdcXP3Hc6pcyp/+L+hya2jZ9NMS8yup6xuoAeh7w +6JNpfE9QnO3/CPrDZTtmjPK2OIRkhgn4Yi+iBQ== + AQAB + + + + + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://demo.egiz.gv.at/demoportal_demologin/ + + + + + http://www.stork.gov.eu/1.0/citizenQAALevel/4 + + + + + 2.1 + + + Mustermann + + + Max + + + 1940-01-01 + + + BF:QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + 4 + + + AT + + + urn:publicid:gv.at:cdid+BF + + + + 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 @@ + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://demo.egiz.gv.at/demoportal_demologin/ + + + + + http://www.stork.gov.eu/1.0/citizenQAALevel/4 + + + + + 2.1 + + + Mustermann + + + Max + + + 1940-01-01 + + + BF:QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + 4 + + + AT + + + urn:publicid:gv.at:cdid+BF + + + + 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 new file mode 100644 index 00000000..b5262cb8 Binary files /dev/null and b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/data/junit.jks differ 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 @@ + + + + + + + + + + + \ 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 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java index 6d868558..0003b829 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java @@ -20,7 +20,8 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.exception; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; -import org.opensaml.saml2.core.StatusCode; + +import org.opensaml.saml.saml2.core.StatusCode; public class InvalidAssertionConsumerServiceException extends Pvp2Exception { @@ -28,7 +29,7 @@ public class InvalidAssertionConsumerServiceException extends Pvp2Exception { public InvalidAssertionConsumerServiceException(final int idx) { super("pvp2.28", new Object[] {idx}); - this.statusCodeValue = StatusCode.REQUESTER_URI; + this.statusCodeValue = StatusCode.REQUESTER; } /** @@ -38,7 +39,7 @@ public class InvalidAssertionConsumerServiceException extends Pvp2Exception { */ public InvalidAssertionConsumerServiceException(final String wrongUrl) { super("pvp2.23", new Object[] {wrongUrl}); - this.statusCodeValue = StatusCode.REQUESTER_URI; + this.statusCodeValue = StatusCode.REQUESTER; } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java index 0d75616a..89179ff6 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java @@ -20,7 +20,8 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.exception; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; -import org.opensaml.saml2.core.StatusCode; + +import org.opensaml.saml.saml2.core.StatusCode; public class InvalidAssertionEncryptionException extends Pvp2Exception { @@ -28,7 +29,7 @@ public class InvalidAssertionEncryptionException extends Pvp2Exception { public InvalidAssertionEncryptionException() { super("pvp2.16", new Object[] {}); - this.statusCodeValue = StatusCode.RESPONDER_URI; + this.statusCodeValue = StatusCode.RESPONDER; } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java index ecceea12..cf4ac8d1 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java @@ -20,7 +20,8 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.exception; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; -import org.opensaml.saml2.core.StatusCode; + +import org.opensaml.saml.saml2.core.StatusCode; public class RequestDeniedException extends Pvp2Exception { @@ -28,7 +29,7 @@ public class RequestDeniedException extends Pvp2Exception { public RequestDeniedException() { super("pvp2.14", null); - this.statusCodeValue = StatusCode.REQUEST_DENIED_URI; + this.statusCodeValue = StatusCode.REQUEST_DENIED; } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java index 331e11cd..e6cdf8f1 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java @@ -20,7 +20,8 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.exception; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; -import org.opensaml.saml2.core.StatusCode; + +import org.opensaml.saml.saml2.core.StatusCode; public class ResponderErrorException extends Pvp2Exception { @@ -29,11 +30,11 @@ public class ResponderErrorException extends Pvp2Exception { public ResponderErrorException(final String messageId, final Object[] parameters, final Throwable wrapped) { super(messageId, parameters, wrapped); - this.statusCodeValue = StatusCode.RESPONDER_URI; + this.statusCodeValue = StatusCode.RESPONDER; } public ResponderErrorException(final String messageId, final Object[] parameters) { super(messageId, parameters); - this.statusCodeValue = StatusCode.RESPONDER_URI; + this.statusCodeValue = StatusCode.RESPONDER; } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java index 4650506d..c02e534c 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java @@ -20,7 +20,8 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.exception; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; -import org.opensaml.saml2.core.StatusCode; + +import org.opensaml.saml.saml2.core.StatusCode; public class SamlRequestNotSignedException extends Pvp2Exception { @@ -28,12 +29,12 @@ public class SamlRequestNotSignedException extends Pvp2Exception { public SamlRequestNotSignedException() { super("pvp2.07", null); - this.statusCodeValue = StatusCode.REQUESTER_URI; + this.statusCodeValue = StatusCode.REQUESTER; } public SamlRequestNotSignedException(final Throwable e) { super("pvp2.07", null, e); - this.statusCodeValue = StatusCode.REQUESTER_URI; + this.statusCodeValue = StatusCode.REQUESTER; } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java index 58a493b9..b0dcdb2e 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java @@ -11,7 +11,7 @@ * 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. @@ -19,18 +19,18 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.exception; -import org.opensaml.saml2.core.StatusCode; - import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import org.opensaml.saml.saml2.core.StatusCode; + public class SamlRequestNotSupported extends Pvp2Exception { private static final long serialVersionUID = 1244883178458802767L; - + public SamlRequestNotSupported() { super("pvp2.09", null); - this.statusCodeValue = StatusCode.REQUEST_UNSUPPORTED_URI; + this.statusCodeValue = StatusCode.REQUEST_UNSUPPORTED; } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java index 41252b78..0f84b8fb 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java @@ -20,7 +20,8 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.exception; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; -import org.opensaml.saml2.core.StatusCode; + +import org.opensaml.saml.saml2.core.StatusCode; public class UnprovideableAttributeException extends Pvp2Exception { @@ -28,6 +29,6 @@ public class UnprovideableAttributeException extends Pvp2Exception { public UnprovideableAttributeException(final String attributeName) { super("pvp2.10", new Object[] {attributeName}); - this.statusCodeValue = StatusCode.UNKNOWN_ATTR_PROFILE_URI; + this.statusCodeValue = StatusCode.UNKNOWN_ATTR_PROFILE; } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java index f8a39b61..f86fd883 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java @@ -39,7 +39,8 @@ import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; import at.gv.egiz.eaaf.modules.pvp2.PvpEventConstants; import at.gv.egiz.eaaf.modules.pvp2.api.IPvp2BasicConfiguration; import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataProvider; +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.api.validation.IAuthnRequestPostProcessor; import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException; import at.gv.egiz.eaaf.modules.pvp2.exception.NameIdFormatNotSupportedException; @@ -60,20 +61,19 @@ import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SamlVerificationEngine; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameIDType; -import org.opensaml.saml2.core.Response; -import org.opensaml.saml2.core.Status; -import org.opensaml.saml2.core.StatusCode; -import org.opensaml.saml2.core.StatusMessage; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.Issuer; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.core.Status; +import org.opensaml.saml.saml2.core.StatusCode; +import org.opensaml.saml.saml2.core.StatusMessage; +import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; import org.opensaml.ws.security.SecurityPolicyException; -import org.opensaml.xml.security.x509.X509Credential; -import org.opensaml.xml.signature.SignableXMLObject; +import org.opensaml.xmlsec.signature.SignableXMLObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -84,7 +84,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement @Autowired(required = true) protected IPvp2BasicConfiguration pvpBasicConfiguration; @Autowired(required = true) - protected IPvpMetadataProvider metadataProvider; + protected IPvp2MetadataProvider metadataProvider; @Autowired(required = true) protected SamlVerificationEngine samlVerificationEngine; @Autowired(required = false) @@ -125,11 +125,11 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement String moaError = null; if (e instanceof NoPassivAuthenticationException) { - statusCode.setValue(StatusCode.NO_PASSIVE_URI); + statusCode.setValue(StatusCode.NO_PASSIVE); statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); } else if (e instanceof NameIdFormatNotSupportedException) { - statusCode.setValue(StatusCode.INVALID_NAMEID_POLICY_URI); + statusCode.setValue(StatusCode.INVALID_NAMEID_POLICY); statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); } else if (e instanceof SloException) { @@ -146,7 +146,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement moaError = statusMessager.mapInternalErrorToExternalError(ex.getErrorId()); } else { - statusCode.setValue(StatusCode.RESPONDER_URI); + statusCode.setValue(StatusCode.RESPONDER); statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); moaError = statusMessager.getResponseErrorCode(e); } @@ -194,9 +194,9 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement relayState = pvpRequest.getRequest().getRelayState(); } - final X509Credential signCred = pvpIdpCredentials.getIdpAssertionSigningCredential(); + final EaafX509Credential signCred = pvpIdpCredentials.getIdpAssertionSigningCredential(); - encoder.encodeRespone(request, response, samlResponse, pvpRequest.getConsumerUrl(), relayState, + encoder.encodeResponse(request, response, samlResponse, pvpRequest.getConsumerUrl(), relayState, signCred, protocolRequest); return true; } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java index d4981cd6..74224dbe 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java @@ -22,6 +22,7 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.IAction; import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -32,7 +33,7 @@ import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.impl.data.SloInformationImpl; import at.gv.egiz.eaaf.modules.pvp2.api.IPvp2BasicConfiguration; import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; -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.exception.BindingNotSupportedException; import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException; import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.AuthResponseBuilder; @@ -42,15 +43,15 @@ import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; + import org.joda.time.DateTime; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.Assertion; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.Response; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.ws.message.encoder.MessageEncodingException; -import org.opensaml.xml.security.SecurityException; +import org.opensaml.messaging.encoder.MessageEncodingException; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -65,7 +66,7 @@ public class AuthenticationAction implements IAction { "protocols.pvp2.assertion.encryption.active"; @Autowired(required = true) - private IPvpMetadataProvider metadataProvider; + private IPvp2MetadataProvider metadataProvider; @Autowired(required = true) ApplicationContext springContext; @Autowired(required = true) @@ -131,7 +132,7 @@ public class AuthenticationAction implements IAction { throw new BindingNotSupportedException(consumerService.getBinding()); } - binding.encodeRespone(httpReq, httpResp, authResponse, consumerService.getLocation(), + binding.encodeResponse(httpReq, httpResp, authResponse, consumerService.getLocation(), moaRequest.getRelayState(), pvpIdpCredentials.getIdpAssertionSigningCredential(), req); revisionsLogger.logEvent(req, 3105, authResponse.getID()); diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java index bf51ac0f..ac551612 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java @@ -21,36 +21,36 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder; import java.util.ArrayList; import java.util.List; + import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; + import org.joda.time.DateTime; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.Assertion; -import org.opensaml.saml2.core.EncryptedAssertion; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameIDType; -import org.opensaml.saml2.core.RequestAbstractType; -import org.opensaml.saml2.core.Response; -import org.opensaml.saml2.encryption.Encrypter; -import org.opensaml.saml2.encryption.Encrypter.KeyPlacement; -import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.core.criterion.EntityIdCriterion; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.EncryptedAssertion; +import org.opensaml.saml.saml2.core.Issuer; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.core.RequestAbstractType; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.encryption.Encrypter.KeyPlacement; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml.security.impl.MetadataCredentialResolver; import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.security.MetadataCredentialResolver; import org.opensaml.security.MetadataCriteria; -import org.opensaml.xml.encryption.EncryptionException; -import org.opensaml.xml.encryption.EncryptionParameters; -import org.opensaml.xml.encryption.KeyEncryptionParameters; -import org.opensaml.xml.security.CriteriaSet; -import org.opensaml.xml.security.SecurityException; -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.security.keyinfo.KeyInfoGeneratorFactory; -import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.security.credential.UsageType; +import org.opensaml.security.criteria.UsageCriterion; +import org.opensaml.security.x509.X509Credential; +import org.opensaml.xmlsec.EncryptionParameters; +import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters; +import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import net.shibboleth.utilities.java.support.resolver.CriteriaSet; + /** * Authentication response builder. * @@ -101,10 +101,10 @@ public class AuthResponseBuilder { new MetadataCredentialResolver(metadataProvider); final CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add(new EntityIDCriteria(req.getIssuer().getValue())); + criteriaSet.add(new EntityIdCriterion(req.getIssuer().getValue())); criteriaSet .add(new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); - criteriaSet.add(new UsageCriteria(UsageType.ENCRYPTION)); + criteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION)); X509Credential encryptionCredentials = null; try { diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java index f57f9db0..922e7efe 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java @@ -23,6 +23,7 @@ import java.security.MessageDigest; import java.util.ArrayList; import java.util.Iterator; import java.util.List; + import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.data.ILoALevelMapper; import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -42,33 +43,34 @@ import at.gv.egiz.eaaf.modules.pvp2.idp.impl.PvpSProfilePendingRequest; import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpAttributeBuilder; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.QaaLevelVerifier; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; + import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.Assertion; -import org.opensaml.saml2.core.Attribute; -import org.opensaml.saml2.core.AttributeQuery; -import org.opensaml.saml2.core.AttributeStatement; -import org.opensaml.saml2.core.Audience; -import org.opensaml.saml2.core.AudienceRestriction; -import org.opensaml.saml2.core.AuthnContext; -import org.opensaml.saml2.core.AuthnContextClassRef; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.AuthnStatement; -import org.opensaml.saml2.core.Conditions; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; -import org.opensaml.saml2.core.NameIDType; -import org.opensaml.saml2.core.RequestedAuthnContext; -import org.opensaml.saml2.core.Subject; -import org.opensaml.saml2.core.SubjectConfirmation; -import org.opensaml.saml2.core.SubjectConfirmationData; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.AttributeConsumingService; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.NameIDFormat; -import org.opensaml.saml2.metadata.RequestedAttribute; -import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.Attribute; +import org.opensaml.saml.saml2.core.AttributeQuery; +import org.opensaml.saml.saml2.core.AttributeStatement; +import org.opensaml.saml.saml2.core.Audience; +import org.opensaml.saml.saml2.core.AudienceRestriction; +import org.opensaml.saml.saml2.core.AuthnContext; +import org.opensaml.saml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.AuthnStatement; +import org.opensaml.saml.saml2.core.Conditions; +import org.opensaml.saml.saml2.core.Issuer; +import org.opensaml.saml.saml2.core.NameID; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.core.RequestedAuthnContext; +import org.opensaml.saml.saml2.core.Subject; +import org.opensaml.saml.saml2.core.SubjectConfirmation; +import org.opensaml.saml.saml2.core.SubjectConfirmationData; +import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.AttributeConsumingService; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.NameIDFormat; +import org.opensaml.saml.saml2.metadata.RequestedAttribute; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/api/IPvpAuthnRequestBuilderConfiguruation.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/api/IPvpAuthnRequestBuilderConfiguruation.java index 2e747656..597507f3 100644 --- a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/api/IPvpAuthnRequestBuilderConfiguruation.java +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/api/IPvpAuthnRequestBuilderConfiguruation.java @@ -21,13 +21,13 @@ package at.gv.egiz.eaaf.modules.pvp2.sp.api; import java.util.List; -import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.xml.security.credential.Credential; -import org.w3c.dom.Element; - +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; +import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.w3c.dom.Element; + /** * Configuration of a PVP2 S-Profile authentication-request builder. * @@ -97,7 +97,7 @@ public interface IPvpAuthnRequestBuilderConfiguruation { * * @return */ - Credential getAuthnRequestSigningCredential(); + EaafX509Credential getAuthnRequestSigningCredential(); /** * Define the SAML2 EntityDescriptor of the IDP, which should receive the diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/PvpAuthnRequestBuilder.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/PvpAuthnRequestBuilder.java index 9b284c88..a81d9119 100644 --- a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/PvpAuthnRequestBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/PvpAuthnRequestBuilder.java @@ -24,34 +24,6 @@ import java.util.List; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.lang3.StringUtils; -import org.joda.time.DateTime; -import org.opensaml.common.impl.SecureRandomIdentifierGenerator; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.common.Extensions; -import org.opensaml.saml2.core.AuthnContextClassRef; -import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; -import org.opensaml.saml2.core.NameIDPolicy; -import org.opensaml.saml2.core.NameIDType; -import org.opensaml.saml2.core.RequestedAuthnContext; -import org.opensaml.saml2.core.RequesterID; -import org.opensaml.saml2.core.Scoping; -import org.opensaml.saml2.core.Subject; -import org.opensaml.saml2.core.SubjectConfirmation; -import org.opensaml.saml2.core.SubjectConfirmationData; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.SingleSignOnService; -import org.opensaml.ws.message.encoder.MessageEncodingException; -import org.opensaml.xml.security.SecurityException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.stereotype.Service; - import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; @@ -64,6 +36,34 @@ import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import at.gv.egiz.eaaf.modules.pvp2.sp.api.IPvpAuthnRequestBuilderConfiguruation; import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnRequestBuildException; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.opensaml.messaging.encoder.MessageEncodingException; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.Extensions; +import org.opensaml.saml.saml2.core.Issuer; +import org.opensaml.saml.saml2.core.NameID; +import org.opensaml.saml.saml2.core.NameIDPolicy; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.core.RequestedAuthnContext; +import org.opensaml.saml.saml2.core.RequesterID; +import org.opensaml.saml.saml2.core.Scoping; +import org.opensaml.saml.saml2.core.Subject; +import org.opensaml.saml.saml2.core.SubjectConfirmation; +import org.opensaml.saml.saml2.core.SubjectConfirmationData; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.SingleSignOnService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; + +import net.shibboleth.utilities.java.support.security.SecureRandomIdentifierGenerationStrategy; + /** * PVP2 S-Profil Authentication-Request builder-implementation. * @@ -127,7 +127,7 @@ public class PvpAuthnRequestBuilder { if (StringUtils.isNotEmpty(reqID)) { authReq.setID(reqID); } else { - final SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); + final SecureRandomIdentifierGenerationStrategy gen = new SecureRandomIdentifierGenerationStrategy(); authReq.setID(gen.generateIdentifier()); } diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/utils/AssertionAttributeExtractor.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/utils/AssertionAttributeExtractor.java index fa2b9312..53d9d9e8 100644 --- a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/utils/AssertionAttributeExtractor.java +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/utils/AssertionAttributeExtractor.java @@ -28,22 +28,22 @@ import java.util.List; import java.util.Map; import java.util.Set; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AssertionAttributeExtractorExeption; + import org.apache.commons.lang3.StringUtils; -import org.opensaml.saml2.core.Assertion; -import org.opensaml.saml2.core.Attribute; -import org.opensaml.saml2.core.AttributeStatement; -import org.opensaml.saml2.core.AuthnContextClassRef; -import org.opensaml.saml2.core.AuthnStatement; -import org.opensaml.saml2.core.Response; -import org.opensaml.saml2.core.StatusResponseType; -import org.opensaml.saml2.core.Subject; -import org.opensaml.xml.XMLObject; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.Attribute; +import org.opensaml.saml.saml2.core.AttributeStatement; +import org.opensaml.saml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml.saml2.core.AuthnStatement; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.core.StatusResponseType; +import org.opensaml.saml.saml2.core.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AssertionAttributeExtractorExeption; - public class AssertionAttributeExtractor { private static final Logger log = LoggerFactory.getLogger(AssertionAttributeExtractor.class); -- cgit v1.2.3