summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf
diff options
context:
space:
mode:
authorThomas Lenz <thomas.lenz@egiz.gv.at>2020-02-04 17:37:34 +0100
committerThomas Lenz <thomas.lenz@egiz.gv.at>2020-02-04 17:37:34 +0100
commite7610325ee2f1d1f4e97e1e7a9b212e692836b5a (patch)
treeed7c0dba5fed47e80e68b4ab5a63846c5724a8e7 /eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf
parent41ea2fdf782cd64d7d29f73c2e83f9c255810818 (diff)
downloadEAAF-Components-e7610325ee2f1d1f4e97e1e7a9b212e692836b5a.tar.gz
EAAF-Components-e7610325ee2f1d1f4e97e1e7a9b212e692836b5a.tar.bz2
EAAF-Components-e7610325ee2f1d1f4e97e1e7a9b212e692836b5a.zip
first stable version that uses OpenSAML 3.x
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf')
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/Pvp2SProfileCoreSpringResourceProvider.java4
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java48
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java3
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java2
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java1
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java6
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java2
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/IAuthnRequestPostProcessor.java14
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/Pvp2InternalErrorException.java12
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java12
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMetadataSignatureException.java26
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java127
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java147
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java234
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java104
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java3
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java53
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java3
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java1
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java11
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java334
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java39
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java293
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java60
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java37
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafKeyStoreX509CredentialAdapter.java20
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HttpPostEncoderWithOwnTemplate.java1
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java11
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java10
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java8
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QaaLevelVerifier.java6
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java80
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SamlHttpUtils.java33
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java47
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java19
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java146
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java41
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSaml2HttpRedirectDeflateSignatureSecurityHandler.java107
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSamlProtocolMessageXmlSignatureSecurityHandler.java75
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java2
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java7
41 files changed, 1329 insertions, 860 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/Pvp2SProfileCoreSpringResourceProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/Pvp2SProfileCoreSpringResourceProvider.java
index 2779ee1d..232e4ae9 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/Pvp2SProfileCoreSpringResourceProvider.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/Pvp2SProfileCoreSpringResourceProvider.java
@@ -19,11 +19,11 @@
package at.gv.egiz.eaaf.modules.pvp2;
+import at.gv.egiz.components.spring.api.SpringResourceProvider;
+
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
-import at.gv.egiz.components.spring.api.SpringResourceProvider;
-
public class Pvp2SProfileCoreSpringResourceProvider implements SpringResourceProvider {
@Override
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java
index b1ac8e75..69b94255 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PvpConstants.java
@@ -36,11 +36,15 @@ import org.opensaml.xmlsec.signature.support.SignatureConstants;
import com.google.common.collect.ImmutableMap;
public interface PvpConstants extends PvpAttributeDefinitions {
- //module configuration parameters
+ // module configuration parameters
String CONFIG_PROP_SEC_SIGNING_RSA_ALG = "pvp2.security.alg.signing.rsa";
String CONFIG_PROP_SEC_SIGNING_EC_ALG = "pvp2.security.alg.signing.ec";
+ String CONFIG_PROP_SEC_ENCRYPTION_DATA = "pvp2.security.alg.enc.data";
+ String CONFIG_PROP_SEC_ENCRYPTION_KEY_RSA_ALG = "pvp2.security.alg.enc.key.rsa";
+ String CONFIG_PROP_SEC_ENCRYPTION_KEY_EC_ALG = "pvp2.security.alg.enc.key.ec";
+ String CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION = "pvp2.assertion.encryption.active";
- //Default values
+ // Default values
String DEFAULT_SIGNING_METHODE_RSA =
SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256;
String DEFAULT_SIGNING_METHODE_EC =
@@ -49,12 +53,13 @@ public interface PvpConstants extends PvpAttributeDefinitions {
String DEFAULT_DIGESTMETHODE = SignatureConstants.ALGO_ID_DIGEST_SHA256;
String DEFAULT_SYM_ENCRYPTION_METHODE =
- EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256;
- String DEFAULT_ASYM_ENCRYPTION_METHODE =
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM;
+ String DEFAULT_ASYM_ENCRYPTION_METHODE_RSA =
EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP;
+ String DEFAULT_ASYM_ENCRYPTION_METHODE_EC =
+ EncryptionConstants.ALGO_ID_KEYAGREEMENT_DH;
-
- //PVP entity categories
+ // PVP entity categories
String ENTITY_CATEGORY_ATTRIBITE = "http://macedir.org/entity-category";
String EGOVTOKEN = "http://www.ref.gv.at/ns/names/agiz/pvp/egovtoken";
String CITIZENTOKEN = "http://www.ref.gv.at/ns/names/agiz/pvp/citizentoken";
@@ -152,19 +157,22 @@ public interface PvpConstants extends PvpAttributeDefinitions {
ImmutableMap<String, String> SIGNATURE_TO_DIGEST_ALGORITHM_MAP =
ImmutableMap.<String, String>builder()
- .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, SignatureConstants.ALGO_ID_DIGEST_SHA256)
- .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA384, SignatureConstants.ALGO_ID_DIGEST_SHA384)
- .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512, SignatureConstants.ALGO_ID_DIGEST_SHA512)
- .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256, SignatureConstants.ALGO_ID_DIGEST_SHA256)
- .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA384, SignatureConstants.ALGO_ID_DIGEST_SHA384)
- .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA512, SignatureConstants.ALGO_ID_DIGEST_SHA512)
- .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA256)
- .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA384)
- .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA512)
- .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_256_MGF1, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_256)
- .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_384_MGF1, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_384)
- .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_512_MGF1, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_512)
-
- .build();
+ .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, SignatureConstants.ALGO_ID_DIGEST_SHA256)
+ .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA384, SignatureConstants.ALGO_ID_DIGEST_SHA384)
+ .put(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512, SignatureConstants.ALGO_ID_DIGEST_SHA512)
+ .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256, SignatureConstants.ALGO_ID_DIGEST_SHA256)
+ .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA384, SignatureConstants.ALGO_ID_DIGEST_SHA384)
+ .put(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA512, SignatureConstants.ALGO_ID_DIGEST_SHA512)
+ .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA256)
+ .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA384)
+ .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1, SignatureConstants.ALGO_ID_DIGEST_SHA512)
+ .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_256_MGF1,
+ MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_256)
+ .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_384_MGF1,
+ MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_384)
+ .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA3_512_MGF1,
+ MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA3_512)
+
+ .build();
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java
index e8da499c..83bfee84 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java
@@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.api.binding;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
@@ -30,7 +31,7 @@ import net.shibboleth.utilities.java.support.net.URIComparator;
public interface IDecoder {
InboundMessageInterface decode(HttpServletRequest req, HttpServletResponse resp,
- IPvp2MetadataProvider metadataProvider, boolean isSpEndPoint, URIComparator comparator)
+ IPvp2MetadataProvider metadataProvider, QName peerEntityRole, URIComparator comparator)
throws Pvp2Exception;
boolean handleDecode(String action, HttpServletRequest req);
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java
index 691d6574..5a8bc4fb 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java
@@ -60,7 +60,7 @@ public interface IEncoder {
* @param credentials Credential to sign the response object
* @param pendingReq Internal MOA-ID request object that contains
* session-state informations but never null
- * @throws SecurityException In case of an error
+ * @throws SecurityException In case of an error
*/
void encodeResponse(HttpServletRequest req, HttpServletResponse resp,
StatusResponseType response, String targetLocation, String relayState, EaafX509Credential credentials,
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java
index 568b617d..ce6451c0 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/credential/EaafX509Credential.java
@@ -4,7 +4,6 @@ import javax.annotation.Nonnull;
import org.opensaml.security.x509.X509Credential;
-
public interface EaafX509Credential extends X509Credential {
/**
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java
index 128d4c2f..3d9125fe 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java
@@ -22,15 +22,15 @@ package at.gv.egiz.eaaf.modules.pvp2.api.metadata;
import java.util.Collection;
import java.util.List;
+import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
+import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException;
+
import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.metadata.ContactPerson;
import org.opensaml.saml.saml2.metadata.Organization;
import org.opensaml.saml.saml2.metadata.RequestedAttribute;
import org.opensaml.security.credential.Credential;
-import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
-import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException;
-
/**
* PVP Metadata builder configuration.
*
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java
index 39536771..cc492345 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java
@@ -27,7 +27,7 @@ import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver;
* @author tlenz
*
*/
-public interface IRefreshableMetadataProvider extends RefreshableMetadataResolver{
+public interface IRefreshableMetadataProvider extends RefreshableMetadataResolver {
/**
* Refresh a entity or load a entity in a metadata provider.
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/IAuthnRequestPostProcessor.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/IAuthnRequestPostProcessor.java
index 2e84413e..9f7a5980 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/IAuthnRequestPostProcessor.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/IAuthnRequestPostProcessor.java
@@ -31,7 +31,8 @@ import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
* SAML2 Authn. request post-processor.
*
* <p>
- * Implementations of this interface are executed before user authentication starts.
+ * Implementations of this interface are executed before user authentication
+ * starts.
* </p>
*
* @author tlenz
@@ -42,12 +43,13 @@ public interface IAuthnRequestPostProcessor {
/**
* Authn. request post-processor
*
- * @param httpReq http request
- * @param pendingReq current pending request
- * @param authReq received SAML2 authentication request
+ * @param httpReq http request
+ * @param pendingReq current pending request
+ * @param authReq received SAML2 authentication request
* @param spSsoDescriptor Metadata descriptor of the requested SP
- * @throws AuthnRequestValidatorException In case of a validation error,
- * if post processor implements additional validation
+ * @throws AuthnRequestValidatorException In case of a validation error, if post
+ * processor implements additional
+ * validation
*/
void process(HttpServletRequest httpReq, IRequest pendingReq, AuthnRequest authReq,
SPSSODescriptor spSsoDescriptor) throws AuthnRequestValidatorException;
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/Pvp2InternalErrorException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/Pvp2InternalErrorException.java
new file mode 100644
index 00000000..0b69897b
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/Pvp2InternalErrorException.java
@@ -0,0 +1,12 @@
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+public class Pvp2InternalErrorException extends Pvp2Exception {
+
+ private static final long serialVersionUID = 496637421176810375L;
+
+ public Pvp2InternalErrorException(Throwable wrapped) {
+ super("internal.pvp.98", new Object[] { wrapped.getMessage() }, wrapped);
+
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java
new file mode 100644
index 00000000..774d0927
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java
@@ -0,0 +1,12 @@
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+public class SamlMessageValidationException extends Pvp2Exception {
+
+ private static final long serialVersionUID = 2545822499416501014L;
+
+ public SamlMessageValidationException(String messageId, Object[] parameters, Throwable wrapped) {
+ super(messageId, parameters, wrapped);
+
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMetadataSignatureException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMetadataSignatureException.java
index 711fa41f..9ef3a673 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMetadataSignatureException.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMetadataSignatureException.java
@@ -21,17 +21,33 @@ package at.gv.egiz.eaaf.modules.pvp2.exception;
import org.opensaml.saml.saml2.core.StatusCode;
-public class SamlMetadataSignatureException extends Pvp2Exception {
+public class SamlMetadataSignatureException extends Pvp2MetadataException {
private static final long serialVersionUID = 1L;
- public SamlMetadataSignatureException() {
- super("pvp2.25", null);
+ /**
+ * In case of a SAML2 metadata-signature verification error.
+ *
+ * @param metadataUrl Path metadata that should be loaded
+ * @param reason Details on error
+ *
+ */
+ public SamlMetadataSignatureException(String metadataUrl, String reason) {
+ super("internal.pvp.07", new Object[] { metadataUrl, reason });
this.statusCodeValue = StatusCode.REQUESTER;
+
}
- public SamlMetadataSignatureException(final Throwable e) {
- super("pvp2.25", null, e);
+ /**
+ * In case of a SAML2 metadata-signature verification error.
+ *
+ * @param metadataUrl Path metadata that should be loaded
+ * @param reason Details on error
+ * @param e Error
+ */
+ public SamlMetadataSignatureException(String metadataUrl, String reason, final Throwable e) {
+ super("internal.pvp.07", new Object[] { metadataUrl, reason }, e);
this.statusCodeValue = StatusCode.REQUESTER;
+
}
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java
index ae108c35..3543d85a 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java
@@ -1,15 +1,29 @@
package at.gv.egiz.eaaf.modules.pvp2.impl.binding;
+import javax.xml.namespace.QName;
+
import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
+import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception;
+import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SamlMessageValidationException;
import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse;
import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain;
import org.opensaml.core.config.ConfigurationService;
import org.opensaml.messaging.context.BaseContext;
import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.decoder.MessageDecodingException;
+import org.opensaml.messaging.decoder.servlet.HttpServletRequestMessageDecoder;
+import org.opensaml.messaging.handler.MessageHandlerException;
import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.common.SignableSAMLObject;
import org.opensaml.saml.common.binding.SAMLBindingSupport;
@@ -19,6 +33,8 @@ import org.opensaml.saml.common.messaging.context.SAMLMessageInfoContext;
import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
import org.opensaml.saml.common.messaging.context.SAMLProtocolContext;
import org.opensaml.saml.common.xml.SAMLConstants;
+import org.opensaml.saml.saml2.core.RequestAbstractType;
+import org.opensaml.saml.saml2.core.StatusResponseType;
import org.opensaml.saml.saml2.metadata.SingleSignOnService;
import org.opensaml.saml.saml2.metadata.impl.SingleSignOnServiceBuilder;
import org.opensaml.xmlsec.SignatureSigningParameters;
@@ -28,21 +44,62 @@ import org.opensaml.xmlsec.context.SecurityParametersContext;
import org.opensaml.xmlsec.signature.support.SignatureConstants;
import org.springframework.beans.factory.annotation.Autowired;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.base.Throwables;
+import com.google.common.collect.FluentIterable;
+import lombok.extern.slf4j.Slf4j;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
/**
* Abstract Binding implements common code for SAML2 binding implementations.
*
* @author tlenz
*
*/
+@Slf4j
public abstract class AbstractBinding {
- @Autowired protected IConfiguration basicConfig;
+ @Autowired
+ protected IConfiguration basicConfig;
public abstract String getSaml2BindingName();
+ protected MessageContext<SAMLObject> internalMessageDecode(
+ HttpServletRequestMessageDecoder<SAMLObject> decoder,
+ String binding) throws Pvp2Exception {
+ try {
+ decoder.initialize();
+ decoder.decode();
+
+ } catch (final ComponentInitializationException e) {
+ log.warn("Internal initialization error. Reason: {}", e.getMessage());
+ throw new Pvp2InternalErrorException(e);
+
+ } catch (final MessageDecodingException e) {
+ final Optional<Throwable> pvpException = FluentIterable.from(
+ Throwables.getCausalChain(e)).filter(
+ Predicates.instanceOf(Pvp2Exception.class)).first();
+
+ if (pvpException.isPresent()) {
+ throw (Pvp2Exception) pvpException.get();
+
+ } else {
+ throw new SamlBindingException("internal.pvp.95",
+ new Object[] { binding, "decoding", e.getMessage() },
+ e);
+
+ }
+
+ }
+
+ return decoder.getMessageContext();
+
+ }
+
protected MessageContext<SAMLObject> buildBasicMessageContext(
SAMLMessageEncoder encoder, SignableSAMLObject response) {
- final MessageContext<SAMLObject> messageContext = new MessageContext<SAMLObject>();
+ final MessageContext<SAMLObject> messageContext = new MessageContext<>();
messageContext.setMessage(response);
encoder.setMessageContext(messageContext);
return messageContext;
@@ -63,7 +120,7 @@ public abstract class AbstractBinding {
signingParams.setSignatureReferenceDigestMethod(
Saml2Utils.getDigestAlgorithm(signingParams.getSignatureAlgorithm()));
- signingParams.setKeyInfoGenerator(Saml2Utils.getKeyInfoGenerator(credentials, false));
+ signingParams.setKeyInfoGenerator(Saml2Utils.getKeyInfoGenerator(credentials, true));
return securityParamContext;
@@ -83,16 +140,16 @@ public abstract class AbstractBinding {
}
protected void injectInboundMessageContexts(MessageContext<SAMLObject> messageContext,
- IPvp2MetadataProvider metadataProvider) {
- messageContext.addSubcontext(new SAMLPeerEntityContext());
+ IPvp2MetadataProvider metadataProvider, QName peerEntityRole) throws Pvp2InternalErrorException {
+ final SAMLPeerEntityContext peerEntityContext = new SAMLPeerEntityContext();
+ peerEntityContext.setRole(peerEntityRole);
+ messageContext.addSubcontext(peerEntityContext);
messageContext.addSubcontext(new SAMLMessageInfoContext());
-
final SAMLProtocolContext protocolContext = new SAMLProtocolContext();
protocolContext.setProtocol(SAMLConstants.SAML20P_NS);
messageContext.addSubcontext(protocolContext);
-
final SecurityParametersContext securityParameterContext = new SecurityParametersContext();
final SignatureValidationParameters sigValParameters = new SignatureValidationParameters();
securityParameterContext.setSignatureValidationParameters(sigValParameters);
@@ -100,9 +157,63 @@ public abstract class AbstractBinding {
sigValParameters.setBlacklistedAlgorithms(
ConfigurationService.get(SignatureValidationConfiguration.class)
- .getBlacklistedAlgorithms());
+ .getBlacklistedAlgorithms());
sigValParameters.setSignatureTrustEngine(
TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider));
}
+
+ protected void performMessageValidation(PvpSamlMessageHandlerChain messageValidatorChain,
+ MessageContext<SAMLObject> messageContext) throws Pvp2Exception {
+ try {
+ messageValidatorChain.initialize();
+ messageValidatorChain.invoke(messageContext);
+
+ } catch (final ComponentInitializationException e) {
+ log.warn("Internal initialization error. Reason: {}", e.getMessage());
+ throw new Pvp2InternalErrorException(e);
+
+ } catch (final MessageHandlerException e) {
+ log.info("SAML message validation error. Reason: {}", e.getMessage());
+ final Optional<Throwable> pvpException = FluentIterable.from(
+ Throwables.getCausalChain(e)).filter(
+ Predicates.instanceOf(Pvp2Exception.class)).first();
+
+ if (pvpException.isPresent()) {
+ throw (Pvp2Exception) pvpException.get();
+
+ } else {
+ throw new SamlMessageValidationException("internal.pvp.11",
+ new Object[] { e.getMessage() }, e);
+
+ }
+ }
+ }
+
+ protected InboundMessageInterface performMessageDecodePostProcessing(
+ MessageContext<SAMLObject> messageContext, boolean isVerified) {
+ InboundMessage msg = null;
+ if (messageContext.getMessage() instanceof RequestAbstractType) {
+ final RequestAbstractType inboundMessage =
+ (RequestAbstractType) messageContext.getMessage();
+ msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName());
+ msg.setEntityID(inboundMessage.getIssuer().getValue());
+
+ } else if (messageContext.getMessage() instanceof StatusResponseType) {
+ final StatusResponseType inboundMessage =
+ (StatusResponseType) messageContext.getMessage();
+ msg = new PvpSProfileResponse(inboundMessage);
+ msg.setEntityID(inboundMessage.getIssuer().getValue());
+
+ } else {
+ // create empty container if request type is unknown
+ msg = new InboundMessage();
+
+ }
+
+ msg.setVerified(isVerified);
+ msg.setRelayState(SAMLBindingSupport.getRelayState(messageContext));
+
+ return msg;
+ }
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java
index 6f39392d..c679de20 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java
@@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.binding;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
import at.gv.egiz.eaaf.core.api.IRequest;
import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfigurationFactory;
@@ -36,16 +37,17 @@ import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException;
import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception;
import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException;
-import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage;
-import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest;
-import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse;
import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.EaafHttpPostDecoder;
import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.HttpPostEncoderWithOwnTemplate;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafSamlProtocolMessageXmlSignatureSecurityHandler;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain;
import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.decoder.MessageDecodingException;
import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.common.binding.SAMLBindingSupport;
+import org.opensaml.saml.common.binding.impl.CheckMessageVersionHandler;
+import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHandler;
+import org.opensaml.saml.common.binding.security.impl.ReceivedEndpointSecurityHandler;
import org.opensaml.saml.common.messaging.SAMLMessageSecuritySupport;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.core.RequestAbstractType;
@@ -53,7 +55,6 @@ import org.opensaml.saml.saml2.core.StatusResponseType;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.extern.slf4j.Slf4j;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.net.URIComparator;
@Slf4j
@@ -78,35 +79,34 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder {
guiConfigFactory.getSpSpecificSaml2PostConfiguration(pendingReq,
"pvp_postbinding_template.html", authConfig.getConfigurationRootDirectory());
- final HttpPostEncoderWithOwnTemplate encoder
- = new HttpPostEncoderWithOwnTemplate(guiConfig, guiBuilder);
+ final HttpPostEncoderWithOwnTemplate encoder = new HttpPostEncoderWithOwnTemplate(guiConfig,
+ guiBuilder);
encoder.setHttpServletResponse(httpResp);
- //inject message context
+ // inject message context
final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, request);
- //inject signing context
+ // inject signing context
messageContext.addSubcontext(injectSigningInfos(credentials));
- //set endpoint url
+ // set endpoint url
messageContext.addSubcontext(injectEndpointInfos(request, targetLocation));
-
- //set relayState of exists
+ // set relayState of exists
SAMLBindingSupport.setRelayState(messageContext, relayState);
- //sign SAML2 message
+ // sign SAML2 message
SAMLMessageSecuritySupport.signMessage(messageContext);
- //encode message
+ // encode message
encoder.initialize();
encoder.encode();
} catch (final Exception e) {
log.warn("Can not encode SAML2 Post-Binding request", e);
throw new SamlBindingException("internal.pvp.95",
- new Object[] {PvpConstants.POST, "encoding", e.getMessage()},
+ new Object[] { PvpConstants.POST, "encoding", e.getMessage() },
e);
}
@@ -116,7 +116,7 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder {
public void encodeResponse(final HttpServletRequest httpReq, final HttpServletResponse httpResp,
final StatusResponseType response, final String targetLocation, final String relayState,
final EaafX509Credential credentials, final IRequest pendingReq)
- throws Pvp2Exception {
+ throws Pvp2Exception {
try {
log.debug("create SAML POSTBinding response");
@@ -130,99 +130,62 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder {
encoder.setHttpServletResponse(httpResp);
- //inject message context
+ // inject message context
final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, response);
- //inject signing context
+ // inject signing context
messageContext.addSubcontext(injectSigningInfos(credentials));
- //set endpoint url
+ // set endpoint url
messageContext.addSubcontext(injectEndpointInfos(response, targetLocation));
- //set relayState of exists
+ // set relayState of exists
SAMLBindingSupport.setRelayState(messageContext, relayState);
- //sign SAML2 message
+ // sign SAML2 message
SAMLMessageSecuritySupport.signMessage(messageContext);
- //encode message
+ // encode message
encoder.initialize();
encoder.encode();
} catch (final Exception e) {
log.warn("Can not encode SAML2 Post-Binding response", e);
throw new SamlBindingException("internal.pvp.95",
- new Object[] {PvpConstants.POST, "encoding", e.getMessage()},
+ new Object[] { PvpConstants.POST, "encoding", e.getMessage() },
e);
}
}
-
-
-
-
@Override
public InboundMessageInterface decode(final HttpServletRequest req,
final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider,
- final boolean isSpEndPoint, final URIComparator comparator)
+ QName peerEntityRole, final URIComparator comparator)
throws Pvp2Exception {
- //TODO: check, if we should re-implement HTTPPostDecoder to collect the last http parameter!!!
- final EaafHttpPostDecoder decode = new EaafHttpPostDecoder();
- decode.setHttpServletRequest(req);
-
- //decode request
- try {
- decode.initialize();
- decode.decode();
-
- } catch (MessageDecodingException | ComponentInitializationException e) {
- throw new SamlBindingException("internal.pvp.95",
- new Object[] {PvpConstants.POST, "decoding", e.getMessage()},
- e);
- }
-
- final MessageContext<SAMLObject> messageContext = decode.getMessageContext();
+ final EaafHttpPostDecoder decode = new EaafHttpPostDecoder(req);
+ final MessageContext<SAMLObject> messageContext = internalMessageDecode(decode, PvpConstants.POST);
- if (SAMLBindingSupport.isSigningCapableBinding(messageContext)) {
+ // check if PVP2 AuthnRequest is signed
+ if (!SAMLBindingSupport.isMessageSigned(messageContext)) {
log.info("SAML Post-Binding message contains no signature. Message will be rejected");
throw new InvalidPvpRequestException("internal.pvp.02", null);
}
- //inject informations into message context that are required for further processing
- injectInboundMessageContexts(messageContext, metadataProvider);
+ // inject informations into message context that are required for further
+ // processing
+ injectInboundMessageContexts(messageContext, metadataProvider, peerEntityRole);
+ final PvpSamlMessageHandlerChain messageValidatorChain =
+ buildMessageValidationChain(req, comparator, metadataProvider);
+ log.trace("Message validation (Signature, ...) on binding-level starts ... ");
+ performMessageValidation(messageValidatorChain, messageContext);
- //TODO: add sig validation!!!
+ log.trace("Message validation successful");
+ return performMessageDecodePostProcessing(messageContext, true);
-
-
- InboundMessage msg = null;
-
- if (messageContext.getMessage() instanceof RequestAbstractType) {
- final RequestAbstractType inboundMessage =
- (RequestAbstractType) messageContext.getMessage();
- msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName());
- msg.setEntityID(inboundMessage.getIssuer().getValue());
-
- } else if (messageContext.getMessage() instanceof StatusResponseType) {
- final StatusResponseType inboundMessage =
- (StatusResponseType) messageContext.getMessage();
- msg = new PvpSProfileResponse(inboundMessage);
- msg.setEntityID(inboundMessage.getIssuer().getValue());
-
- } else {
- // create empty container if request type is unknown
- msg = new InboundMessage();
-
- }
-
- msg.setVerified(false);
- msg.setRelayState(SAMLBindingSupport.getRelayState(messageContext));
-
- return msg;
}
@Override
@@ -234,5 +197,41 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder {
@Override
public String getSaml2BindingName() {
return SAMLConstants.SAML2_POST_BINDING_URI;
+
+ }
+
+ private PvpSamlMessageHandlerChain buildMessageValidationChain(HttpServletRequest req,
+ URIComparator comparator, IPvp2MetadataProvider metadataProvider) {
+ final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain();
+
+ final ReceivedEndpointSecurityHandler endpointSecurityHandler = new ReceivedEndpointSecurityHandler();
+ endpointSecurityHandler.setHttpServletRequest(req);
+ endpointSecurityHandler.setURIComparator(comparator);
+
+ messageValidatorChain.addHandler(new CheckMessageVersionHandler());
+ messageValidatorChain.addHandler(endpointSecurityHandler);
+ messageValidatorChain.addHandler(
+ new EaafSamlProtocolMessageXmlSignatureSecurityHandler(metadataProvider));
+ messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler());
+
+ /*
+ * TODO: maybe we add it in a later version Because: - AuthnRequest replay
+ * should not be a problem on IDP side - Response replay will be not possible,
+ * because EAAF PVP implements countermeasure based on one-time tokens for each
+ * request
+ *
+ */
+ // final MessageReplaySecurityHandler replaySecurityHandler = new
+ // MessageReplaySecurityHandler();
+ // final StorageService replayCacheStorage = null;
+ // final ReplayCache replayCache = new ReplayCache();
+ // replayCache.setId("Message replay cache");
+ // replayCache.setStrict(true);
+ // replayCache.setStorage(replayCacheStorage);
+ // replaySecurityHandler.setReplayCache(replayCache );
+ // messageValidatorChain.addHandler(replaySecurityHandler);
+
+ return messageValidatorChain;
+
}
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java
index 5f74053d..f62f8a11 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java
@@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.binding;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
import at.gv.egiz.eaaf.core.api.IRequest;
import at.gv.egiz.eaaf.modules.pvp2.PvpConstants;
@@ -32,15 +33,11 @@ import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException;
import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception;
import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException;
-import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage;
-import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest;
-import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse;
import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.EaafHttpRedirectDeflateDecoder;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafSaml2HttpRedirectDeflateSignatureSecurityHandler;
import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain;
import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.decoder.MessageDecodingException;
-import org.opensaml.messaging.handler.MessageHandlerException;
import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.common.binding.SAMLBindingSupport;
import org.opensaml.saml.common.binding.impl.CheckMessageVersionHandler;
@@ -48,13 +45,11 @@ import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHan
import org.opensaml.saml.common.messaging.context.SAMLBindingContext;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.binding.encoding.impl.HTTPRedirectDeflateEncoder;
-import org.opensaml.saml.saml2.binding.security.impl.SAML2HTTPRedirectDeflateSignatureSecurityHandler;
import org.opensaml.saml.saml2.core.RequestAbstractType;
import org.opensaml.saml.saml2.core.StatusResponseType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.net.URIComparator;
public class RedirectBinding extends AbstractBinding implements IDecoder, IEncoder {
@@ -137,26 +132,11 @@ public class RedirectBinding extends AbstractBinding implements IDecoder, IEncod
@Override
public InboundMessageInterface decode(final HttpServletRequest req,
final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider,
- final boolean isSpEndPoint, final URIComparator comparator)
+ QName peerEntityRole, final URIComparator comparator)
throws Pvp2Exception {
- // TODO: implement one flat decoder to get SAML2 request/response parametes as
- // same as in SAML2HTTPRedirectDeflateSignatureSecurityHandler
- final EaafHttpRedirectDeflateDecoder decode = new EaafHttpRedirectDeflateDecoder();
- decode.setHttpServletRequest(req);
-
- // decode request
- try {
- decode.initialize();
- decode.decode();
-
- } catch (MessageDecodingException | ComponentInitializationException e) {
- throw new SamlBindingException("internal.pvp.95",
- new Object[] { PvpConstants.REDIRECT, "decoding", e.getMessage() },
- e);
- }
-
- final MessageContext<SAMLObject> messageContext = decode.getMessageContext();
+ final EaafHttpRedirectDeflateDecoder decode = new EaafHttpRedirectDeflateDecoder(req);
+ final MessageContext<SAMLObject> messageContext = internalMessageDecode(decode, PvpConstants.REDIRECT);
final SAMLBindingContext bindingContext = messageContext.getSubcontext(SAMLBindingContext.class, true);
if (!bindingContext.hasBindingSignature()) {
@@ -165,171 +145,18 @@ public class RedirectBinding extends AbstractBinding implements IDecoder, IEncod
}
- //inject informations into message context that are required for further processing
- injectInboundMessageContexts(messageContext, metadataProvider);
+ // inject informations into message context that are required for further
+ // processing
+ injectInboundMessageContexts(messageContext, metadataProvider, peerEntityRole);
+ final PvpSamlMessageHandlerChain messageValidatorChain =
+ buildMessageValidationChain(req, metadataProvider);
- log.trace("Signature validation on binding-level starts ... ");
- final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain();
- final SAML2HTTPRedirectDeflateSignatureSecurityHandler redirectBindingSignaturHandler =
- new SAML2HTTPRedirectDeflateSignatureSecurityHandler();
- redirectBindingSignaturHandler.setHttpServletRequest(req);
-
- messageValidatorChain.addHandler(new CheckMessageVersionHandler());
- messageValidatorChain.addHandler(redirectBindingSignaturHandler);
- messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler());
-
-
- /*TODO: maybe we add it in a later version
- * Because:
- * - AuthnRequest replay should not be a problem on IDP side
- * - Response replay will be not possible, because EAAF PVP implements
- * countermeasure based on one-time tokens for each request
- *
- */
- //final MessageReplaySecurityHandler replaySecurityHandler = new MessageReplaySecurityHandler();
- //final StorageService replayCacheStorage = null;
- //final ReplayCache replayCache = new ReplayCache();
- //replayCache.setId("Message replay cache");
- //replayCache.setStrict(true);
- //replayCache.setStorage(replayCacheStorage);
- //replaySecurityHandler.setReplayCache(replayCache );
- //messageValidatorChain.addHandler(replaySecurityHandler);
+ log.trace("Message validation (Signature, ...) on binding-level starts ... ");
+ performMessageValidation(messageValidatorChain, messageContext);
+ log.trace("Message validation successful");
+ return performMessageDecodePostProcessing(messageContext, true);
- try {
- messageValidatorChain.initialize();
- messageValidatorChain.invoke(messageContext);
-
- } catch (final ComponentInitializationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
-
- } catch (final MessageHandlerException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- InboundMessage msg = null;
-
- if (messageContext.getMessage() instanceof RequestAbstractType) {
- final RequestAbstractType inboundMessage =
- (RequestAbstractType) messageContext.getMessage();
- msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName());
- msg.setEntityID(inboundMessage.getIssuer().getValue());
-
- } else if (messageContext.getMessage() instanceof StatusResponseType) {
- final StatusResponseType inboundMessage =
- (StatusResponseType) messageContext.getMessage();
- msg = new PvpSProfileResponse(inboundMessage);
- msg.setEntityID(inboundMessage.getIssuer().getValue());
-
- } else {
- // create empty container if request type is unknown
- msg = new InboundMessage();
-
- }
-
- msg.setVerified(false);
- msg.setRelayState(SAMLBindingSupport.getRelayState(messageContext));
-
- return msg;
-
-// final BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext =
-// new BasicSAMLMessageContext<>();
-// messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(req));
-//
-// // set metadata descriptor type
-// if (isSpEndPoint) {
-// messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
-// decode.setURIComparator(comparator);
-//
-// } else {
-// messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
-// decode.setURIComparator(comparator);
-// }
-//
-// messageContext.setMetadataProvider(metadataProvider);
-//
-// final SAML2HTTPRedirectDeflateSignatureRule signatureRule =
-// new SAML2HTTPRedirectDeflateSignatureRule(
-// TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider));
-// final PvpAuthRequestSignedRole signedRole = new PvpAuthRequestSignedRole();
-// final BasicSecurityPolicy policy = new BasicSecurityPolicy();
-// policy.getPolicyRules().add(signedRole);
-// policy.getPolicyRules().add(signatureRule);
-// final SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver(policy);
-// messageContext.setSecurityPolicyResolver(resolver);
-//
-// // set metadata descriptor type
-// if (isSpEndPoint) {
-// messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
-// } else {
-// messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
-// }
-//
-// SAML2AuthnRequestsSignedSecurityHandler
-//
-// try {
-// decode.decode(messageContext);
-//
-// // check signature
-// signatureRule.evaluate(messageContext);
-//
-// } catch (final SecurityException e) {
-// if (StringUtils.isEmpty(messageContext.getInboundMessageIssuer())) {
-// throw e;
-//
-// }
-//
-// if (metadataProvider instanceof IRefreshableMetadataProvider) {
-// log.debug("PVP2X message validation FAILED. Reload metadata for entityID: "
-// + messageContext.getInboundMessageIssuer());
-// if (!((IRefreshableMetadataProvider) metadataProvider)
-// .refreshMetadataProvider(messageContext.getInboundMessageIssuer())) {
-// throw e;
-// } else {
-// log.trace("PVP2X metadata reload finished. Check validate message again.");
-// decode.decode(messageContext);
-//
-// // check signature
-// signatureRule.evaluate(messageContext);
-//
-// }
-// log.trace("Second PVP2X message validation finished");
-//
-// } else {
-// throw e;
-//
-// }
-// }
-//
-// InboundMessage msg = null;
-// if (messageContext.getInboundMessage() instanceof RequestAbstractType) {
-// final RequestAbstractType inboundMessage =
-// (RequestAbstractType) messageContext.getInboundMessage();
-// msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName());
-//
-// } else if (messageContext.getInboundMessage() instanceof StatusResponseType) {
-// final StatusResponseType inboundMessage =
-// (StatusResponseType) messageContext.getInboundMessage();
-// msg = new PvpSProfileResponse(inboundMessage);
-//
-// } else {
-// // create empty container if request type is unknown
-// msg = new InboundMessage();
-// }
-//
-// if (messageContext.getPeerEntityMetadata() != null) {
-// msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID());
-// } else {
-// log.info(
-// "No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer());
-// }
-//
-// msg.setVerified(true);
-// msg.setRelayState(messageContext.getRelayState());
-//
-// return msg;
}
@Override
@@ -341,5 +168,38 @@ public class RedirectBinding extends AbstractBinding implements IDecoder, IEncod
@Override
public String getSaml2BindingName() {
return SAMLConstants.SAML2_REDIRECT_BINDING_URI;
+
+ }
+
+ private PvpSamlMessageHandlerChain buildMessageValidationChain(HttpServletRequest req,
+ IPvp2MetadataProvider metadataProvider) {
+ final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain();
+ final EaafSaml2HttpRedirectDeflateSignatureSecurityHandler redirectBindingSignaturHandler =
+ new EaafSaml2HttpRedirectDeflateSignatureSecurityHandler(metadataProvider);
+ redirectBindingSignaturHandler.setHttpServletRequest(req);
+
+ messageValidatorChain.addHandler(new CheckMessageVersionHandler());
+ messageValidatorChain.addHandler(redirectBindingSignaturHandler);
+ messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler());
+
+ /*
+ * TODO: maybe we add it in a later version Because: - AuthnRequest replay
+ * should not be a problem on IDP side - Response replay will be not possible,
+ * because EAAF PVP implements countermeasure based on one-time tokens for each
+ * request
+ *
+ */
+ // final MessageReplaySecurityHandler replaySecurityHandler = new
+ // MessageReplaySecurityHandler();
+ // final StorageService replayCacheStorage = null;
+ // final ReplayCache replayCache = new ReplayCache();
+ // replayCache.setId("Message replay cache");
+ // replayCache.setStrict(true);
+ // replayCache.setStorage(replayCacheStorage);
+ // replaySecurityHandler.setReplayCache(replayCache );
+ // messageValidatorChain.addHandler(replaySecurityHandler);
+
+ return messageValidatorChain;
+
}
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java
index e0df2d2a..49e93f0a 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java
@@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.binding;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
import at.gv.egiz.eaaf.core.api.IRequest;
import at.gv.egiz.eaaf.modules.pvp2.PvpConstants;
@@ -29,27 +30,29 @@ import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder;
import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
-import at.gv.egiz.eaaf.modules.pvp2.exception.AttributQueryException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException;
import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception;
+import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException;
import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafMessageContextInitializationHandler;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafSamlProtocolMessageXmlSignatureSecurityHandler;
import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain;
import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.decoder.MessageDecodingException;
import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.common.binding.SAMLBindingSupport;
import org.opensaml.saml.common.binding.impl.CheckMessageVersionHandler;
import org.opensaml.saml.common.binding.impl.SAMLProtocolAndRoleHandler;
import org.opensaml.saml.common.binding.impl.SAMLSOAPDecoderBodyHandler;
import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHandler;
-import org.opensaml.saml.common.binding.security.impl.SAMLProtocolMessageXMLSignatureSecurityHandler;
import org.opensaml.saml.common.messaging.SAMLMessageSecuritySupport;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.binding.decoding.impl.HTTPSOAP11Decoder;
import org.opensaml.saml.saml2.binding.encoding.impl.HTTPSOAP11Encoder;
import org.opensaml.saml.saml2.core.RequestAbstractType;
import org.opensaml.saml.saml2.core.StatusResponseType;
+import org.opensaml.soap.messaging.context.SOAP11Context;
import lombok.extern.slf4j.Slf4j;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -61,72 +64,55 @@ public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder {
@Override
public InboundMessageInterface decode(final HttpServletRequest req,
final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider,
- final boolean isSpEndPoint, final URIComparator comparator)
+ QName peerEntityRole, final URIComparator comparator)
throws Pvp2Exception {
- try {
- final HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder();
+ final HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder();
+ soapDecoder.setHttpServletRequest(req);
+
+ injectMessageHandlerChain(soapDecoder, metadataProvider, peerEntityRole);
+
+ final MessageContext<SAMLObject> messageContext =
+ internalMessageDecode(soapDecoder, PvpConstants.SOAP);
+
+ // check if PVP2 AuthnRequest is signed
+ if (!SAMLBindingSupport.isMessageSigned(messageContext)) {
+ log.info("SAML Post-Binding message contains no signature. Message will be rejected");
+ throw new InvalidPvpRequestException("internal.pvp.02", null);
+
+ }
+
+ return performMessageDecodePostProcessing(messageContext, true);
+ }
+ private void injectMessageHandlerChain(HTTPSOAP11Decoder soapDecoder,
+ IPvp2MetadataProvider metadataProvider, QName peerEntityRole) throws Pvp2InternalErrorException {
+ try {
final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain();
- soapDecoder.setBodyHandler(messageValidatorChain);
+ messageValidatorChain.addHandler(new EaafMessageContextInitializationHandler(metadataProvider));
+ messageValidatorChain.addHandler(new SAMLSOAPDecoderBodyHandler());
- final SAMLProtocolMessageXMLSignatureSecurityHandler msgSignatureValidationHandler =
- new SAMLProtocolMessageXMLSignatureSecurityHandler();
+ final SAMLProtocolAndRoleHandler samlProtocolHandler = new SAMLProtocolAndRoleHandler();
+ samlProtocolHandler.setProtocol(SAMLConstants.SAML20P_NS);
+ samlProtocolHandler.setRole(peerEntityRole);
+ messageValidatorChain.addHandler(samlProtocolHandler);
- messageValidatorChain.addHandler(new EaafMessageContextInitializationHandler());
messageValidatorChain.addHandler(new CheckMessageVersionHandler());
- messageValidatorChain.addHandler(new SAMLProtocolAndRoleHandler());
- messageValidatorChain.addHandler(msgSignatureValidationHandler);
+ messageValidatorChain.addHandler(
+ new EaafSamlProtocolMessageXmlSignatureSecurityHandler(metadataProvider));
messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler());
- messageValidatorChain.addHandler(new SAMLSOAPDecoderBodyHandler());
- // decode message
- soapDecoder.initialize();
- soapDecoder.decode();
+ messageValidatorChain.initialize();
- final MessageContext<SAMLObject> messageContext = soapDecoder.getMessageContext();
- messageContext.getMessage();
+ soapDecoder.setBodyHandler(messageValidatorChain);
+
+ } catch (final ComponentInitializationException e) {
+ log.warn("Internal initialization error. Reason: {}", e.getMessage());
+ throw new Pvp2InternalErrorException(e);
- } catch (MessageDecodingException | ComponentInitializationException e) {
- throw new SamlBindingException("internal.pvp.95",
- new Object[] { PvpConstants.POST, "decoding", e.getMessage() },
- e);
}
-// final Envelope inboundMessage = (Envelope) messageContext.getMessage();
-//
-// if (inboundMessage.getBody() != null) {
-// final List<XMLObject> xmlElemList = inboundMessage.getBody().getUnknownXMLObjects();
-//
-// if (!xmlElemList.isEmpty()) {
-// final SignableXMLObject attrReq = (SignableXMLObject) xmlElemList.get(0);
-// final PvpSProfileRequest request = new PvpSProfileRequest(attrReq, getSaml2BindingName());
-//
-// if (messageContext.getPeerEntityMetadata() != null) {
-// request.setEntityID(messageContext.getPeerEntityMetadata().getEntityID());
-//
-// } else if (attrReq instanceof RequestAbstractType) {
-// final RequestAbstractType attributeRequest = (RequestAbstractType) attrReq;
-// try {
-// if (StringUtils.isNotEmpty(attributeRequest.getIssuer().getValue())
-// && metadataProvider.getRole(attributeRequest.getIssuer().getValue(),
-// SPSSODescriptor.DEFAULT_ELEMENT_NAME) != null) {
-// request.setEntityID(attributeRequest.getIssuer().getValue());
-// }
-//
-// } catch (final Exception e) {
-// log.warn("No Metadata found with EntityID " + attributeRequest.getIssuer().getValue());
-// }
-// }
-//
-// request.setVerified(false);
-// return request;
-//
-// }
-// }
-
- log.error("Receive empty PVP 2.1 attributequery request.");
- throw new AttributQueryException("Receive empty PVP 2.1 attributequery request.", null);
+
}
@Override
@@ -157,6 +143,11 @@ public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder {
// inject message context
final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, response);
+ //inject SOAP enveloped
+ final SOAP11Context soap11Context = new SOAP11Context();
+ soap11Context.setEnvelope(Saml2Utils.buildSoap11Envelope(response));
+ messageContext.addSubcontext(soap11Context);
+
// inject signing context
messageContext.addSubcontext(injectSigningInfos(credentials));
@@ -172,6 +163,7 @@ public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder {
// encode message
encoder.initialize();
encoder.encode();
+
} catch (final Exception e) {
log.warn("Can not encode SAML2 SOAP-Binding response", e);
throw new SamlBindingException("internal.pvp.95",
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java
index 1667a07d..bf201803 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java
@@ -61,7 +61,8 @@ public class CitizenTokenBuilder {
*/
public static XMLObject buildAttributeIntegerValue(final int value) {
final XSIntegerBuilder integerBuilder =
- (XSIntegerBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(XSInteger.TYPE_NAME);
+ (XSIntegerBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(
+ XSInteger.TYPE_NAME);
final XSInteger integerValue =
integerBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSInteger.TYPE_NAME);
integerValue.setValue(value);
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java
index d5893d4a..92922e09 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java
@@ -20,6 +20,7 @@
package at.gv.egiz.eaaf.modules.pvp2.impl.builder;
import java.io.IOException;
+import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;
@@ -28,6 +29,13 @@ import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
+import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration;
+import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
+
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.opensaml.core.xml.io.MarshallingException;
@@ -57,14 +65,8 @@ import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory;
import org.opensaml.xmlsec.signature.support.SignatureException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
import org.w3c.dom.Element;
-import at.gv.egiz.eaaf.core.exceptions.EaafException;
-import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
-import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration;
-import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException;
-import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
import net.shibboleth.utilities.java.support.xml.SerializeSupport;
/**
@@ -74,9 +76,10 @@ import net.shibboleth.utilities.java.support.xml.SerializeSupport;
*
*/
-@Service("PVPMetadataBuilder")
public class PvpMetadataBuilder {
+ private static final String ERROR_ROLE_DESCR = "Can not build {0}";
+
private static final Logger log = LoggerFactory.getLogger(PvpMetadataBuilder.class);
X509KeyInfoGeneratorFactory keyInfoFactory = null;
@@ -133,6 +136,12 @@ public class PvpMetadataBuilder {
final RoleDescriptor idpSsoDesc = generateIdpMetadata(config);
if (idpSsoDesc != null) {
entityDescriptor.getRoleDescriptors().add(idpSsoDesc);
+
+ } else {
+ final String msg = MessageFormat.format(ERROR_ROLE_DESCR,
+ IDPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
+ throw new EaafBuilderException("internal.pvp.13", new Object[] { msg }, msg);
+
}
}
@@ -142,12 +151,17 @@ public class PvpMetadataBuilder {
final RoleDescriptor spSsoDesc = generateSpMetadata(config);
if (spSsoDesc != null) {
entityDescriptor.getRoleDescriptors().add(spSsoDesc);
+
+ } else {
+ final String msg = MessageFormat.format(ERROR_ROLE_DESCR, SPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
+ throw new EaafBuilderException("internal.pvp.13", new Object[] { msg }, msg);
+
}
}
-
+
SignableSAMLObject metadataToSign;
-
+
// build entities descriptor
if (config.buildEntitiesDescriptorAsRootElement()) {
final EntitiesDescriptor entitiesDescriptor =
@@ -157,24 +171,24 @@ public class PvpMetadataBuilder {
entitiesDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil()));
entitiesDescriptor.getEntityDescriptors().add(entityDescriptor);
metadataToSign = entitiesDescriptor;
-
+
} else {
entityDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil()));
entityDescriptor.setID(Saml2Utils.getSecureIdentifier());
metadataToSign = entityDescriptor;
-
+
}
// sign metadata
final EaafX509Credential metadataSignCred = config.getMetadataSigningCredentials();
- SignableSAMLObject signedMetadata = Saml2Utils.signSamlObject(metadataToSign, metadataSignCred, true);
-
-
+ final SignableSAMLObject signedMetadata = Saml2Utils.signSamlObject(metadataToSign, metadataSignCred,
+ true);
+
// Serialize metadata
- final Element document =XMLObjectSupport.marshall(signedMetadata);
- String serializedMetadata = SerializeSupport.nodeToString(document);
+ final Element document = XMLObjectSupport.marshall(signedMetadata);
+ final String serializedMetadata = SerializeSupport.nodeToString(document);
return serializedMetadata;
-
+
}
private RoleDescriptor generateSpMetadata(final IPvpMetadataBuilderConfiguration config)
@@ -402,7 +416,10 @@ public class PvpMetadataBuilder {
idpSsoDescriptor.getKeyDescriptors().add(signKeyDescriptor);
// set IDP attribute set
- idpSsoDescriptor.getAttributes().addAll(config.getIdpPossibleAttributes());
+ if (config.getIdpPossibleAttributes() != null) {
+ idpSsoDescriptor.getAttributes().addAll(config.getIdpPossibleAttributes());
+
+ }
// set providable nameID formats
for (final String format : config.getIdpPossibleNameIdTypes()) {
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java
index d37d6724..5c44af24 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java
@@ -44,7 +44,8 @@ public class SamlAttributeGenerator implements IAttributeGenerator<Attribute> {
private XMLObject buildAttributeIntegerValue(final int value) {
final XSIntegerBuilder integerBuilder =
- (XSIntegerBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(XSInteger.TYPE_NAME);
+ (XSIntegerBuilder) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(
+ XSInteger.TYPE_NAME);
final XSInteger integerValue =
integerBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSInteger.TYPE_NAME);
integerValue.setValue(value);
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java
index 961f29cb..227ff30e 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/logging/PvpModuleMessageSource.java
@@ -5,7 +5,6 @@ import java.util.List;
import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation;
-
public class PvpModuleMessageSource implements IMessageSourceLocation {
@Override
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java
index da958d5b..0ffa3789 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java
@@ -25,16 +25,17 @@ import java.io.Serializable;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
+import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
+import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException;
+
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
-import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
-import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
-import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
-import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
public class InboundMessage implements InboundMessageInterface, Serializable {
@@ -68,7 +69,7 @@ public class InboundMessage implements InboundMessageInterface, Serializable {
} catch (final ResolverException e) {
log.warn("No Metadata for EntitiyID " + entityID);
throw new NoMetadataInformationException();
-
+
}
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java
index 3fc675e9..8a20b932 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java
@@ -27,12 +27,17 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.naming.ConfigurationException;
+import at.gv.egiz.components.spring.api.IDestroyableObject;
+import at.gv.egiz.eaaf.core.api.IGarbageCollectorProcessing;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.opensaml.core.criterion.EntityIdCriterion;
@@ -43,11 +48,6 @@ import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
import org.opensaml.saml.metadata.resolver.impl.AbstractMetadataResolver;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
-import at.gv.egiz.components.spring.api.IDestroyableObject;
-import at.gv.egiz.eaaf.core.api.IGarbageCollectorProcessing;
-import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
-import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
-import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
import lombok.extern.slf4j.Slf4j;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.component.IdentifiedComponent;
@@ -55,10 +55,13 @@ import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
@Slf4j
-public abstract class AbstractChainingMetadataProvider implements IGarbageCollectorProcessing, IRefreshableMetadataProvider,
+public abstract class AbstractChainingMetadataProvider implements IGarbageCollectorProcessing,
+ IRefreshableMetadataProvider,
IDestroyableObject, IPvp2MetadataProvider, ClearableMetadataResolver {
-
- @Nonnull @NonnullElements private final List<MetadataResolver> internalResolvers;
+
+ @Nonnull
+ @NonnullElements
+ private final List<MetadataResolver> internalResolvers;
private DateTime lastRefeshTimestamp;
private boolean lastRefeshSuccessful;
private static Object mutex = new Object();
@@ -72,7 +75,6 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec
}
-
/*
* (non-Javadoc)
*
@@ -104,8 +106,6 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec
}
-
-
@Override
public synchronized boolean refreshMetadataProvider(final String entityId) {
try {
@@ -130,7 +130,7 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec
// check if MetadataProvider is actually loaded
final MetadataResolver loadedResover = actuallyLoadedResolver.get(metadataUrl);
if (loadedResover instanceof RefreshableMetadataResolver) {
- ((RefreshableMetadataResolver)loadedResover).refresh();
+ ((RefreshableMetadataResolver) loadedResover).refresh();
log.info("SAML2 metadata for service provider: " + entityId + " is refreshed.");
return true;
@@ -162,30 +162,29 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec
*
*/
public void internalDestroy() {
- log.info("Destroying chained metadata resolvers ...");
+ log.info("Destroying chained metadata resolvers ...");
- for (final MetadataResolver resolver : internalResolvers) {
- destroyMetadataResolver(resolver);
- }
+ for (final MetadataResolver resolver : internalResolvers) {
+ destroyMetadataResolver(resolver);
+ }
- internalResolvers.clear();
+ internalResolvers.clear();
}
- /** {@inheritDoc} */
- @Override
+ @Override
public final MetadataFilter getMetadataFilter() {
- log.warn("{} does NOT support {}", AbstractChainingMetadataProvider.class.getName(),
- MetadataFilter.class.getName());
- return null;
+ log.warn("{} does NOT support {}", AbstractChainingMetadataProvider.class.getName(),
+ MetadataFilter.class.getName());
+ return null;
}
- /** {@inheritDoc} */
- @Override
+ @Override
public final void setMetadataFilter(final MetadataFilter newFilter) {
log.warn("{} does NOT support {}", AbstractChainingMetadataProvider.class.getName(),
MetadataFilter.class.getName());
- throw new UnsupportedOperationException("Metadata filters are not supported on AbstractChainingMetadataProvider");
+ throw new UnsupportedOperationException(
+ "Metadata filters are not supported on AbstractChainingMetadataProvider");
}
/*
@@ -221,17 +220,17 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec
}
@Override
- @Nullable
+ @Nullable
public final EntityDescriptor resolveSingle(@Nullable final CriteriaSet criteria) throws ResolverException {
for (final MetadataResolver resolver : internalResolvers) {
try {
- final EntityDescriptor descriptors = resolver.resolveSingle(criteria);
- if (descriptors != null) {
- return descriptors;
- }
+ final EntityDescriptor descriptors = resolver.resolveSingle(criteria);
+ if (descriptors != null) {
+ return descriptors;
+ }
} catch (final ResolverException e) {
- continue;
+ continue;
}
@@ -242,87 +241,90 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec
}
@Override
- @Nonnull
- public final Iterable<EntityDescriptor> resolve(@Nullable final CriteriaSet criteria) throws ResolverException {
- for (final MetadataResolver resolver : internalResolvers) {
- try {
- final Iterable<EntityDescriptor> descriptors = resolver.resolve(criteria);
- if (descriptors != null && descriptors.iterator().hasNext()) {
- return descriptors;
-
- }
-
- } catch (final ResolverException e) {
- continue;
-
- }
+ @Nonnull
+ public final Iterable<EntityDescriptor> resolve(@Nullable final CriteriaSet criteria)
+ throws ResolverException {
+ for (final MetadataResolver resolver : internalResolvers) {
+ try {
+ final Iterable<EntityDescriptor> descriptors = resolver.resolve(criteria);
+ if (descriptors != null && descriptors.iterator().hasNext()) {
+ return descriptors;
+
+ }
+
+ } catch (final ResolverException e) {
+ continue;
+
}
+ }
- return Collections.emptyList();
+ return Collections.emptyList();
}
-
+
@Override
public final void clear() throws ResolverException {
- for (final MetadataResolver resolver : internalResolvers) {
- if (resolver instanceof ClearableMetadataResolver) {
- ((ClearableMetadataResolver) resolver).clear();
- }
+ for (final MetadataResolver resolver : internalResolvers) {
+ if (resolver instanceof ClearableMetadataResolver) {
+ ((ClearableMetadataResolver) resolver).clear();
}
+ }
}
@Override
public final void clear(String entityID) throws ResolverException {
- for (final MetadataResolver resolver : internalResolvers) {
- if (resolver instanceof ClearableMetadataResolver) {
- ((ClearableMetadataResolver) resolver).clear(entityID);
- }
+ for (final MetadataResolver resolver : internalResolvers) {
+ if (resolver instanceof ClearableMetadataResolver) {
+ ((ClearableMetadataResolver) resolver).clear(entityID);
}
+ }
}
- @Override final public void refresh() throws ResolverException {
- this.lastRefeshSuccessful = false;
- for (final MetadataResolver resolver : internalResolvers) {
- if (resolver instanceof RefreshableMetadataResolver) {
- ((RefreshableMetadataResolver) resolver).refresh();
-
- }
+ @Override
+ public final void refresh() throws ResolverException {
+ this.lastRefeshSuccessful = false;
+ for (final MetadataResolver resolver : internalResolvers) {
+ if (resolver instanceof RefreshableMetadataResolver) {
+ ((RefreshableMetadataResolver) resolver).refresh();
+
}
-
- this.lastRefeshTimestamp = DateTime.now();
- this.lastRefeshSuccessful = true;
+ }
+
+ this.lastRefeshTimestamp = DateTime.now();
+ this.lastRefeshSuccessful = true;
}
@Override
- @Nullable public DateTime getLastUpdate() {
- DateTime ret = null;
- for (final MetadataResolver resolver : internalResolvers) {
- if (resolver instanceof RefreshableMetadataResolver) {
- final DateTime lastUpdate = ((RefreshableMetadataResolver) resolver).getLastUpdate();
- if (ret == null || ret.isBefore(lastUpdate)) {
- ret = lastUpdate;
- }
- }
+ @Nullable
+ public DateTime getLastUpdate() {
+ DateTime ret = null;
+ for (final MetadataResolver resolver : internalResolvers) {
+ if (resolver instanceof RefreshableMetadataResolver) {
+ final DateTime lastUpdate = ((RefreshableMetadataResolver) resolver).getLastUpdate();
+ if (ret == null || ret.isBefore(lastUpdate)) {
+ ret = lastUpdate;
+ }
}
-
- return ret;
+ }
+
+ return ret;
}
@Override
- @Nullable final public DateTime getLastRefresh() {
- DateTime ret = null;
- for (final MetadataResolver resolver : internalResolvers) {
- if (resolver instanceof RefreshableMetadataResolver) {
- final DateTime lastRefresh = ((RefreshableMetadataResolver) resolver).getLastRefresh();
- if (ret == null || ret.isBefore(lastRefresh)) {
- ret = lastRefresh;
- }
- }
+ @Nullable
+ public final DateTime getLastRefresh() {
+ DateTime ret = null;
+ for (final MetadataResolver resolver : internalResolvers) {
+ if (resolver instanceof RefreshableMetadataResolver) {
+ final DateTime lastRefresh = ((RefreshableMetadataResolver) resolver).getLastRefresh();
+ if (ret == null || ret.isBefore(lastRefresh)) {
+ ret = lastRefresh;
+ }
}
-
- return ret;
+ }
+
+ return ret;
}
-
-
+
/**
* Get the URL to metadata for a specific entityID.
*
@@ -354,103 +356,92 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec
protected abstract List<String> getAllMetadataUrlsFromConfiguration()
throws EaafConfigurationException;
-
/**
* Get a Id for this metadata provider.
- *
+ *
* @return
*/
@Nonnull
protected abstract String getMetadataProviderId();
-
+
protected final MetadataResolver getMetadataResolver() {
log.warn("{} does NOT support 'getMetadataResolver'", AbstractChainingMetadataProvider.class.getName());
return null;
-
+
}
-
+
private Map<String, MetadataResolver> getAllActuallyLoadedResolvers() {
final Map<String, MetadataResolver> loadedproviders =
new HashMap<>();
// make a Map of all actually loaded HTTPMetadataProvider
for (final MetadataResolver resolver : internalResolvers) {
- if (resolver instanceof IdentifiedComponent) {
- loadedproviders.put(((IdentifiedComponent) resolver).getId(), resolver);
-
- } else {
- final String uuid = UUID.randomUUID().toString();
- loadedproviders.put(uuid, resolver);
- log.debug("MetadatenResolver is not of type: {}. Mark it with id: {}",
- IdentifiedComponent.class.getSimpleName(), uuid);
+ loadedproviders.put(((IdentifiedComponent) resolver).getId(), resolver);
- }
}
return loadedproviders;
}
private void addAndRemoveMetadataProvider() throws EaafConfigurationException {
- log.info("EAAF chaining metadata resolver starting internal managment task .... ");
+ log.info("EAAF chaining metadata resolver starting internal managment task .... ");
+
+ /*
+ * OpenSAML ChainingMetadataProvider can not remove a MetadataProvider
+ * (UnsupportedOperationException) The ChainingMetadataProvider use internal a
+ * unmodifiableList to hold all registrated MetadataProviders.
+ */
+ final Map<String, MetadataResolver> providersinuse = new HashMap<>();
+
+ // get all actually loaded metadata providers
+ final Map<String, MetadataResolver> loadedproviders = getAllActuallyLoadedResolvers();
+
+ /*
+ * TODO: maybe add metadata provider destroy after timeout. But could be a
+ * problem if one Metadataprovider load an EntitiesDescriptor with more the
+ * multiple EntityDescriptors. If one of this EntityDesciptors are expired the
+ * full EntitiesDescriptor is removed.
+ *
+ * Timeout requires a better solution in this case!
+ */
+
+ // load all SAML2 SPs form configuration and
+ // compare actually loaded Providers with configured SAML2 SPs
+ final List<String> allMetadataUrls = getAllMetadataUrlsFromConfiguration();
+
+ final Iterator<String> metadataUrlInterator = allMetadataUrls.iterator();
+ while (metadataUrlInterator.hasNext()) {
+ final String metadataurl = metadataUrlInterator.next();
+ try {
+ if (StringUtils.isNotEmpty(metadataurl)
+ && loadedproviders.containsKey(metadataurl)) {
+ // SAML2 SP is actually loaded, to nothing
+ providersinuse.put(metadataurl, loadedproviders.get(metadataurl));
+ loadedproviders.remove(metadataurl);
+
+ }
+ } catch (final Throwable e) {
+ log.error("Failed to add Metadata (unhandled reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ // remove all actually loaded MetadataProviders with are not in ConfigurationDB
+ // any more
+ final Collection<MetadataResolver> notusedproviders = loadedproviders.values();
+ for (final MetadataResolver resolver : notusedproviders) {
+ log.info("Remove not used MetadataProvider with MetadataURL " + resolver.getId());
+ destroyMetadataResolver(resolver);
+ internalResolvers.remove(resolver);
/*
* OpenSAML ChainingMetadataProvider can not remove a MetadataProvider
* (UnsupportedOperationException) The ChainingMetadataProvider use internal a
* unmodifiableList to hold all registrated MetadataProviders.
*/
- final Map<String, MetadataResolver> providersinuse = new HashMap<>();
+ // chainProvider.removeMetadataProvider(provider);
- // get all actually loaded metadata providers
- final Map<String, MetadataResolver> loadedproviders = getAllActuallyLoadedResolvers();
-
- /*
- * TODO: maybe add metadata provider destroy after timeout. But could be a
- * problem if one Metadataprovider load an EntitiesDescriptor with more the
- * multiple EntityDescriptors. If one of this EntityDesciptors are expired the
- * full EntitiesDescriptor is removed.
- *
- * Timeout requires a better solution in this case!
- */
-
- // load all SAML2 SPs form configuration and
- // compare actually loaded Providers with configured SAML2 SPs
- final List<String> allMetadataUrls = getAllMetadataUrlsFromConfiguration();
-
- final Iterator<String> metadataUrlInterator = allMetadataUrls.iterator();
- while (metadataUrlInterator.hasNext()) {
- final String metadataurl = metadataUrlInterator.next();
- try {
- if (StringUtils.isNotEmpty(metadataurl)
- && loadedproviders.containsKey(metadataurl)) {
- // SAML2 SP is actually loaded, to nothing
- providersinuse.put(metadataurl, loadedproviders.get(metadataurl));
- loadedproviders.remove(metadataurl);
-
- }
- } catch (final Throwable e) {
- log.error("Failed to add Metadata (unhandled reason: " + e.getMessage(), e);
-
- }
- }
-
-
- // remove all actually loaded MetadataProviders with are not in ConfigurationDB
- // any more
- final Collection<MetadataResolver> notusedproviders = loadedproviders.values();
- for (final MetadataResolver resolver : notusedproviders) {
- log.info("Remove not used MetadataProvider with MetadataURL " + resolver.getId());
- destroyMetadataResolver(resolver);
- internalResolvers.remove(resolver);
-
- /*
- * OpenSAML ChainingMetadataProvider can not remove a MetadataProvider
- * (UnsupportedOperationException) The ChainingMetadataProvider use internal a
- * unmodifiableList to hold all registrated MetadataProviders.
- */
- // chainProvider.removeMetadataProvider(provider);
-
-
- }
+ }
}
@@ -474,39 +465,34 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec
}
}
-
-
@Override
public DateTime getLastSuccessfulRefresh() {
return this.lastRefeshTimestamp;
-
- }
+ }
@Override
public Boolean wasLastRefreshSuccess() {
return this.lastRefeshSuccessful;
-
- }
-
-
- /** {@inheritDoc} */
- @Override public boolean isRequireValidMetadata() {
- log.warn("Attempt to access unsupported requireValidMetadata property on ChainingMetadataResolver");
- return false;
}
- /** {@inheritDoc} */
- @Override public void setRequireValidMetadata(final boolean requireValidMetadata) {
- throw new UnsupportedOperationException("Setting requireValidMetadata is not supported on chaining resolver");
+ @Override
+ public boolean isRequireValidMetadata() {
+ log.warn("Attempt to access unsupported requireValidMetadata property on ChainingMetadataResolver");
+ return false;
}
+ @Override
+ public void setRequireValidMetadata(final boolean requireValidMetadata) {
+ throw new UnsupportedOperationException(
+ "Setting requireValidMetadata is not supported on chaining resolver");
+ }
@Override
public String getId() {
return getMetadataProviderId();
-
+
}
-
+
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java
index bd2b79cb..d2b861dc 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java
@@ -1,18 +1,22 @@
package at.gv.egiz.eaaf.modules.pvp2.impl.metadata;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+
import org.joda.time.DateTime;
import org.opensaml.core.criterion.EntityIdCriterion;
import org.opensaml.saml.metadata.resolver.ExtendedRefreshableMetadataResolver;
import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
-import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import lombok.extern.slf4j.Slf4j;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
-public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider {
-
- private ExtendedRefreshableMetadataResolver internalProvider;
+@Slf4j
+public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider, IRefreshableMetadataProvider {
+
+ private final ExtendedRefreshableMetadataResolver internalProvider;
public PvpMetadataResolverAdapter(ExtendedRefreshableMetadataResolver provider) {
this.internalProvider = provider;
@@ -27,7 +31,7 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider {
@Override
public DateTime getLastRefresh() {
return internalProvider.getLastRefresh();
-
+
}
@Override
@@ -38,7 +42,7 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider {
@Override
public boolean isRequireValidMetadata() {
return internalProvider.isRequireValidMetadata();
-
+
}
@Override
@@ -50,12 +54,12 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider {
@Override
public MetadataFilter getMetadataFilter() {
return internalProvider.getMetadataFilter();
-
+
}
@Override
public void setMetadataFilter(MetadataFilter newFilter) {
- internalProvider.setMetadataFilter(newFilter);
+ internalProvider.setMetadataFilter(newFilter);
}
@@ -67,7 +71,7 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider {
@Override
public EntityDescriptor resolveSingle(CriteriaSet criteria) throws ResolverException {
return internalProvider.resolveSingle(criteria);
-
+
}
@Override
@@ -80,7 +84,7 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider {
final CriteriaSet criteria = new CriteriaSet();
criteria.add(new EntityIdCriterion(entityId));
return internalProvider.resolveSingle(criteria);
-
+
}
@Override
@@ -93,4 +97,19 @@ public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider {
return internalProvider.wasLastRefreshSuccess();
}
+ @Override
+ public boolean refreshMetadataProvider(String entityID) {
+ try {
+ log.trace("Refeshing metadata-provider: {} ... ", getId());
+ internalProvider.refresh();
+ return true;
+
+ } catch (final ResolverException e) {
+ log.warn("Refreshing of metadata-provider: {} failed. Reason: {}",
+ getId(), e.getMessage());
+ return false;
+
+ }
+ }
+
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java
index f548bc7b..0b505e56 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java
@@ -8,23 +8,31 @@ import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.net.ssl.SSLHandshakeException;
+import at.gv.egiz.components.spring.api.IDestroyableObject;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.impl.utils.FileUtils;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SignatureValidationException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.OpenSaml3ResourceAdapter;
+
import org.apache.http.client.HttpClient;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.saml.metadata.resolver.ExtendedRefreshableMetadataResolver;
import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
+import org.opensaml.saml.metadata.resolver.impl.AbstractReloadingMetadataResolver;
import org.opensaml.saml.metadata.resolver.impl.HTTPMetadataResolver;
import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ResourceLoader;
-import at.gv.egiz.components.spring.api.IDestroyableObject;
-import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
-import at.gv.egiz.eaaf.core.impl.utils.FileUtils;
-import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
-import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
-import at.gv.egiz.eaaf.modules.pvp2.exception.SignatureValidationException;
-import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.OpenSaml3ResourceAdapter;
+import com.google.common.base.Predicates;
+import com.google.common.base.Throwables;
+import com.google.common.collect.FluentIterable;
import lombok.extern.slf4j.Slf4j;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
import net.shibboleth.utilities.java.support.resource.Resource;
import net.shibboleth.utilities.java.support.xml.ParserPool;
@@ -34,13 +42,18 @@ public class PvpMetadataResolverFactory implements IDestroyableObject {
private static final String URI_PREFIX_HTTP = "http:";
private static final String URI_PREFIX_HTTPS = "https:";
+ private static final String NOT_SUCCESS = "Maybe metadata was expired";
+
private Timer timer = null;
-
- @Autowired private IConfiguration authConfig;
- @Autowired private ResourceLoader resourceLoader;
-
+
+ @Autowired
+ private IConfiguration authConfig;
+ @Autowired
+ private ResourceLoader resourceLoader;
+
/**
- * Create a single SAML2 metadata provider by using the default OpenSAML3 parser-pool.
+ * Create a single SAML2 metadata provider by using the default OpenSAML3
+ * parser-pool.
*
* @param metadataLocation where the metadata should be loaded, but never null.
* If the location starts with http(s):, than a http
@@ -54,17 +67,18 @@ public class PvpMetadataResolverFactory implements IDestroyableObject {
*
* @return SAML2 Metadata Provider, or null if the metadata provider can not
* initialized
+ * @throws Pvp2MetadataException In case of an initialization error
*/
- @Nullable
+ @Nullable
public IPvp2MetadataProvider createMetadataProvider(@Nonnull final String metadataLocation,
@Nullable final MetadataFilter filter, @Nonnull final String idForLogging,
- @Nullable final HttpClient httpClient) {
- return createMetadataProvider(metadataLocation, filter, idForLogging,
- XMLObjectProviderRegistrySupport.getParserPool(),
- httpClient);
-
+ @Nullable final HttpClient httpClient) throws Pvp2MetadataException {
+ return createMetadataProvider(metadataLocation, filter, idForLogging,
+ XMLObjectProviderRegistrySupport.getParserPool(),
+ httpClient);
+
}
-
+
/**
* Create a single SAML2 metadata provider.
*
@@ -80,57 +94,74 @@ public class PvpMetadataResolverFactory implements IDestroyableObject {
*
* @return SAML2 Metadata Provider, or null if the metadata provider can not
* initialized
+ * @throws Pvp2MetadataException In case of an initialization error
*/
- @Nullable
+ @Nullable
public IPvp2MetadataProvider createMetadataProvider(@Nonnull final String metadataLocation,
@Nullable final MetadataFilter filter, @Nonnull final String idForLogging,
- @Nullable final ParserPool pool, @Nullable final HttpClient httpClient) {
-
+ @Nullable final ParserPool pool, @Nullable final HttpClient httpClient) throws Pvp2MetadataException {
+
ExtendedRefreshableMetadataResolver internalProvider = null;
-
- if (metadataLocation.startsWith(URI_PREFIX_HTTP)
- || metadataLocation.startsWith(URI_PREFIX_HTTPS)) {
- if (httpClient != null) {
- internalProvider = createNewHttpMetaDataProvider(metadataLocation, filter, idForLogging, timer, pool,
- httpClient);
+
+ try {
+ if (metadataLocation.startsWith(URI_PREFIX_HTTP)
+ || metadataLocation.startsWith(URI_PREFIX_HTTPS)) {
+ internalProvider = createNewHttpMetaDataProvider(metadataLocation, filter,
+ idForLogging, timer, pool, httpClient);
+
} else {
- log.warn("Can not load http(s) based SAML2 metadata without a HTTP client");
-
+ final String absoluteMetadataLocation =
+ FileUtils.makeAbsoluteUrl(metadataLocation, authConfig.getConfigurationRootDirectory());
+ final org.springframework.core.io.Resource resource =
+ resourceLoader.getResource(absoluteMetadataLocation);
+
+ if (resource.exists()) {
+ internalProvider = createNewFileSystemMetaDataProvider(
+ new OpenSaml3ResourceAdapter(resource),
+ filter, idForLogging, timer,
+ pool);
+
+ } else {
+ log.warn(
+ "SAML2 metadata file: {} not found or not exist", absoluteMetadataLocation);
+ throw new Pvp2MetadataException("internal.pvp.05",
+ new Object[] { absoluteMetadataLocation, "File NOT found or exist." });
+
+ }
}
- } else {
- String absoluteMetadataLocation;
- try {
- absoluteMetadataLocation =
- FileUtils.makeAbsoluteUrl(metadataLocation, authConfig.getConfigurationRootDirectory());
+ } catch (final ComponentInitializationException e) {
+ log.warn("Failed to load Metadata file for {} [ {} ]",
+ idForLogging, e.getMessage());
+ checkResolverInitializationError(e, metadataLocation);
- org.springframework.core.io.Resource resource = resourceLoader.getResource(absoluteMetadataLocation);
- if (resource.exists()) {
- internalProvider = createNewFileSystemMetaDataProvider(
- new OpenSaml3ResourceAdapter(resource),
- filter, idForLogging, timer,
- pool);
- } else {
- log.warn(
- "SAML2 metadata file: " + absoluteMetadataLocation + " not found or not exist");
-
- }
+ } catch (final Exception e) {
+ throw new Pvp2MetadataException("internal.pvp.09", new Object[] { metadataLocation, e.getMessage() });
+ }
- } catch (final IOException e) {
- log.warn("SAML2 metadata URL is invalid: " + metadataLocation, e);
+ if (!internalProvider.wasLastRefreshSuccess()) {
+ log.info("Metadata loading from source: {} failed. {}", metadataLocation, NOT_SUCCESS);
+ throw new Pvp2MetadataException("internal.pvp.09", new Object[] { metadataLocation, NOT_SUCCESS });
- }
}
- if (internalProvider != null) {
- return new PvpMetadataResolverAdapter(internalProvider);
-
- } else {
- log.warn("SAML2 metadata has an unsupported metadata location prefix: " + metadataLocation);
- return null;
-
+ return new PvpMetadataResolverAdapter(internalProvider);
+
+ }
+
+ @Override
+ public void fullyDestroy() {
+ if (timer != null) {
+ log.info("Stopping timer-thread for PVP metadata resolver ... ");
+ timer.cancel();
}
+ }
+
+ @PostConstruct
+ private void initialize() {
+ log.info("Initializing timer-thread for PVP metadata resolver ... ");
+ timer = new Timer("PVP metadata-resolver refresh");
}
@@ -142,55 +173,26 @@ public class PvpMetadataResolverFactory implements IDestroyableObject {
* @param idForLogging Id, which is used for Logging
* @param timer {@link Timer} which is used to schedule metadata refresh
* operations
- * @param pool
+ * @param pool SAML2 parser pool that should be used
*
* @return SAML2 Metadata Provider
- * @throws IOException
+ * @throws IOException In case of a metadata resource error
+ * @throws ComponentInitializationException In case of a metadata resolver
+ * initialization error
*/
private ExtendedRefreshableMetadataResolver createNewFileSystemMetaDataProvider(final Resource metadataFile,
final MetadataFilter filter, final String idForLogging, final Timer timer,
- final ParserPool pool) throws IOException {
+ final ParserPool pool) throws IOException, ComponentInitializationException {
ResourceBackedMetadataResolver fileSystemResolver = null;
- try {
- //fileSystemResolver = new FilesystemMetadataResolver(timer, metadataFile);
-
- fileSystemResolver = new ResourceBackedMetadataResolver(timer, metadataFile);
-
- if (pool != null) {
- fileSystemResolver.setParserPool(pool);
-
- } else {
- fileSystemResolver.setParserPool(
- XMLObjectProviderRegistrySupport.getParserPool());
-
- }
- fileSystemResolver.setRequireValidMetadata(true);
- fileSystemResolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes
- fileSystemResolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours
-
- fileSystemResolver.setMetadataFilter(filter);
- fileSystemResolver.initialize();
- fileSystemResolver.setId(metadataFile.getURI().toASCIIString());
-
- fileSystemResolver.setRequireValidMetadata(true);
-
- return fileSystemResolver;
-
- } catch (final Exception e) {
- log.warn("Failed to load Metadata file for " + idForLogging + "[ " + "File: "
- + metadataFile.getURI().toASCIIString() + " Msg: " + e.getMessage() + " ]", e);
-
- log.warn("Can not initialize SAML2 metadata provider from filesystem: "
- + metadataFile.getURI().toASCIIString() + " Reason: " + e.getMessage(), e);
+ fileSystemResolver = new ResourceBackedMetadataResolver(timer, metadataFile);
+ injectMetadataResolverConfiguration(fileSystemResolver, filter, pool);
+ fileSystemResolver.setId(metadataFile.getURI().toASCIIString());
+ fileSystemResolver.initialize();
- if (fileSystemResolver != null) {
- fileSystemResolver.destroy();
+ log.trace("Set-up metadata-resolver with ID: {} as: {}",
+ idForLogging, fileSystemResolver.getClass().getSimpleName());
- }
-
- }
-
- return null;
+ return fileSystemResolver;
}
@@ -202,70 +204,75 @@ public class PvpMetadataResolverFactory implements IDestroyableObject {
* @param idForLogging Id, which is used for Logging
* @param timer {@link Timer} which is used to schedule metadata refresh
* operations
- * @param pool
- *
+ * @param pool SAML2 parser pool that should be used
* @return SAML2 Metadata Provider
+ * @throws ComponentInitializationException In case of a metadata resolver
+ * initialization error
+ * @throws ResolverException In case of an internal OpenSAML
+ * resolver error
*/
private ExtendedRefreshableMetadataResolver createNewHttpMetaDataProvider(final String metadataUrl,
final MetadataFilter filter, final String idForLogging, final Timer timer,
- final ParserPool pool, final HttpClient httpClient) {
+ final ParserPool pool, final HttpClient httpClient) throws ComponentInitializationException,
+ ResolverException {
HTTPMetadataResolver httpMetadataResolver = null;
- try {
- httpMetadataResolver = new HTTPMetadataResolver(timer, httpClient, metadataUrl);
- httpMetadataResolver.setParserPool(pool);
- httpMetadataResolver.setRequireValidMetadata(true);
- httpMetadataResolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes
- httpMetadataResolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours
- // httpProvider.setRefreshDelayFactor(0.1F);
+ httpMetadataResolver = new HTTPMetadataResolver(timer, httpClient, metadataUrl);
+ injectMetadataResolverConfiguration(httpMetadataResolver, filter, pool);
+ httpMetadataResolver.setId(metadataUrl);
+ httpMetadataResolver.initialize();
- httpMetadataResolver.setMetadataFilter(filter);
- httpMetadataResolver.setId(metadataUrl);
- httpMetadataResolver.initialize();
+ log.trace("Set-up metadata-resolver with ID: {} as: {}",
+ idForLogging, httpMetadataResolver.getClass().getSimpleName());
- httpMetadataResolver.setRequireValidMetadata(true);
+ return httpMetadataResolver;
- return httpMetadataResolver;
+ }
- } catch (final Throwable e) {
- if (e.getCause() != null && e.getCause().getCause() instanceof SSLHandshakeException) {
- log.warn("SSL-Server certificate for metadata " + metadataUrl + " not trusted.", e);
+ private void injectMetadataResolverConfiguration(AbstractReloadingMetadataResolver resolver,
+ final MetadataFilter filter, final ParserPool pool) {
+ if (pool != null) {
+ resolver.setParserPool(pool);
- }
- if (e.getCause() != null && e.getCause().getCause() instanceof SignatureValidationException) {
- log.warn("Signature verification for metadata" + metadataUrl + " FAILED.", e);
+ } else {
+ resolver.setParserPool(
+ XMLObjectProviderRegistrySupport.getParserPool());
- }
- if (e.getCause() != null && e.getCause().getCause() instanceof SchemaValidationException) {
- log.warn("Schema validation for metadata " + metadataUrl + " FAILED.", e);
- }
+ }
+
+ resolver.setRequireValidMetadata(true);
+ resolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes
+ resolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours
+ resolver.setMetadataFilter(filter);
+
+ }
- log.warn("Failed to load Metadata file for " + idForLogging + "[ " + e.getMessage() + " ]",
+ private void checkResolverInitializationError(ComponentInitializationException e, String metadataLocation)
+ throws Pvp2MetadataException {
+ if (FluentIterable.from(Throwables.getCausalChain(e)).filter(
+ Predicates.instanceOf(SSLHandshakeException.class)).first().isPresent()) {
+ log.info("SSL-Server certificate for metadata: {} not trusted.", metadataLocation, null, e);
+ throw new Pvp2MetadataException("internal.pvp.06", new Object[] { metadataLocation, e.getMessage() },
e);
- if (httpMetadataResolver != null) {
- log.debug("Destroy failed Metadata provider");
- httpMetadataResolver.destroy();
+ } else if (FluentIterable.from(Throwables.getCausalChain(e)).filter(
+ Predicates.instanceOf(SignatureValidationException.class)).first().isPresent()) {
+ log.info("Signature verification for metadata: {} FAILED.", metadataLocation, null, e);
+ throw new Pvp2MetadataException("internal.pvp.07", new Object[] { metadataLocation, e.getMessage() },
+ e);
- }
+ } else if (FluentIterable.from(Throwables.getCausalChain(e)).filter(
+ Predicates.instanceOf(SchemaValidationException.class)).first().isPresent()) {
+ log.info("Schema validation for metadata: {} FAILED.", metadataLocation, null, e);
+ throw new Pvp2MetadataException("internal.pvp.08", new Object[] { metadataLocation, e.getMessage() },
+ e);
+
+ } else {
+ log.info("Generic initialization error for metadata: {}", metadataLocation, null, e);
+ throw new Pvp2MetadataException("internal.pvp.09", new Object[] { metadataLocation, e.getMessage() },
+ e);
}
- return null;
}
- @Override
- public void fullyDestroy() {
- if (timer != null) {
- log.info("Stopping timer-thread for PVP metadata resolver ... ");
- timer.cancel();
- }
- }
-
- @PostConstruct
- private void initialize() {
- log.info("Initializing timer-thread for PVP metadata resolver ... ");
- timer = new Timer("PVP metadata-resolver refresh");
-
- }
-
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java
index d23affba..fdd44b9a 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java
@@ -2,18 +2,18 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SamlHttpUtils;
+
import org.opensaml.core.xml.XMLObject;
import org.opensaml.messaging.decoder.MessageDecodingException;
import org.opensaml.saml.saml2.binding.decoding.impl.HTTPPostDecoder;
import com.google.common.base.Strings;
-
-import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
import lombok.extern.slf4j.Slf4j;
import net.shibboleth.utilities.java.support.codec.Base64Support;
@@ -27,14 +27,22 @@ import net.shibboleth.utilities.java.support.codec.Base64Support;
@Slf4j
public class EaafHttpPostDecoder extends HTTPPostDecoder {
+ private static final String SAML_REQ_PARAM_NAME = "SAMLRequest";
+ private static final String SAML_RESP_PARAM_NAME = "SAMLResponse";
+
+ public EaafHttpPostDecoder(HttpServletRequest req) {
+ setHttpServletRequest(req);
+ }
+
@Override
protected InputStream getBase64DecodedMessage(final HttpServletRequest request)
throws MessageDecodingException {
log.debug("Getting Base64 encoded message from request");
- String encodedMessage = getLastParameterFromRequest(request, "SAMLRequest");
+ String encodedMessage = SamlHttpUtils.getLastParameterFromRequest(request, SAML_REQ_PARAM_NAME);
if (Strings.isNullOrEmpty(encodedMessage)) {
- encodedMessage = getLastParameterFromRequest(request, "SAMLResponse");
+ encodedMessage = SamlHttpUtils.getLastParameterFromRequest(request, SAML_RESP_PARAM_NAME);
+
}
if (Strings.isNullOrEmpty(encodedMessage)) {
@@ -43,14 +51,17 @@ public class EaafHttpPostDecoder extends HTTPPostDecoder {
throw new MessageDecodingException("No SAML message present in request");
}
- log.trace("Base64 decoding SAML message:\n{}", encodedMessage);
+ log.trace("Base64 decoding SAML message: {}", encodedMessage);
final byte[] decodedBytes = Base64Support.decode(encodedMessage);
- if (decodedBytes == null) {
- log.info("Unable to Base64 decode SAML message");
- throw new MessageDecodingException("Unable to Base64 decode SAML message");
+
+ try {
+ log.trace("Decoded SAML message: {}", new String(decodedBytes, "UTF-8"));
+
+ } catch (final UnsupportedEncodingException e) {
+ log.warn("Logging of incomming message failed", e);
+
}
- log.trace("Decoded SAML message:\n{}", new String(decodedBytes));
return new ByteArrayInputStream(decodedBytes);
}
@@ -61,31 +72,8 @@ public class EaafHttpPostDecoder extends HTTPPostDecoder {
*/
@Override
protected XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException {
- return Saml2Utils.unmarshallMessage(messageStream);
-
- }
-
- /**
- * Always read the last parameter with this name from request to get a strict
- * deterministic behavior. <br>
- * <br>
- * <b><i>If more than one parameters with the same name exists, this method
- * always select the last parameter value.</i></b>
- *
- * @param request Incoming http request
- * @param paramName Name of the http parameter
- * @return the last parameter value with this name, or <code>null</code> if the
- * parameter not exists
- */
- @Nullable
- private String getLastParameterFromRequest(@Nonnull HttpServletRequest request, @Nonnull String paramName) {
- final String[] values = request.getParameterValues(paramName);
- if (values != null && values.length > 0) {
- return values[values.length - 1];
-
- }
-
- return null;
+ return Saml2Utils.unmarshallMessage(messageStream);
}
+
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java
index 16d73296..c5174f02 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java
@@ -4,6 +4,9 @@ import java.io.InputStream;
import javax.servlet.http.HttpServletRequest;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SamlHttpUtils;
+
import org.opensaml.core.xml.XMLObject;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.decoder.MessageDecodingException;
@@ -13,10 +16,7 @@ import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.binding.decoding.impl.HTTPRedirectDeflateDecoder;
import com.google.common.base.Strings;
-
-import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
import lombok.extern.slf4j.Slf4j;
-import net.shibboleth.utilities.java.support.net.URISupport;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
/**
@@ -29,6 +29,14 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
@Slf4j
public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder {
+ private static final String SAML_REQ_PARAM_NAME = "SAMLRequest";
+ private static final String SAML_RESP_PARAM_NAME = "SAMLResponse";
+
+ public EaafHttpRedirectDeflateDecoder(HttpServletRequest req) {
+ setHttpServletRequest(req);
+
+ }
+
@Override
protected void doDecode() throws MessageDecodingException {
final MessageContext<SAMLObject> messageContext = new MessageContext<>();
@@ -52,16 +60,19 @@ public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder {
// implement parameter extraction as same as in
// SAML2HTTPRedirectDeflateSignatureSecurityHandler.java
- final String queryString = getHttpServletRequest().getQueryString();
- if (!Strings.isNullOrEmpty(URISupport.getRawQueryStringParameter(queryString, "SAMLRequest"))) {
- samlMessageIns = decodeMessage(URISupport.getRawQueryStringParameter(queryString, "SAMLRequest"));
- } else if (!Strings.isNullOrEmpty(URISupport.getRawQueryStringParameter(queryString, "SAMLResponse"))) {
- samlMessageIns = decodeMessage(URISupport.getRawQueryStringParameter(queryString, "SAMLResponse"));
+ final String samlReq = SamlHttpUtils.getLastParameterFromRequest(request, SAML_REQ_PARAM_NAME);
+ final String samlResp = SamlHttpUtils.getLastParameterFromRequest(request, SAML_RESP_PARAM_NAME);
+ if (!Strings.isNullOrEmpty(samlReq)) {
+ samlMessageIns = decodeMessage(samlReq);
+
+ } else if (!Strings.isNullOrEmpty(samlResp)) {
+ samlMessageIns = decodeMessage(samlResp);
+
} else {
throw new MessageDecodingException(
"No SAMLRequest or SAMLResponse query path parameter, invalid SAML 2 HTTP Redirect message");
}
-
+
final SAMLObject samlMessage = (SAMLObject) unmarshallMessage(samlMessageIns);
messageContext.setMessage(samlMessage);
log.debug("Decoded SAML message");
@@ -69,9 +80,9 @@ public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder {
populateBindingContext(messageContext);
setMessageContext(messageContext);
-
+
}
-
+
/**
* EAAF specific unmarshaller perform XML schema validation before unmarshalling
* the SAML message.
@@ -79,8 +90,8 @@ public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder {
*/
@Override
protected XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException {
- return Saml2Utils.unmarshallMessage(messageStream);
-
+ return Saml2Utils.unmarshallMessage(messageStream);
+
}
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafKeyStoreX509CredentialAdapter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafKeyStoreX509CredentialAdapter.java
index 7c433c1c..6d81700a 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafKeyStoreX509CredentialAdapter.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafKeyStoreX509CredentialAdapter.java
@@ -50,21 +50,24 @@ public class EaafKeyStoreX509CredentialAdapter extends KeyStoreX509CredentialAda
/**
* Get an OpenSAML2 keystore.
*
- * @param store Java KeyStore
- * @param alias Key alias
- * @param password key Password
- * @param keyStoreFriendlyName Friendlyname of this keystore for logging purposes
- * @throws CredentialsNotAvailableException In case of an initialization exception
+ * @param store Java KeyStore
+ * @param alias Key alias
+ * @param password key Password
+ * @param keyStoreFriendlyName Friendlyname of this keystore for logging
+ * purposes
+ * @throws CredentialsNotAvailableException In case of an initialization
+ * exception
*/
public EaafKeyStoreX509CredentialAdapter(@Nonnull final KeyStore store, @Nonnull final String alias,
- @Nullable final char[] password, @Nonnull String keyStoreFriendlyName) throws CredentialsNotAvailableException {
+ @Nullable final char[] password, @Nonnull String keyStoreFriendlyName)
+ throws CredentialsNotAvailableException {
super(store, alias, password);
if (getPrivateKey() == null && getSecretKey() == null) {
log.error("KeyStore: {} Key with alias: {} not found or contains no PrivateKey.",
keyStoreFriendlyName, alias);
throw new CredentialsNotAvailableException("internal.pvp.00",
- new Object[] { keyStoreFriendlyName, alias});
+ new Object[] { keyStoreFriendlyName, alias });
}
@@ -74,7 +77,8 @@ public class EaafKeyStoreX509CredentialAdapter extends KeyStoreX509CredentialAda
PvpConstants.DEFAULT_SIGNING_METHODE_EC));
} catch (final SamlSigningException e) {
- throw new CredentialsNotAvailableException("internal.pvp.01", new Object[] {keyStoreFriendlyName, alias}, e);
+ throw new CredentialsNotAvailableException("internal.pvp.01", new Object[] { keyStoreFriendlyName,
+ alias }, e);
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HttpPostEncoderWithOwnTemplate.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HttpPostEncoderWithOwnTemplate.java
index 3650e617..fa77b73c 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HttpPostEncoderWithOwnTemplate.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HttpPostEncoderWithOwnTemplate.java
@@ -19,7 +19,6 @@
package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java
index 2e45aea2..f474267f 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java
@@ -9,22 +9,23 @@ import java.net.URL;
import net.shibboleth.utilities.java.support.resource.Resource;
/**
- * Adapter that connects a Spring {@link org.springframework.core.io.Resource} to a {@link Resource}.
- *
+ * Adapter that connects a Spring {@link org.springframework.core.io.Resource}
+ * to a {@link Resource}.
+ *
* @author tlenz
*
*/
public class OpenSaml3ResourceAdapter implements Resource {
- private org.springframework.core.io.Resource internalResource;
+ private final org.springframework.core.io.Resource internalResource;
public OpenSaml3ResourceAdapter(org.springframework.core.io.Resource resource) {
this.internalResource = resource;
}
-
+
@Override
public boolean exists() {
- return internalResource.exists();
+ return internalResource.exists();
}
@Override
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java
index bd450518..38735fb8 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java
@@ -23,8 +23,8 @@ import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.encoder.MessageEncodingException;
import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.saml2.binding.encoding.impl.HTTPRedirectDeflateEncoder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import lombok.extern.slf4j.Slf4j;
/**
* Create deflate encoded SAML2 redirect-binding informations.
@@ -32,9 +32,9 @@ import org.slf4j.LoggerFactory;
* @author tlenz
*
*/
-public class StringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder {
- private static final Logger log = LoggerFactory.getLogger(StringRedirectDeflateEncoder.class);
+@Slf4j
+public class StringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder {
private String redirectUrl = null;
@Override
@@ -50,6 +50,8 @@ public class StringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder {
redirectUrl = buildRedirectURL(messageContext, endpointUrl, encodedMessage);
+ log.trace("SAML2 redirect-binding URL was generated as: {}", redirectUrl);
+
}
/**
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java
index 42d4d736..5c6d861d 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EaafOpenSaml3xInitializer.java
@@ -60,10 +60,12 @@ public class EaafOpenSaml3xInitializer extends InitializationService {
/**
* EAAF specific OpenSAML3.x initialization.
*
- * @throws InitializationException In case of an error
- * @throws ComponentInitializationException
+ * @throws InitializationException In case of an error
+ * @throws ComponentInitializationException In case of an OpenSAML3
+ * initialization error
*/
- public static synchronized void eaafInitialize() throws InitializationException, ComponentInitializationException {
+ public static synchronized void eaafInitialize() throws InitializationException,
+ ComponentInitializationException {
log.debug("Initializing OpenSAML 3.x ... ");
initialize();
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QaaLevelVerifier.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QaaLevelVerifier.java
index 31ffd5a7..ca6f29e4 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QaaLevelVerifier.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QaaLevelVerifier.java
@@ -21,13 +21,13 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.utils;
import java.util.List;
+import at.gv.egiz.eaaf.core.api.data.EaafConstants;
+import at.gv.egiz.eaaf.modules.pvp2.exception.QaaNotAllowedException;
+
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import at.gv.egiz.eaaf.core.api.data.EaafConstants;
-import at.gv.egiz.eaaf.modules.pvp2.exception.QaaNotAllowedException;
-
/**
* EAAF LoA Level verifier checks if requested LoA matchs to LoA of
* authentication.
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java
index 763c07f6..dc7e9338 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java
@@ -37,6 +37,14 @@ import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;
+import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
+import at.gv.egiz.eaaf.core.impl.utils.Random;
+import at.gv.egiz.eaaf.modules.pvp2.PvpConstants;
+import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
+import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
+
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.opensaml.core.xml.XMLObject;
@@ -82,13 +90,6 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
-import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
-import at.gv.egiz.eaaf.core.impl.utils.Random;
-import at.gv.egiz.eaaf.modules.pvp2.PvpConstants;
-import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
-import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute;
-import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException;
-import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
import net.shibboleth.utilities.java.support.xml.QNameSupport;
import net.shibboleth.utilities.java.support.xml.SerializeSupport;
@@ -114,13 +115,14 @@ public class Saml2Utils {
}
/**
- * Sign a OpenSAML 3.x object with a {@link X509Credential}.
- * <br>
- * <p>This method used {@link PvpConstants.DEFAULT_SIGNING_METHODE_RSA}
- * or {@link PvpConstants.DEFAULT_SIGNING_METHODE_EC} as algorithm</p>
+ * Sign a OpenSAML 3.x object with a {@link X509Credential}. <br>
+ * <p>
+ * This method used {@link PvpConstants.DEFAULT_SIGNING_METHODE_RSA} or
+ * {@link PvpConstants.DEFAULT_SIGNING_METHODE_EC} as algorithm
+ * </p>
*
- * @param <T> {@link SignableXMLObject}
- * @param toSign object that should be signed
+ * @param <T> {@link SignableXMLObject}
+ * @param toSign object that should be signed
* @param signingCredential Credentials that should be used for signing
* @param injectCertificate true, if certificate should be part of the signature
* @return Signed object
@@ -157,18 +159,20 @@ public class Saml2Utils {
} catch (final SignatureException | MarshallingException | SecurityException e) {
throw new SamlSigningException("internal.pvp.96",
- new Object[] {signingCredential.getEntityId(), e.getMessage()}, e);
+ new Object[] { signingCredential.getEntityId(), e.getMessage() }, e);
}
}
/**
- * SAML2 message unmarshaller that performs schema validation before unmarshall the message.
- *
+ * SAML2 message unmarshaller that performs schema validation before unmarshall
+ * the message.
+ *
* @param messageStream SAML2 message that shoulld be unmarshalled
* @return OpenSAML XML object
- * @throws MessageDecodingException In case of a schema-validation or unmarshalling error
+ * @throws MessageDecodingException In case of a schema-validation or
+ * unmarshalling error
*/
public static XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException {
try {
@@ -201,22 +205,24 @@ public class Saml2Utils {
} catch (ParserConfigurationException | SAXException e) {
log.warn("Message schema-validation failed.");
- throw new MessageDecodingException("Message schema-validation failed.",
+ throw new MessageDecodingException("Message schema-validation failed.",
new SchemaValidationException("internal.pvp.03", new Object[] { e.getMessage() }, e));
} catch (final IOException e) {
log.error("Error read message from input stream", e);
throw new MessageDecodingException("Error read message from input stream", e);
-
+
}
}
-
+
/**
* Select signature algorithm for a given credential.
*
- * @param credentials {@link X509Credential} that will be used for signing
- * @param rsaSigAlgorithm RSA based signing algorithm that should be used in case of RSA credential
- * @param ecSigAlgorithm EC based signing algorithm that should be used in case of RSA credential
+ * @param credentials {@link X509Credential} that will be used for signing
+ * @param rsaSigAlgorithm RSA based signing algorithm that should be used in
+ * case of RSA credential
+ * @param ecSigAlgorithm EC based signing algorithm that should be used in case
+ * of RSA credential
* @return either the rsaSigAlgorithm or the ecSigAlgorithm
* @throws SamlSigningException In case of an unsupported credential
*/
@@ -233,7 +239,7 @@ public class Saml2Utils {
log.warn("Could NOT evaluate the Private-Key type from " + credentials.getEntityId()
+ " credential.");
throw new SamlSigningException("internal.pvp.97",
- new Object[] {credentials.getEntityId(), privatekey.getClass().getName()});
+ new Object[] { credentials.getEntityId(), privatekey.getClass().getName() });
}
}
@@ -263,14 +269,16 @@ public class Saml2Utils {
}
/**
- * Get a {@link KeyInfoGenerator} that injects key information into XML signature.
+ * Get a {@link KeyInfoGenerator} that injects key information into XML
+ * signature.
*
- * @param credential @link X509Credential} that will be used for signing
- * @param injectCertificate Set <code>true</code> if the certificate should be added to KeyInfo
+ * @param credential @link X509Credential} that will be used for signing
+ * @param injectCertificate Set <code>true</code> if the certificate should be
+ * added to KeyInfo
* @return Generator for a XML signature key-information
*/
public static KeyInfoGenerator getKeyInfoGenerator(X509Credential credential, boolean injectCertificate) {
- //OpenSAML3 only support RSA and DSA for direct key injection
+ // OpenSAML3 only support RSA and DSA for direct key injection
KeyInfoGeneratorFactory keyInfoGenFac = null;
if (injectCertificate || credential.getPublicKey() instanceof ECPublicKey) {
final SignatureSigningConfiguration secConfiguration = SecurityConfigurationSupport
@@ -280,7 +288,7 @@ public class Saml2Utils {
keyInfoGenFac = keyInfoGenManager.getFactory(credential);
} else {
- keyInfoGenFac = createKeyInfoWithoutCertificate(credential);
+ keyInfoGenFac = createKeyInfoWithoutCertificate();
}
@@ -288,7 +296,6 @@ public class Saml2Utils {
}
-
/**
* Create a SAML2 object.
*
@@ -462,19 +469,20 @@ public class Saml2Utils {
.buildObject(Signature.DEFAULT_ELEMENT_NAME);
signature.setSigningCredential(signingCredential);
signature.setSignatureAlgorithm(usedSigAlg);
- final KeyInfo keyInfo = getKeyInfoGenerator(signingCredential, injectCertificate).generate(signingCredential);
+ final KeyInfo keyInfo = getKeyInfoGenerator(signingCredential, injectCertificate).generate(
+ signingCredential);
signature.setKeyInfo(keyInfo);
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
return signature;
}
- private static KeyInfoGeneratorFactory createKeyInfoWithoutCertificate(X509Credential credential) {
+ private static KeyInfoGeneratorFactory createKeyInfoWithoutCertificate() {
final KeyInfoGeneratorFactory keyInfoGenFac = new BasicKeyInfoGeneratorFactory();
- ((BasicKeyInfoGeneratorFactory)keyInfoGenFac).setEmitPublicKeyValue(true);
- ((BasicKeyInfoGeneratorFactory)keyInfoGenFac).setEmitEntityIDAsKeyName(true);
- ((BasicKeyInfoGeneratorFactory)keyInfoGenFac).setEmitKeyNames(true);
- ((BasicKeyInfoGeneratorFactory)keyInfoGenFac).setEmitPublicDEREncodedKeyValue(true);
+ ((BasicKeyInfoGeneratorFactory) keyInfoGenFac).setEmitPublicKeyValue(true);
+ ((BasicKeyInfoGeneratorFactory) keyInfoGenFac).setEmitEntityIDAsKeyName(true);
+ ((BasicKeyInfoGeneratorFactory) keyInfoGenFac).setEmitKeyNames(true);
+ ((BasicKeyInfoGeneratorFactory) keyInfoGenFac).setEmitPublicDEREncodedKeyValue(true);
return keyInfoGenFac;
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SamlHttpUtils.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SamlHttpUtils.java
new file mode 100644
index 00000000..2e02bf22
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SamlHttpUtils.java
@@ -0,0 +1,33 @@
+package at.gv.egiz.eaaf.modules.pvp2.impl.utils;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+public class SamlHttpUtils {
+
+ /**
+ * Always read the last parameter with this name from request to get a strict
+ * deterministic behavior. <br>
+ * <br>
+ * <b><i>If more than one parameters with the same name exists, this method
+ * always select the last parameter value.</i></b>
+ *
+ * @param request Incoming http request
+ * @param paramName Name of the http parameter
+ * @return the last parameter value with this name, or <code>null</code> if the
+ * parameter not exists
+ */
+ @Nullable
+ public static String getLastParameterFromRequest(@Nonnull HttpServletRequest request,
+ @Nonnull String paramName) {
+ final String[] values = request.getParameterValues(paramName);
+ if (values != null && values.length > 0) {
+ return values[values.length - 1];
+
+ }
+
+ return null;
+
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java
index 1591198c..f0758706 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java
@@ -23,9 +23,11 @@ import java.util.ArrayList;
import java.util.List;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException;
import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver;
import org.opensaml.saml.security.impl.MetadataCredentialResolver;
+import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver;
import org.opensaml.xmlsec.keyinfo.impl.BasicProviderKeyInfoCredentialResolver;
import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider;
import org.opensaml.xmlsec.keyinfo.impl.provider.DSAKeyValueProvider;
@@ -34,29 +36,50 @@ import org.opensaml.xmlsec.keyinfo.impl.provider.RSAKeyValueProvider;
import org.opensaml.xmlsec.signature.support.SignatureTrustEngine;
import org.opensaml.xmlsec.signature.support.impl.ExplicitKeySignatureTrustEngine;
+import lombok.extern.slf4j.Slf4j;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+@Slf4j
public class TrustEngineFactory {
/**
* Get OpenSAML2 TrustEngine.
*
* @param mdResolver Metadata provider
- * @return
+ * @return TrustEngine for SAML2 message validation
+ * @throws Pvp2InternalErrorException In case of a TrustEngine initialization
+ * error
*/
public static SignatureTrustEngine getSignatureKnownKeysTrustEngine(
- final IPvp2MetadataProvider mdResolver) {
- final MetadataCredentialResolver resolver = new MetadataCredentialResolver();
- resolver.setRoleDescriptorResolver(new PredicateRoleDescriptorResolver(mdResolver));
+ final IPvp2MetadataProvider mdResolver) throws Pvp2InternalErrorException {
+ try {
+ final List<KeyInfoProvider> keyInfoProvider = new ArrayList<>();
+ keyInfoProvider.add(new DSAKeyValueProvider());
+ keyInfoProvider.add(new RSAKeyValueProvider());
+ keyInfoProvider.add(new InlineX509DataProvider());
+ final KeyInfoCredentialResolver keyInfoCredentialResolver = new BasicProviderKeyInfoCredentialResolver(
+ keyInfoProvider);
+
+ final PredicateRoleDescriptorResolver roleDescriptorResolver = new PredicateRoleDescriptorResolver(
+ mdResolver);
+ roleDescriptorResolver.setRequireValidMetadata(true);
+ roleDescriptorResolver.initialize();
+
+ final MetadataCredentialResolver resolver = new MetadataCredentialResolver();
+ resolver.setRoleDescriptorResolver(roleDescriptorResolver);
+ resolver.setKeyInfoCredentialResolver(keyInfoCredentialResolver);
+ resolver.initialize();
+
+ final ExplicitKeySignatureTrustEngine engine =
+ new ExplicitKeySignatureTrustEngine(resolver, keyInfoCredentialResolver);
- final List<KeyInfoProvider> keyInfoProvider = new ArrayList<>();
- keyInfoProvider.add(new DSAKeyValueProvider());
- keyInfoProvider.add(new RSAKeyValueProvider());
- keyInfoProvider.add(new InlineX509DataProvider());
+ return engine;
- final ExplicitKeySignatureTrustEngine engine =
- new ExplicitKeySignatureTrustEngine(resolver,
- new BasicProviderKeyInfoCredentialResolver(keyInfoProvider));
+ } catch (final ComponentInitializationException e) {
+ log.warn("Initialization of SignatureTrustEngine FAILED.", e);
+ throw new Pvp2InternalErrorException(e);
- return engine;
+ }
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java
index 73a11c49..1994eba0 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java
@@ -32,7 +32,6 @@ import org.opensaml.saml.metadata.resolver.filter.FilterException;
import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.xml.sax.SAXException;
public class SchemaValidationFilter implements MetadataFilter {
private static final Logger log = LoggerFactory.getLogger(SchemaValidationFilter.class);
@@ -58,8 +57,6 @@ public class SchemaValidationFilter implements MetadataFilter {
@Override
public XMLObject filter(final XMLObject arg0) throws FilterException {
- String errString = null;
-
if (isActive) {
try {
final Schema test = schemaBuilder.getSAMLSchema();
@@ -68,15 +65,6 @@ public class SchemaValidationFilter implements MetadataFilter {
val.validate(source);
log.info("Metadata Schema validation check done OK");
- } catch (final SAXException e) {
- if (log.isDebugEnabled() || log.isTraceEnabled()) {
- log.warn("Metadata Schema validation FAILED with exception:", e);
- } else {
- log.warn("Metadata Schema validation FAILED with message: " + e.getMessage());
- }
-
- errString = e.getMessage();
-
} catch (final Exception e) {
if (log.isDebugEnabled() || log.isTraceEnabled()) {
log.warn("Metadata Schema validation FAILED with exception:", e);
@@ -84,13 +72,10 @@ public class SchemaValidationFilter implements MetadataFilter {
log.warn("Metadata Schema validation FAILED with message: " + e.getMessage());
}
- errString = e.getMessage();
-
+ throw new FilterException(new SchemaValidationException("internal.pvp.03",
+ new Object[] { e.getMessage() }, e));
}
- throw new FilterException(new SchemaValidationException("pvp2.26",
- new Object[] { "Metadata Schema validation FAILED with message: " + errString }));
-
} else {
log.info("Metadata Schema validation check is DEACTIVATED!");
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java
new file mode 100644
index 00000000..ef09e5c4
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2018 A-SIT Plus GmbH
+ * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "License");
+ * You may not use this work except in compliance with the License.
+ * You may obtain a copy of the License at:
+ * https://joinup.ec.europa.eu/news/understanding-eupl-v12
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+*/
+
+package at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SamlMetadataSignatureException;
+
+import org.opensaml.saml.common.SignableSAMLObject;
+import org.opensaml.saml.saml2.metadata.EntitiesDescriptor;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator;
+import org.opensaml.security.x509.BasicX509Credential;
+import org.opensaml.xmlsec.signature.support.SignatureException;
+import org.opensaml.xmlsec.signature.support.SignatureValidator;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class SimpleMetadataSignatureVerificationFilter extends AbstractMetadataSignatureFilter {
+
+ private final String metadataUrl;
+ private final List<BasicX509Credential> trustedCredential = new ArrayList<>();
+
+ private static final String ERROR_07 = "internal.pvp.07";
+ private static final String ERROR_12 = "internal.pvp.12";
+ private static final String ERROR_MSG_ENTITIESDESC = "EntitiesDescritors are NOT supported";
+ private static final String ERROR_MSG_SIGNOTVALID = "Signature not valid or no trusted certificate found";
+
+ /**
+ * SAML2 metadata-signature verification-filter that uses a simple {@link List}
+ * of trusted {@link BasicX509Credential} as truststore. <br>
+ * <p>
+ * This filter only validates {@link EntityDescriptor} elements.<br>
+ * SAML2 metadata with {@link EntitiesDescriptor} <b>are not supported.</b>
+ * </p>
+ *
+ * @param credentials Trust X509 certificates
+ * @param metadataUrl Metadata URL for logging purposes
+ */
+ public SimpleMetadataSignatureVerificationFilter(@Nonnull List<BasicX509Credential> credentials,
+ @Nonnull String metadataUrl) {
+ this.metadataUrl = metadataUrl;
+ this.trustedCredential.addAll(credentials);
+
+ }
+
+ @Override
+ protected void verify(EntityDescriptor desc) throws Pvp2MetadataException {
+ try {
+ internalVerify(desc);
+
+ } catch (final EaafException e) {
+ log.info("Metadata verification FAILED for: {} Reason: {}", metadataUrl, e.getMessage());
+ throw new Pvp2MetadataException(ERROR_07,
+ new Object[] { metadataUrl, e.getMessage() }, e);
+
+ }
+ }
+
+ @Override
+ protected void verify(EntitiesDescriptor desc) throws Pvp2MetadataException {
+ throw new Pvp2MetadataException(ERROR_07,
+ new Object[] { metadataUrl, ERROR_MSG_ENTITIESDESC });
+
+ }
+
+ @Override
+ protected void verify(EntityDescriptor entity, EntitiesDescriptor desc) throws Pvp2MetadataException {
+ throw new Pvp2MetadataException(ERROR_07,
+ new Object[] { metadataUrl, ERROR_MSG_ENTITIESDESC });
+
+ }
+
+ private void internalVerify(SignableSAMLObject signedElement)
+ throws EaafException {
+ // check if signature exists
+ if (signedElement.getSignature() == null) {
+ throw new Pvp2MetadataException(ERROR_12,
+ new Object[] { metadataUrl });
+
+ }
+
+ // perform general signature validation
+ try {
+ final SAMLSignatureProfileValidator sigValidator = new SAMLSignatureProfileValidator();
+ sigValidator.validate(signedElement.getSignature());
+
+ } catch (final SignatureException e) {
+ log.error("Failed to validate Signature", e);
+ throw new Pvp2MetadataException(ERROR_07,
+ new Object[] { metadataUrl, e.getMessage() }, e);
+
+ }
+
+ // perform cryptographic signature verification
+ boolean isTrusted = false;
+ for (final BasicX509Credential cred : trustedCredential) {
+ log.trace("Validating signature with credential: {} ... ",
+ cred.getEntityCertificate().getSubjectDN());
+ try {
+ SignatureValidator.validate(signedElement.getSignature(), cred);
+ isTrusted = true;
+
+ } catch (final SignatureException e) {
+ log.debug("Failed to verfiy Signature with cert: {} Reason: {}",
+ cred.getEntityCertificate().getSubjectDN(), e.getMessage());
+
+ }
+ }
+
+ if (!isTrusted) {
+ log.info("PVP2 metadata: " + metadataUrl + " are NOT trusted!");
+ throw new SamlMetadataSignatureException(metadataUrl, ERROR_MSG_SIGNOTVALID);
+
+ }
+
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java
index 2672bef2..aba0a68b 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafMessageContextInitializationHandler.java
@@ -1,23 +1,64 @@
package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+import javax.annotation.Nonnull;
+
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory;
+
+import org.opensaml.core.config.ConfigurationService;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.handler.AbstractMessageHandler;
import org.opensaml.messaging.handler.MessageHandlerException;
import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.common.messaging.context.SAMLMessageInfoContext;
import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
+import org.opensaml.xmlsec.SignatureValidationConfiguration;
+import org.opensaml.xmlsec.SignatureValidationParameters;
+import org.opensaml.xmlsec.context.SecurityParametersContext;
+import org.opensaml.xmlsec.signature.support.SignatureTrustEngine;
import lombok.extern.slf4j.Slf4j;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@Slf4j
public class EaafMessageContextInitializationHandler extends AbstractMessageHandler<SAMLObject> {
+ private final IPvp2MetadataProvider internalMetadataProvider;
+ private SignatureTrustEngine trustEngine;
+
+ public EaafMessageContextInitializationHandler(@Nonnull IPvp2MetadataProvider metadataProvider) {
+ internalMetadataProvider = metadataProvider;
+ }
+
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ try {
+ trustEngine = TrustEngineFactory.getSignatureKnownKeysTrustEngine(internalMetadataProvider);
+
+ } catch (final Pvp2InternalErrorException e) {
+ throw new ComponentInitializationException("TrustEngine injection FAILED", e);
+
+ }
+ }
+
+
@Override
protected void doInvoke(MessageContext<SAMLObject> messageContext) throws MessageHandlerException {
log.trace("Injecting sub-context to SAML2 message ... ");
messageContext.addSubcontext(new SAMLPeerEntityContext());
messageContext.addSubcontext(new SAMLMessageInfoContext());
+
+ final SecurityParametersContext securityParameterContext = new SecurityParametersContext();
+ final SignatureValidationParameters sigValParameters = new SignatureValidationParameters();
+ securityParameterContext.setSignatureValidationParameters(sigValParameters);
+ messageContext.addSubcontext(securityParameterContext);
+
+ sigValParameters.setBlacklistedAlgorithms(
+ ConfigurationService.get(SignatureValidationConfiguration.class)
+ .getBlacklistedAlgorithms());
+ sigValParameters.setSignatureTrustEngine(trustEngine);
}
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSaml2HttpRedirectDeflateSignatureSecurityHandler.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSaml2HttpRedirectDeflateSignatureSecurityHandler.java
new file mode 100644
index 00000000..204229ee
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSaml2HttpRedirectDeflateSignatureSecurityHandler.java
@@ -0,0 +1,107 @@
+package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SamlHttpUtils;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
+import org.opensaml.saml.saml2.binding.security.impl.SAML2HTTPRedirectDeflateSignatureSecurityHandler;
+
+import com.google.common.base.Strings;
+import lombok.extern.slf4j.Slf4j;
+import net.shibboleth.utilities.java.support.codec.Base64Support;
+
+/**
+ * Always extracts the last http parameter with a specific name from request, if
+ * more than one with the same name exists.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class EaafSaml2HttpRedirectDeflateSignatureSecurityHandler extends
+ SAML2HTTPRedirectDeflateSignatureSecurityHandler {
+
+ public static final String HTTP_REDIRECT_SIGALG = "SigAlg";
+ public static final String HTTP_REDIRECT_SIGNATURE = "Signature";
+
+ private IRefreshableMetadataProvider refreshableMetadataProvider = null;
+
+ /**
+ * Signature verification handler that reloads SAML2 metadata if signature
+ * verification fails.
+ *
+ * @param metadataProvider Metadata provider implementation. Refreshing is only
+ * possible, if that provider implements
+ * {@link IRefreshableMetadataProvider}
+ */
+ public EaafSaml2HttpRedirectDeflateSignatureSecurityHandler(
+ @Nullable IPvp2MetadataProvider metadataProvider) {
+ if (metadataProvider != null) {
+ if (metadataProvider instanceof IRefreshableMetadataProvider) {
+ refreshableMetadataProvider = (IRefreshableMetadataProvider) metadataProvider;
+
+ } else {
+ log.trace("Refreshing is not supported by {} metadata-provider",
+ metadataProvider.getClass().getSimpleName());
+
+ }
+ }
+ }
+
+ @Override
+ protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+ try {
+ super.doInvoke(messageContext);
+
+ } catch (final MessageHandlerException e) {
+ if (refreshableMetadataProvider != null) {
+
+ log.debug("Starting metadata refresh process ... ");
+ if (refreshableMetadataProvider.refreshMetadataProvider(
+ messageContext.getSubcontext(SAMLPeerEntityContext.class).getEntityId())) {
+ log.trace("Refreshing successful. Restarting message evaluation ... ");
+
+ try {
+ super.doInvoke(messageContext);
+ return;
+
+ } catch (final MessageHandlerException e1) {
+ log.debug("Signature validation fails twice with second error: {}", e.getMessage());
+
+ }
+ }
+ }
+
+ log.info("Signature validation of SAML message failed. Reason: {}", e.getMessage());
+ throw new MessageHandlerException(
+ new SamlSigningException("internal.pvp.10", new Object[] { e.getMessage() }, e));
+ }
+ }
+
+ @Override
+ @Nullable
+ protected byte[] getSignature() throws MessageHandlerException {
+ final String signature = SamlHttpUtils.getLastParameterFromRequest(
+ getHttpServletRequest(), HTTP_REDIRECT_SIGNATURE);
+
+ if (Strings.isNullOrEmpty(signature)) {
+ return null;
+
+ }
+ return Base64Support.decode(signature);
+ }
+
+ @Override
+ @Nullable
+ protected String getSignatureAlgorithm() throws MessageHandlerException {
+ return SamlHttpUtils.getLastParameterFromRequest(getHttpServletRequest(), HTTP_REDIRECT_SIGALG);
+
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSamlProtocolMessageXmlSignatureSecurityHandler.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSamlProtocolMessageXmlSignatureSecurityHandler.java
new file mode 100644
index 00000000..9f6bc864
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/EaafSamlProtocolMessageXmlSignatureSecurityHandler.java
@@ -0,0 +1,75 @@
+package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.saml.common.binding.security.impl.SAMLProtocolMessageXMLSignatureSecurityHandler;
+import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class EaafSamlProtocolMessageXmlSignatureSecurityHandler extends
+ SAMLProtocolMessageXMLSignatureSecurityHandler {
+
+ private IRefreshableMetadataProvider refreshableMetadataProvider = null;
+
+ /**
+ * Signature verification handler that reloads SAML2 metadata if signature
+ * verification fails.
+ *
+ * @param metadataProvider Metadata provider implementation. Refreshing is only
+ * possible, if that provider implements
+ * {@link IRefreshableMetadataProvider}
+ */
+ public EaafSamlProtocolMessageXmlSignatureSecurityHandler(
+ @Nullable IPvp2MetadataProvider metadataProvider) {
+ if (metadataProvider != null) {
+ if (metadataProvider instanceof IRefreshableMetadataProvider) {
+ refreshableMetadataProvider = (IRefreshableMetadataProvider) metadataProvider;
+
+ } else {
+ log.trace("Refreshing is not supported by {} metadata-provider",
+ metadataProvider.getClass().getSimpleName());
+
+ }
+ }
+ }
+
+ @Override
+ public void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+ try {
+ super.doInvoke(messageContext);
+
+ } catch (final MessageHandlerException e) {
+ if (refreshableMetadataProvider != null) {
+
+ log.debug("Starting metadata refresh process ... ");
+ if (refreshableMetadataProvider.refreshMetadataProvider(
+ messageContext.getSubcontext(SAMLPeerEntityContext.class).getEntityId())) {
+ log.trace("Refreshing successful. Restarting message evaluation ... ");
+
+ try {
+ super.doInvoke(messageContext);
+ return;
+
+ } catch (final MessageHandlerException e1) {
+ log.debug("Signature validation fails twice with second error: {}", e.getMessage());
+
+ }
+ }
+ }
+
+ log.info("Signature validation of SAML message failed. Reason: {}", e.getMessage());
+ throw new MessageHandlerException(
+ new SamlSigningException("internal.pvp.10", new Object[] { e.getMessage() }, e));
+ }
+
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java
index e43d0423..a1365023 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSamlMessageHandlerChain.java
@@ -24,12 +24,12 @@ public class PvpSamlMessageHandlerChain implements MessageHandlerChain<SAMLObjec
+ PvpSamlMessageHandlerChain.class.getName() + " not initialized");
}
+
for (final MessageHandler<SAMLObject> handler : getHandlers()) {
log.trace("Initializing SAML message handler: {}", handler.getClass().getName());
handler.invoke(messageContext);
}
-
}
@Override
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java
index 658dfe16..2e26de7f 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java
@@ -68,9 +68,10 @@ public class SamlVerificationEngine {
*
* @param msg SAML2 message
* @param sigTrustEngine TrustEngine
- * @throws org.opensaml.xml.security.SecurityException In case of
- * invalid signature
- * @throws Exception In case of a general error
+ * @throws org.opensaml.xml.security.SecurityException In case of invalid
+ * signature
+ * @throws Exception In case of a general
+ * error
*/
public void verify(final InboundMessage msg, final SignatureTrustEngine sigTrustEngine)
throws SecurityException, Exception {