summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_pvp2_core
diff options
context:
space:
mode:
authorThomas Lenz <thomas.lenz@egiz.gv.at>2018-06-26 11:03:48 +0200
committerThomas Lenz <thomas.lenz@egiz.gv.at>2018-06-26 11:03:48 +0200
commitbee5dd259a4438d45ecd1bcc26dfba12875236d6 (patch)
treefe1cf7a35cd15dee5fb3c05de0341aa63bf743e0 /eaaf_modules/eaaf_module_pvp2_core
downloadEAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.tar.gz
EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.tar.bz2
EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.zip
initial commit
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_core')
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/pom.xml94
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PVP2SProfileCoreSpringResourceProvider.java30
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PVPConstants.java107
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PVPEventConstants.java11
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/IPVP2BasicConfiguration.java26
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java25
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java51
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/message/InboundMessageInterface.java18
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataBuilderConfiguration.java218
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataConfigurationFactory.java11
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataProvider.java37
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java18
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/ISAMLValidator.java11
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/AttributQueryException.java24
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/BindingNotSupportedException.java21
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/CredentialsNotAvailableException.java24
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/InvalidDateFormatException.java19
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/InvalidPVPRequestException.java16
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/NameIDFormatNotSupportedException.java22
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/NoMetadataInformationException.java19
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/PVP2Exception.java42
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/PVP2MetadataException.java17
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/QAANotAllowedException.java20
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/QAANotSupportedException.java20
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SchemaValidationException.java32
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SignatureValidationException.java38
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java211
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java215
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java148
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java97
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PVPAttributeBuilder.java186
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PVPMetadataBuilder.java425
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java68
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java99
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PVPSProfileRequest.java45
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PVPSProfileResponse.java37
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java446
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java56
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java212
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HTTPPostEncoderWithOwnTemplate.java97
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/KeyStoreX509CredentialAdapter.java32
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java57
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EAAFDefaultSAML2Bootstrap.java42
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EAAFDefaultSecurityConfigurationBootstrap.java132
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java201
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QAALevelVerifier.java41
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SAML2Utils.java125
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/EAAFURICompare.java36
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java41
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/AbstractMetadataSignatureFilter.java128
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/PVPEntityCategoryFilter.java211
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java81
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java171
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AuthnRequestValidator.java45
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPAuthRequestSignedRole.java29
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPSignedRequestPolicyRule.java60
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java183
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider1
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml30
59 files changed, 4959 insertions, 0 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_core/pom.xml b/eaaf_modules/eaaf_module_pvp2_core/pom.xml
new file mode 100644
index 00000000..57d190eb
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<!--
+ -->
+
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>at.gv.egiz.eaaf</groupId>
+ <artifactId>eaaf_modules</artifactId>
+ <version>1.x</version>
+ </parent>
+ <artifactId>eaaf_module_pvp2_core</artifactId>
+ <version>${egiz.eaaf.version}</version>
+ <name>eaaf_module_pvp2_core</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>at.gv.egiz.eaaf</groupId>
+ <artifactId>eaaf-core</artifactId>
+ <version>${egiz.eaaf.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opensaml</groupId>
+ <artifactId>opensaml</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opensaml</groupId>
+ <artifactId>xmltooling</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opensaml</groupId>
+ <artifactId>openws</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.santuario</groupId>
+ <artifactId>xmlsec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.owasp.esapi</groupId>
+ <artifactId>esapi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Testing -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>eaaf_module_pvp2_core</finalName>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.7.0</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+
+ <!-- enable co-existence of testng and junit -->
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ <configuration>
+ <threadCount>1</threadCount>
+ <argLine>--add-modules java.xml.bind</argLine>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-junit47</artifactId>
+ <version>${surefire.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
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
new file mode 100644
index 00000000..cfb88e87
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PVP2SProfileCoreSpringResourceProvider.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2;
+
+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
+ public String getName() {
+ return "EAAF PVP2 S-Profile Core SpringResourceProvider";
+ }
+
+ @Override
+ public String[] getPackagesToScan() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Resource[] getResourcesToLoad() {
+ ClassPathResource sl20AuthConfig = new ClassPathResource("/eaaf_pvp.beans.xml", PVP2SProfileCoreSpringResourceProvider.class);
+
+ return new Resource[] {sl20AuthConfig};
+ }
+
+}
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
new file mode 100644
index 00000000..f5b7baa8
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PVPConstants.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opensaml.xml.encryption.EncryptionConstants;
+import org.opensaml.xml.signature.SignatureConstants;
+
+import at.gv.egiz.eaaf.core.api.data.PVPAttributeDefinitions;
+import at.gv.egiz.eaaf.core.impl.data.Trible;
+
+public interface PVPConstants extends PVPAttributeDefinitions {
+
+ public static final String DEFAULT_SIGNING_METHODE = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256;
+ public static final String DEFAULT_DIGESTMETHODE = SignatureConstants.ALGO_ID_DIGEST_SHA256;
+ public static final String DEFAULT_SYM_ENCRYPTION_METHODE = EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256;
+ public static final String DEFAULT_ASYM_ENCRYPTION_METHODE = EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP;
+
+ public static final String ENTITY_CATEGORY_ATTRIBITE = "http://macedir.org/entity-category";
+ public static final String EGOVTOKEN = "http://www.ref.gv.at/ns/names/agiz/pvp/egovtoken";
+ public static final String CITIZENTOKEN = "http://www.ref.gv.at/ns/names/agiz/pvp/citizentoken";
+
+ @Deprecated
+ public static final String STORK_ATTRIBUTE_PREFIX = "http://www.stork.gov.eu/";
+
+ public static final String REDIRECT = "Redirect";
+ public static final String POST = "Post";
+ public static final String SOAP = "Soap";
+ public static final String METADATA = "Metadata";
+ public static final String ATTRIBUTEQUERY = "AttributeQuery";
+ public static final String SINGLELOGOUT = "SingleLogOut";
+
+ /**
+ *
+ * Get required PVP attributes for egovtoken
+ * First : PVP attribute name (OID)
+ * Second: FriendlyName
+ * Third: Required
+ *
+ */
+ public static final List<Trible<String, String, Boolean>> EGOVTOKEN_PVP_ATTRIBUTES =
+ Collections.unmodifiableList(new ArrayList<Trible<String, String, Boolean>>() {
+ private static final long serialVersionUID = 1L;
+ {
+ //currently supported attributes
+ add(Trible.newInstance(PVP_VERSION_NAME, PVP_VERSION_FRIENDLY_NAME, true));
+ add(Trible.newInstance(PRINCIPAL_NAME_NAME, PRINCIPAL_NAME_FRIENDLY_NAME, true));
+
+ //currently not supported attributes
+ add(Trible.newInstance(USERID_NAME, USERID_FRIENDLY_NAME, false));
+ add(Trible.newInstance(GID_NAME, GID_FRIENDLY_NAME, false));
+ add(Trible.newInstance(PARTICIPANT_ID_NAME, PARTICIPANT_ID_FRIENDLY_NAME, false));
+ add(Trible.newInstance(OU_GV_OU_ID_NAME, OU_GV_OU_ID_FRIENDLY_NAME, false));
+ add(Trible.newInstance(OU_NAME, OU_FRIENDLY_NAME, false));
+ add(Trible.newInstance(SECCLASS_NAME, SECCLASS_FRIENDLY_NAME, false));
+
+
+ }
+ });
+
+ /**
+ *
+ * Get required PVP attributes for citizenToken
+ * First : PVP attribute name (OID)
+ * Second: FriendlyName
+ * Third: Required
+ *
+ */
+ public static final List<Trible<String, String, Boolean>> CITIZENTOKEN_PVP_ATTRIBUTES =
+ Collections.unmodifiableList(new ArrayList<Trible<String, String, Boolean>>() {
+ private static final long serialVersionUID = 1L;
+ {
+ //required attributes - eIDAS minimal-data set
+ add(Trible.newInstance(PVP_VERSION_NAME, PVP_VERSION_FRIENDLY_NAME, true));
+ add(Trible.newInstance(PRINCIPAL_NAME_NAME, PRINCIPAL_NAME_FRIENDLY_NAME, true));
+ add(Trible.newInstance(GIVEN_NAME_NAME, GIVEN_NAME_FRIENDLY_NAME, true));
+ add(Trible.newInstance(BIRTHDATE_NAME, BIRTHDATE_FRIENDLY_NAME, true));
+ add(Trible.newInstance(BPK_NAME, BPK_FRIENDLY_NAME, true));
+
+
+ //not required attributes
+ add(Trible.newInstance(EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, EID_CITIZEN_EIDAS_QAA_LEVEL_FRIENDLY_NAME, false));
+ add(Trible.newInstance(EID_ISSUING_NATION_NAME, EID_ISSUING_NATION_FRIENDLY_NAME, false));
+ add(Trible.newInstance(EID_SECTOR_FOR_IDENTIFIER_NAME, EID_SECTOR_FOR_IDENTIFIER_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_TYPE_NAME, MANDATE_TYPE_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_TYPE_OID_NAME, MANDATE_TYPE_OID_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_LEG_PER_SOURCE_PIN_NAME, MANDATE_LEG_PER_SOURCE_PIN_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, MANDATE_LEG_PER_SOURCE_PIN_TYPE_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_NAT_PER_BPK_NAME, MANDATE_NAT_PER_BPK_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_NAT_PER_GIVEN_NAME_NAME, MANDATE_NAT_PER_GIVEN_NAME_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_NAT_PER_FAMILY_NAME_NAME, MANDATE_NAT_PER_FAMILY_NAME_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_NAT_PER_BIRTHDATE_NAME, MANDATE_NAT_PER_BIRTHDATE_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_LEG_PER_FULL_NAME_NAME, MANDATE_LEG_PER_FULL_NAME_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_PROF_REP_OID_NAME, MANDATE_PROF_REP_OID_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_PROF_REP_DESC_NAME, MANDATE_PROF_REP_DESC_FRIENDLY_NAME, false));
+ add(Trible.newInstance(MANDATE_REFERENCE_VALUE_NAME, MANDATE_REFERENCE_VALUE_FRIENDLY_NAME, false));
+
+
+
+ }
+ });
+
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PVPEventConstants.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PVPEventConstants.java
new file mode 100644
index 00000000..9b620a04
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/PVPEventConstants.java
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2;
+
+public class PVPEventConstants {
+
+ //TODO!!!
+ public static final int AUTHPROTOCOL_PVP_METADATA = 3100;
+ public static final int AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST = 3101;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/IPVP2BasicConfiguration.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/IPVP2BasicConfiguration.java
new file mode 100644
index 00000000..28ccd7e0
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/IPVP2BasicConfiguration.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.api;
+
+import java.util.List;
+
+import org.opensaml.saml2.metadata.ContactPerson;
+import org.opensaml.saml2.metadata.Organization;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+public interface IPVP2BasicConfiguration {
+
+ public String getIDPEntityId(String authURL) throws EAAFException;
+
+ public String getIDPSSOPostService(String authURL) throws EAAFException;
+
+ public String getIDPSSORedirectService(String authURL) throws EAAFException;
+
+ public Object getIDPSSOSOAPService(String extractAuthURLFromRequest) throws EAAFException;
+
+ public List<ContactPerson> getIDPContacts() throws EAAFException;
+
+ public Organization getIDPOrganisation() throws EAAFException;
+
+}
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
new file mode 100644
index 00000000..959ad747
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IDecoder.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.api.binding;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.opensaml.common.binding.decoding.URIComparator;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.ws.message.decoder.MessageDecodingException;
+import org.opensaml.xml.security.SecurityException;
+
+import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+
+public interface IDecoder {
+ public InboundMessageInterface decode(HttpServletRequest req,
+ HttpServletResponse resp, MetadataProvider metadataProvider, boolean isSPEndPoint, URIComparator comparator)
+ throws MessageDecodingException, SecurityException, PVP2Exception;
+
+ public boolean handleDecode(String action, HttpServletRequest req);
+
+ public String getSAML2BindingName();
+}
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
new file mode 100644
index 00000000..a4475f20
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/binding/IEncoder.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.api.binding;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.opensaml.saml2.core.RequestAbstractType;
+import org.opensaml.saml2.core.StatusResponseType;
+import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.credential.Credential;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+public interface IEncoder {
+
+ /**
+ *
+ * @param req The http request
+ * @param resp The http response
+ * @param request The SAML2 request object
+ * @param targetLocation URL, where the request should be transmit
+ * @param relayState token for session handling
+ * @param credentials Credential to sign the request object
+ * @param pendingReq Internal MOA-ID request object that contains session-state informations but never null
+ * @throws MessageEncodingException
+ * @throws SecurityException
+ * @throws PVP2Exception
+ */
+ public void encodeRequest(HttpServletRequest req,
+ HttpServletResponse resp, RequestAbstractType request, String targetLocation, String relayState, Credential credentials, IRequest pendingReq)
+ throws MessageEncodingException, SecurityException, PVP2Exception;
+
+ /**
+ * Encoder SAML Response
+ * @param req The http request
+ * @param resp The http response
+ * @param response The SAML2 repsonse object
+ * @param targetLocation URL, where the request should be transmit
+ * @param relayState token for session handling
+ * @param credentials Credential to sign the response object
+ * @param pendingReq Internal MOA-ID request object that contains session-state informations but never null
+ * @throws MessageEncodingException
+ * @throws SecurityException
+ */
+ public void encodeRespone(HttpServletRequest req,
+ HttpServletResponse resp, StatusResponseType response, String targetLocation, String relayState, Credential credentials, IRequest pendingReq)
+ throws MessageEncodingException, SecurityException, PVP2Exception;
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/message/InboundMessageInterface.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/message/InboundMessageInterface.java
new file mode 100644
index 00000000..00edb1bf
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/message/InboundMessageInterface.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.api.message;
+
+import org.w3c.dom.Element;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface InboundMessageInterface {
+
+ public String getRelayState();
+ public String getEntityID();
+ public boolean isVerified();
+ public Element getInboundMessage();
+
+}
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
new file mode 100644
index 00000000..218e5171
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataBuilderConfiguration.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.api.metadata;
+
+import java.util.List;
+
+import org.opensaml.saml2.core.Attribute;
+import org.opensaml.saml2.metadata.ContactPerson;
+import org.opensaml.saml2.metadata.Organization;
+import org.opensaml.saml2.metadata.RequestedAttribute;
+import org.opensaml.xml.security.credential.Credential;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IPVPMetadataBuilderConfiguration {
+
+
+ /**
+ * Defines a unique name for this PVP Service-provider, which is used for logging
+ *
+ * @return
+ */
+ public String getSPNameForLogging();
+
+ /**
+ * Set metadata valid area
+ *
+ * @return valid until in hours [h]
+ */
+ public int getMetadataValidUntil();
+
+ /**
+ * Build a SAML2 Entities element as metadata root element
+ *
+ * @return true, if the metadata should start with entities element
+ */
+ public boolean buildEntitiesDescriptorAsRootElement();
+
+ /**
+ *
+ *
+ * @return true, if an IDP SSO-descriptor element should be generated
+ */
+ public boolean buildIDPSSODescriptor();
+
+ /**
+ *
+ *
+ * @return true, if an SP SSO-descriptor element should be generated
+ */
+ public boolean buildSPSSODescriptor();
+
+ /**
+ * Set the PVP entityID for this SAML2 metadata.
+ * The entityID must be an URL and must be start with the public-URL prefix of the server
+ *
+ * @return PVP entityID postfix as String
+ */
+ public String getEntityID();
+
+ /**
+ * Set a friendlyName for this PVP entity
+ *
+ * @return
+ */
+ public String getEntityFriendlyName();
+
+ /**
+ * Set the contact information for this metadata entity
+ *
+ * @return
+ */
+ public List<ContactPerson> getContactPersonInformation();
+
+ /**
+ * Set organisation information for this metadata entity
+ *
+ * @return
+ */
+ public Organization getOrgansiationInformation();
+
+
+ /**
+ * Set the credential for metadata signing
+ *
+ * @return
+ * @throws CredentialsNotAvailableException
+ */
+ public Credential getMetadataSigningCredentials() throws CredentialsNotAvailableException;
+
+ /**
+ * Set the credential for request/response signing
+ * IDP metadata: this credential is used for SAML2 response signing
+ * SP metadata: this credential is used for SAML2 response signing
+ *
+ * @return
+ * @throws CredentialsNotAvailableException
+ */
+ public Credential getRequestorResponseSigningCredentials() throws CredentialsNotAvailableException;
+
+ /**
+ * Set the credential for response encryption
+ *
+ * @return
+ * @throws CredentialsNotAvailableException
+ */
+ public Credential getEncryptionCredentials() throws CredentialsNotAvailableException;
+
+ /**
+ * Set the IDP Post-Binding URL for WebSSO
+ *
+ * @return
+ */
+ public String getIDPWebSSOPostBindingURL();
+
+ /**
+ * Set the IDP Redirect-Binding URL for WebSSO
+ *
+ * @return
+ */
+ public String getIDPWebSSORedirectBindingURL();
+
+ /**
+ * Set the IDP Post-Binding URL for Single LogOut
+ *
+ * @return
+ */
+ public String getIDPSLOPostBindingURL();
+
+ /**
+ * Set the IDP Redirect-Binding URL for Single LogOut
+ *
+ * @return
+ */
+ public String getIDPSLORedirectBindingURL();
+
+ /**
+ * Set the SP Post-Binding URL for for the Assertion-Consumer Service
+ *
+ * @return
+ */
+ public String getSPAssertionConsumerServicePostBindingURL();
+
+ /**
+ * Set the SP Redirect-Binding URL for the Assertion-Consumer Service
+ *
+ * @return
+ */
+ public String getSPAssertionConsumerServiceRedirectBindingURL();
+
+ /**
+ * Set the SP Post-Binding URL for Single LogOut
+ *
+ * @return
+ */
+ public String getSPSLOPostBindingURL();
+
+ /**
+ * Set the SP Redirect-Binding URL for Single LogOut
+ *
+ * @return
+ */
+ public String getSPSLORedirectBindingURL();
+
+ /**
+ * Set the SP SOAP-Binding URL for Single LogOut
+ *
+ * @return
+ */
+ public String getSPSLOSOAPBindingURL();
+
+
+ /**
+ * Set all SAML2 attributes which could be provided by this IDP
+ *
+ * @return
+ */
+ public List<Attribute> getIDPPossibleAttributes();
+
+ /**
+ * Set all nameID types which could be provided by this IDP
+ *
+ * @return a List of SAML2 nameID types
+ */
+ public List<String> getIDPPossibleNameITTypes();
+
+ /**
+ * Set all SAML2 attributes which are required by the SP
+ *
+ * @return
+ */
+ public List<RequestedAttribute> getSPRequiredAttributes();
+
+ /**
+ * Set all nameID types which allowed from the SP
+ *
+ * @return a List of SAML2 nameID types
+ */
+ public List<String> getSPAllowedNameITTypes();
+
+ /**
+ * Set the 'wantAssertionSigned' attribute in SP metadata
+ *
+ * @return
+ */
+ public boolean wantAssertionSigned();
+
+ /**
+ * Set the 'wantAuthnRequestSigned' attribute
+ *
+ * @return
+ */
+ public boolean wantAuthnRequestSigned();
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataConfigurationFactory.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataConfigurationFactory.java
new file mode 100644
index 00000000..7492c0ff
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataConfigurationFactory.java
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.api.metadata;
+
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider;
+
+public interface IPVPMetadataConfigurationFactory {
+
+ public IPVPMetadataBuilderConfiguration generateMetadataBuilderConfiguration(String authURL, AbstractCredentialProvider pvpIDPCredentials);
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataProvider.java
new file mode 100644
index 00000000..4c721d45
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPVPMetadataProvider.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.api.metadata;
+
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.opensaml.saml2.metadata.EntitiesDescriptor;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.RoleDescriptor;
+import org.opensaml.saml2.metadata.provider.MetadataFilter;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.saml2.metadata.provider.MetadataProviderException;
+import org.opensaml.xml.XMLObject;
+
+public interface IPVPMetadataProvider extends MetadataProvider {
+
+ boolean requireValidMetadata();
+
+ void setRequireValidMetadata(boolean requireValidMetadata);
+
+ MetadataFilter getMetadataFilter();
+
+ void setMetadataFilter(MetadataFilter newFilter) throws MetadataProviderException;
+
+ XMLObject getMetadata() throws MetadataProviderException;
+
+ EntitiesDescriptor getEntitiesDescriptor(String entitiesID) throws MetadataProviderException;
+
+ EntityDescriptor getEntityDescriptor(String entityID) throws MetadataProviderException;
+
+ List<RoleDescriptor> getRole(String entityID, QName roleName) throws MetadataProviderException;
+
+ RoleDescriptor getRole(String entityID, QName roleName, String supportedProtocol) throws MetadataProviderException;
+
+} \ No newline at end of file
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
new file mode 100644
index 00000000..07321e0c
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.api.metadata;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IRefreshableMetadataProvider {
+
+ /**
+ * Refresh a entity or load a entity in a metadata provider
+ *
+ * @param entityID
+ * @return true, if refresh is success, otherwise false
+ */
+ public boolean refreshMetadataProvider(String entityID);
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/ISAMLValidator.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/ISAMLValidator.java
new file mode 100644
index 00000000..a13a0bac
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/validation/ISAMLValidator.java
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.api.validation;
+
+import org.opensaml.saml2.core.RequestAbstractType;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+public interface ISAMLValidator {
+ public void validateRequest(RequestAbstractType request) throws EAAFException;
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/AttributQueryException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/AttributQueryException.java
new file mode 100644
index 00000000..5388d446
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/AttributQueryException.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+/**
+ * @author tlenz
+ *
+ */
+public class AttributQueryException extends PVP2Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4302422507173728748L;
+
+ public AttributQueryException(String messageId, Object[] parameters) {
+ super(messageId, parameters);
+ }
+
+ public AttributQueryException(String messageId, Object[] parameters, Throwable e) {
+ super(messageId, parameters, e);
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/BindingNotSupportedException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/BindingNotSupportedException.java
new file mode 100644
index 00000000..e230d490
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/BindingNotSupportedException.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+public class BindingNotSupportedException extends PVP2Exception {
+
+ public BindingNotSupportedException(String binding) {
+ super("pvp2.11", new Object[] {binding});
+ this.statusCodeValue = StatusCode.UNSUPPORTED_BINDING_URI;
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7227603941387879360L;
+
+
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/CredentialsNotAvailableException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/CredentialsNotAvailableException.java
new file mode 100644
index 00000000..f477b67b
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/CredentialsNotAvailableException.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+public class CredentialsNotAvailableException extends EAAFException {
+
+ public CredentialsNotAvailableException(String messageId,
+ Object[] parameters) {
+ super(messageId, parameters, messageId);
+ }
+
+ public CredentialsNotAvailableException(String messageId,
+ Object[] parameters, Throwable e) {
+ super(messageId, parameters, e.getMessage(), e);
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2564476345552842599L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/InvalidDateFormatException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/InvalidDateFormatException.java
new file mode 100644
index 00000000..1ea49a49
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/InvalidDateFormatException.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+public class InvalidDateFormatException extends PVP2Exception {
+
+ public InvalidDateFormatException() {
+ super("pvp2.02", null);
+ this.statusCodeValue = StatusCode.REQUESTER_URI;
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6867976890237846085L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/InvalidPVPRequestException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/InvalidPVPRequestException.java
new file mode 100644
index 00000000..31050425
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/InvalidPVPRequestException.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+public class InvalidPVPRequestException extends PVP2Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public InvalidPVPRequestException(String messageId, Object[] parameters) {
+ super(messageId, parameters);
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/NameIDFormatNotSupportedException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/NameIDFormatNotSupportedException.java
new file mode 100644
index 00000000..140ef179
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/NameIDFormatNotSupportedException.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException;
+
+public class NameIDFormatNotSupportedException extends AuthnRequestValidatorException {
+
+ public NameIDFormatNotSupportedException(String nameIDFormat) {
+ super("pvp2.12", new Object[] {nameIDFormat}, "NameID format not supported");
+ statusCodeValue = StatusCode.INVALID_NAMEID_POLICY_URI;
+
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2270762519437873336L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/NoMetadataInformationException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/NoMetadataInformationException.java
new file mode 100644
index 00000000..bf528e5c
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/NoMetadataInformationException.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+public class NoMetadataInformationException extends PVP2Exception {
+
+ public NoMetadataInformationException() {
+ super("pvp2.15", null);
+ this.statusCodeValue = StatusCode.UNKNOWN_PRINCIPAL_URI;
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4608068445208032193L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/PVP2Exception.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/PVP2Exception.java
new file mode 100644
index 00000000..889bda2e
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/PVP2Exception.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+public abstract class PVP2Exception extends EAAFException {
+ //TODO:!!!!!
+
+ protected String statusCodeValue = StatusCode.RESPONDER_URI;
+ protected String statusMessageValue = null;
+
+ public PVP2Exception(String messageId, Object[] parameters,
+ Throwable wrapped) {
+ super(messageId, parameters, wrapped.getMessage(), wrapped);
+ this.statusMessageValue = this.getMessage();
+ }
+
+ public PVP2Exception(String messageId, Object[] parameters) {
+ super(messageId, parameters, messageId);
+ this.statusMessageValue = this.getMessage();
+ }
+
+
+ public String getStatusCodeValue() {
+ return (this.statusCodeValue);
+ }
+
+ public String getStatusMessageValue() {
+ return (this.statusMessageValue);
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7669537952484421069L;
+
+
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/PVP2MetadataException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/PVP2MetadataException.java
new file mode 100644
index 00000000..f255a7e4
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/PVP2MetadataException.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+public class PVP2MetadataException extends PVP2Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public PVP2MetadataException(String messageId, Object[] parameters) {
+ super(messageId, parameters);
+ }
+
+ public PVP2MetadataException(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/QAANotAllowedException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/QAANotAllowedException.java
new file mode 100644
index 00000000..8b4e74d5
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/QAANotAllowedException.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+
+public class QAANotAllowedException extends PVP2Exception {
+
+ public QAANotAllowedException(String qaa_auth, String qaa_request) {
+ super("pvp2.17", new Object[] {qaa_auth, qaa_request});
+ this.statusCodeValue = StatusCode.REQUESTER_URI;
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3964192953884089323L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/QAANotSupportedException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/QAANotSupportedException.java
new file mode 100644
index 00000000..9eb44a61
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/QAANotSupportedException.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+
+public class QAANotSupportedException extends PVP2Exception {
+
+ public QAANotSupportedException(String qaa) {
+ super("pvp2.05", new Object[] {qaa});
+ this.statusCodeValue = StatusCode.REQUESTER_URI;
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3964192953884089323L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SchemaValidationException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SchemaValidationException.java
new file mode 100644
index 00000000..de728f84
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SchemaValidationException.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+/**
+ * @author tlenz
+ *
+ */
+public class SchemaValidationException extends PVP2Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param messageId
+ * @param parameters
+ */
+ public SchemaValidationException(String messageId, Object[] parameters) {
+ super(messageId, parameters);
+ }
+
+ /**
+ * @param messageId
+ * @param parameters
+ */
+ public SchemaValidationException(String messageId, Object[] parameters, Throwable e) {
+ super(messageId, parameters, e);
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SignatureValidationException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SignatureValidationException.java
new file mode 100644
index 00000000..77d32f10
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SignatureValidationException.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+import org.opensaml.saml2.metadata.provider.FilterException;
+
+/**
+ * @author tlenz
+ *
+ */
+public class SignatureValidationException extends FilterException {
+
+ /**
+ * @param string
+ */
+ public SignatureValidationException(String string) {
+ super(string);
+
+ }
+
+ /**
+ * @param e
+ */
+ public SignatureValidationException(Exception e) {
+ super(e);
+ }
+
+ /**
+ * @param string
+ * @param object
+ */
+ public SignatureValidationException(String string, Exception e) {
+ super(string, e);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+}
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
new file mode 100644
index 00000000..4bcbed19
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.binding;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.common.binding.decoding.URIComparator;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.binding.decoding.HTTPPostDecoder;
+import org.opensaml.saml2.core.RequestAbstractType;
+import org.opensaml.saml2.core.StatusResponseType;
+import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.SingleSignOnService;
+import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.ws.message.decoder.MessageDecodingException;
+import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.opensaml.ws.security.SecurityPolicyResolver;
+import org.opensaml.ws.security.provider.BasicSecurityPolicy;
+import org.opensaml.ws.security.provider.StaticSecurityPolicyResolver;
+import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
+import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
+import org.opensaml.xml.parse.BasicParserPool;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.credential.Credential;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfiguration;
+import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfigurationFactory;
+import at.gv.egiz.eaaf.core.api.gui.IGUIFormBuilder;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.impl.gui.velocity.VelocityProvider;
+import at.gv.egiz.eaaf.modules.pvp2.PVPConstants;
+import at.gv.egiz.eaaf.modules.pvp2.api.binding.IDecoder;
+import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder;
+import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
+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.HTTPPostEncoderWithOwnTemplate;
+import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EAAFDefaultSAML2Bootstrap;
+import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PVPSignedRequestPolicyRule;
+
+@Service("PVPPOSTBinding")
+public class PostBinding implements IDecoder, IEncoder {
+ private static final Logger log = LoggerFactory.getLogger(PostBinding.class);
+
+ @Autowired(required=true) IConfiguration authConfig;
+ @Autowired(required=true) IGUIFormBuilder guiBuilder;
+ @Autowired(required=true) IGUIBuilderConfigurationFactory guiConfigFactory;
+
+ public void encodeRequest(HttpServletRequest req, HttpServletResponse resp,
+ RequestAbstractType request, String targetLocation, String relayState, Credential credentials, IRequest pendingReq)
+ throws MessageEncodingException, SecurityException {
+
+ try {
+ //load default PVP security configurations
+ EAAFDefaultSAML2Bootstrap.initializeDefaultPVPConfiguration();
+
+ //initialize POST binding encoder with template decoration
+ IGUIBuilderConfiguration guiConfig = guiConfigFactory.getSPSpecificSAML2PostConfiguration(
+ pendingReq,
+ "pvp_postbinding_template.html",
+ authConfig.getConfigurationRootDirectory());
+
+ HTTPPostEncoderWithOwnTemplate encoder = new HTTPPostEncoderWithOwnTemplate(guiConfig, guiBuilder,
+ VelocityProvider.getClassPathVelocityEngine());
+
+ //set OpenSAML2 process parameter into binding context dao
+ HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
+ resp, true);
+ BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ SingleSignOnService service = new SingleSignOnServiceBuilder().buildObject();
+ service.setBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
+ service.setLocation(targetLocation);;
+
+ context.setOutboundSAMLMessageSigningCredential(credentials);
+ context.setPeerEntityEndpoint(service);
+ context.setOutboundSAMLMessage(request);
+ context.setOutboundMessageTransport(responseAdapter);
+ context.setRelayState(relayState);
+
+ encoder.encode(context);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new SecurityException(e);
+ }
+ }
+
+ public void encodeRespone(HttpServletRequest req, HttpServletResponse resp,
+ StatusResponseType response, String targetLocation, String relayState, Credential credentials, IRequest pendingReq)
+ throws MessageEncodingException, SecurityException {
+
+ try {
+ //load default PVP security configurations
+ EAAFDefaultSAML2Bootstrap.initializeDefaultPVPConfiguration();
+
+ log.debug("create SAML POSTBinding response");
+
+ //initialize POST binding encoder with template decoration
+ IGUIBuilderConfiguration guiConfig = guiConfigFactory.getSPSpecificSAML2PostConfiguration(
+ pendingReq,
+ "pvp_postbinding_template.html",
+ authConfig.getConfigurationRootDirectory());
+ HTTPPostEncoderWithOwnTemplate encoder = new HTTPPostEncoderWithOwnTemplate(guiConfig, guiBuilder,
+ VelocityProvider.getClassPathVelocityEngine());
+
+ //set OpenSAML2 process parameter into binding context dao
+ HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
+ resp, true);
+ BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ SingleSignOnService service = new SingleSignOnServiceBuilder()
+ .buildObject();
+ service.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
+ service.setLocation(targetLocation);
+ context.setOutboundSAMLMessageSigningCredential(credentials);
+ context.setPeerEntityEndpoint(service);
+ // context.setOutboundMessage(authReq);
+ context.setOutboundSAMLMessage(response);
+ context.setOutboundMessageTransport(responseAdapter);
+ context.setRelayState(relayState);
+
+ encoder.encode(context);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new SecurityException(e);
+ }
+ }
+
+ public InboundMessageInterface decode(HttpServletRequest req,
+ HttpServletResponse resp, MetadataProvider metadataProvider, boolean isSPEndPoint, URIComparator comparator) throws MessageDecodingException,
+ SecurityException {
+
+ HTTPPostDecoder decode = new HTTPPostDecoder(new BasicParserPool());
+ BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ 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);
+
+ //set security policy context
+ BasicSecurityPolicy policy = new BasicSecurityPolicy();
+ policy.getPolicyRules().add(
+ new PVPSignedRequestPolicyRule(metadataProvider,
+ TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider),
+ messageContext.getPeerEntityRole()));
+ SecurityPolicyResolver secResolver = new StaticSecurityPolicyResolver(policy);
+ messageContext.setSecurityPolicyResolver(secResolver);
+
+ decode.decode(messageContext);
+
+ InboundMessage msg = null;
+ if (messageContext.getInboundMessage() instanceof RequestAbstractType) {
+ RequestAbstractType inboundMessage = (RequestAbstractType) messageContext
+ .getInboundMessage();
+ msg = new PVPSProfileRequest(inboundMessage, getSAML2BindingName());
+ msg.setEntityID(inboundMessage.getIssuer().getValue());
+
+ } else if (messageContext.getInboundMessage() instanceof StatusResponseType){
+ StatusResponseType inboundMessage = (StatusResponseType) messageContext.getInboundMessage();
+ msg = new PVPSProfileResponse(inboundMessage);
+ msg.setEntityID(inboundMessage.getIssuer().getValue());
+
+ } else
+ //create empty container if request type is unknown
+ msg = new InboundMessage();
+
+ if (messageContext.getPeerEntityMetadata() != null)
+ msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID());
+
+ else {
+ if (StringUtils.isEmpty(msg.getEntityID()))
+ log.info("No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer());
+ }
+
+
+ msg.setVerified(true);
+ msg.setRelayState(messageContext.getRelayState());
+
+ return msg;
+ }
+
+ public boolean handleDecode(String action, HttpServletRequest req) {
+ return (req.getMethod().equals("POST") && action.equals(PVPConstants.POST));
+ }
+
+ public String getSAML2BindingName() {
+ return SAMLConstants.SAML2_POST_BINDING_URI;
+ }
+}
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
new file mode 100644
index 00000000..949cbe57
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.binding;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.common.binding.decoding.URIComparator;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.binding.decoding.HTTPRedirectDeflateDecoder;
+import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder;
+import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule;
+import org.opensaml.saml2.core.RequestAbstractType;
+import org.opensaml.saml2.core.StatusResponseType;
+import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.SingleSignOnService;
+import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.ws.message.decoder.MessageDecodingException;
+import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.opensaml.ws.security.SecurityPolicyResolver;
+import org.opensaml.ws.security.provider.BasicSecurityPolicy;
+import org.opensaml.ws.security.provider.StaticSecurityPolicyResolver;
+import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
+import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
+import org.opensaml.xml.parse.BasicParserPool;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.credential.Credential;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.modules.pvp2.PVPConstants;
+import at.gv.egiz.eaaf.modules.pvp2.api.binding.IDecoder;
+import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder;
+import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileRequest;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileResponse;
+import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EAAFDefaultSAML2Bootstrap;
+import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PVPAuthRequestSignedRole;
+
+@Service("PVPRedirectBinding")
+public class RedirectBinding implements IDecoder, IEncoder {
+
+ private static final Logger log = LoggerFactory.getLogger(RedirectBinding.class);
+
+ public void encodeRequest(HttpServletRequest req, HttpServletResponse resp,
+ RequestAbstractType request, String targetLocation, String relayState, Credential credentials, IRequest pendingReq)
+ throws MessageEncodingException, SecurityException {
+
+ //load default PVP security configurations
+ EAAFDefaultSAML2Bootstrap.initializeDefaultPVPConfiguration();
+
+ log.debug("create SAML RedirectBinding response");
+
+ HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
+ HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
+ resp, true);
+ BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ SingleSignOnService service = new SingleSignOnServiceBuilder()
+ .buildObject();
+ service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ service.setLocation(targetLocation);
+ context.setOutboundSAMLMessageSigningCredential(credentials);
+ context.setPeerEntityEndpoint(service);
+ context.setOutboundSAMLMessage(request);
+ context.setOutboundMessageTransport(responseAdapter);
+ context.setRelayState(relayState);
+
+ encoder.encode(context);
+ }
+
+ public void encodeRespone(HttpServletRequest req, HttpServletResponse resp,
+ StatusResponseType response, String targetLocation, String relayState,
+ Credential credentials, IRequest pendingReq) throws MessageEncodingException, SecurityException {
+
+ //load default PVP security configurations
+ EAAFDefaultSAML2Bootstrap.initializeDefaultPVPConfiguration();
+
+ log.debug("create SAML RedirectBinding response");
+
+ HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
+ HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
+ resp, true);
+ BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ SingleSignOnService service = new SingleSignOnServiceBuilder()
+ .buildObject();
+ service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ service.setLocation(targetLocation);
+ context.setOutboundSAMLMessageSigningCredential(credentials);
+ context.setPeerEntityEndpoint(service);
+ context.setOutboundSAMLMessage(response);
+ context.setOutboundMessageTransport(responseAdapter);
+ context.setRelayState(relayState);
+
+ encoder.encode(context);
+
+ }
+
+ public InboundMessageInterface decode(HttpServletRequest req,
+ HttpServletResponse resp, MetadataProvider metadataProvider, boolean isSPEndPoint, URIComparator comparator) throws MessageDecodingException,
+ SecurityException {
+
+ HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder(
+ new BasicParserPool());
+
+ BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ 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);
+
+ SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule(
+ TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider));
+ PVPAuthRequestSignedRole signedRole = new PVPAuthRequestSignedRole();
+ BasicSecurityPolicy policy = new BasicSecurityPolicy();
+ policy.getPolicyRules().add(signedRole);
+ policy.getPolicyRules().add(signatureRule);
+ 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);
+
+ try {
+ decode.decode(messageContext);
+
+ //check signature
+ signatureRule.evaluate(messageContext);
+
+ } catch (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) {
+ RequestAbstractType inboundMessage = (RequestAbstractType) messageContext
+ .getInboundMessage();
+ msg = new PVPSProfileRequest(inboundMessage, getSAML2BindingName());
+
+
+ } else if (messageContext.getInboundMessage() instanceof StatusResponseType){
+ 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;
+ }
+
+ public boolean handleDecode(String action, HttpServletRequest req) {
+ return ((action.equals(PVPConstants.REDIRECT) || action.equals(PVPConstants.SINGLELOGOUT))
+ && req.getMethod().equals("GET"));
+ }
+
+ public String getSAML2BindingName() {
+ return SAMLConstants.SAML2_REDIRECT_BINDING_URI;
+ }
+}
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
new file mode 100644
index 00000000..2c2e0d77
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.binding;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.common.binding.decoding.URIComparator;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.binding.encoding.HTTPSOAP11Encoder;
+import org.opensaml.saml2.core.RequestAbstractType;
+import org.opensaml.saml2.core.StatusResponseType;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.ws.message.decoder.MessageDecodingException;
+import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.opensaml.ws.soap.soap11.Envelope;
+import org.opensaml.ws.soap.soap11.decoder.http.HTTPSOAP11Decoder;
+import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
+import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
+import org.opensaml.xml.XMLObject;
+import org.opensaml.xml.parse.BasicParserPool;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.credential.Credential;
+import org.opensaml.xml.signature.SignableXMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.modules.pvp2.PVPConstants;
+import at.gv.egiz.eaaf.modules.pvp2.api.binding.IDecoder;
+import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder;
+import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
+import at.gv.egiz.eaaf.modules.pvp2.exception.AttributQueryException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileRequest;
+import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EAAFDefaultSAML2Bootstrap;
+
+@Service("PVPSOAPBinding")
+public class SoapBinding implements IDecoder, IEncoder {
+
+ private static final Logger log = LoggerFactory.getLogger(SoapBinding.class);
+ public InboundMessageInterface decode(HttpServletRequest req,
+ HttpServletResponse resp, MetadataProvider metadataProvider, boolean isSPEndPoint, URIComparator comparator) throws MessageDecodingException,
+ SecurityException, PVP2Exception {
+ HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder(new BasicParserPool());
+ BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext =
+ new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ messageContext
+ .setInboundMessageTransport(new HttpServletRequestAdapter(
+ req));
+ messageContext.setMetadataProvider(metadataProvider);
+
+ //TODO: update in a futher version:
+ // requires a special SignedSOAPRequestPolicyRole because
+ // messageContext.getInboundMessage() is not directly signed
+
+ //set security context
+// BasicSecurityPolicy policy = new BasicSecurityPolicy();
+// policy.getPolicyRules().add(
+// new MOAPVPSignedRequestPolicyRule(
+// TrustEngineFactory.getSignatureKnownKeysTrustEngine(),
+// SPSSODescriptor.DEFAULT_ELEMENT_NAME));
+// SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver(
+// policy);
+// messageContext.setSecurityPolicyResolver(resolver);
+
+ //decode message
+ soapDecoder.decode(messageContext);
+
+ Envelope inboundMessage = (Envelope) messageContext
+ .getInboundMessage();
+
+ if (inboundMessage.getBody() != null) {
+ List<XMLObject> xmlElemList = inboundMessage.getBody().getUnknownXMLObjects();
+
+ if (!xmlElemList.isEmpty()) {
+ SignableXMLObject attrReq = (SignableXMLObject) xmlElemList.get(0);
+ PVPSProfileRequest request = new PVPSProfileRequest(attrReq, getSAML2BindingName());
+
+ if (messageContext.getPeerEntityMetadata() != null)
+ request.setEntityID(messageContext.getPeerEntityMetadata().getEntityID());
+
+ else if (attrReq instanceof RequestAbstractType) {
+ 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 (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);
+ }
+
+ public boolean handleDecode(String action, HttpServletRequest req) {
+ return (req.getMethod().equals("POST") &&
+ (action.equals(PVPConstants.SOAP) || action.equals(PVPConstants.ATTRIBUTEQUERY)));
+ }
+
+ public void encodeRequest(HttpServletRequest req, HttpServletResponse resp,
+ RequestAbstractType request, String targetLocation, String relayState, Credential credentials, IRequest pendingReq)
+ throws MessageEncodingException, SecurityException, PVP2Exception {
+
+ }
+
+ public void encodeRespone(HttpServletRequest req, HttpServletResponse resp,
+ StatusResponseType response, String targetLocation, String relayState, Credential credentials, IRequest pendingReq)
+ throws MessageEncodingException, SecurityException, PVP2Exception {
+
+ //load default PVP security configurations
+ EAAFDefaultSAML2Bootstrap.initializeDefaultPVPConfiguration();
+
+ HTTPSOAP11Encoder encoder = new HTTPSOAP11Encoder();
+ HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
+ resp, true);
+ BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ context.setOutboundSAMLMessageSigningCredential(credentials);
+ context.setOutboundSAMLMessage(response);
+ context.setOutboundMessageTransport(responseAdapter);
+
+ encoder.encode(context);
+
+ }
+
+ public String getSAML2BindingName() {
+ return SAMLConstants.SAML2_SOAP11_BINDING_URI;
+ }
+
+}
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
new file mode 100644
index 00000000..abc47e81
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/CitizenTokenBuilder.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.builder;
+
+import org.opensaml.saml2.core.Attribute;
+import org.opensaml.saml2.core.AttributeValue;
+import org.opensaml.xml.Configuration;
+import org.opensaml.xml.XMLObject;
+import org.opensaml.xml.schema.XSInteger;
+import org.opensaml.xml.schema.XSString;
+import org.opensaml.xml.schema.impl.XSIntegerBuilder;
+import org.opensaml.xml.schema.impl.XSStringBuilder;
+
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+
+public class CitizenTokenBuilder {
+
+ public static XMLObject buildAttributeStringValue(String value) {
+ XSStringBuilder stringBuilder = (XSStringBuilder) Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME);
+ XSString stringValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
+ stringValue.setValue(value);
+ return stringValue;
+ }
+
+ public static XMLObject buildAttributeIntegerValue(int value) {
+ XSIntegerBuilder integerBuilder = (XSIntegerBuilder) Configuration.getBuilderFactory().getBuilder(XSInteger.TYPE_NAME);
+ XSInteger integerValue = integerBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSInteger.TYPE_NAME);
+ integerValue.setValue(value);
+ return integerValue;
+ }
+
+ public static Attribute buildStringAttribute(String friendlyName,
+ String name, String value) {
+ Attribute attribute =
+ SAML2Utils.createSAMLObject(Attribute.class);
+ attribute.setFriendlyName(friendlyName);
+ attribute.setName(name);
+ attribute.getAttributeValues().add(buildAttributeStringValue(value));
+ return attribute;
+ }
+
+ public static Attribute buildIntegerAttribute(String friendlyName,
+ String name, int value) {
+ Attribute attribute =
+ SAML2Utils.createSAMLObject(Attribute.class);
+ attribute.setFriendlyName(friendlyName);
+ attribute.setName(name);
+ attribute.getAttributeValues().add(buildAttributeIntegerValue(value));
+ return attribute;
+ }
+
+ public static Attribute buildPVPVersion(String value) {
+ return buildStringAttribute("PVP-VERSION",
+ "urn:oid:1.2.40.0.10.2.1.1.261.10", value);
+ }
+
+ public static Attribute buildSecClass(int value) {
+ return buildIntegerAttribute("SECCLASS",
+ "", value);
+ }
+
+ public static Attribute buildPrincipalName(String value) {
+ return buildStringAttribute("PRINCIPAL-NAME",
+ "urn:oid:1.2.40.0.10.2.1.1.261.20", value);
+ }
+
+ public static Attribute buildGivenName(String value) {
+ return buildStringAttribute("GIVEN-NAME",
+ "urn:oid:2.5.4.42", value);
+ }
+
+ public static Attribute buildBirthday(String value) {
+ return buildStringAttribute("BIRTHDATE",
+ "urn:oid:1.2.40.0.10.2.1.1.55", value);
+ }
+
+ public static Attribute buildBPK(String value) {
+ return buildStringAttribute("BPK",
+ "urn:oid:1.2.40.0.10.2.1.1.149", value);
+ }
+
+ public static Attribute buildEID_CITIZEN_QAALEVEL(int value) {
+ return buildIntegerAttribute("EID-CITIZEN-QAA-LEVEL",
+ "urn:oid:1.2.40.0.10.2.1.1.261.94", value);
+ }
+
+ public static Attribute buildEID_ISSUING_NATION(String value) {
+ return buildStringAttribute("EID-ISSUING-NATION",
+ "urn:oid:1.2.40.0.10.2.1.1.261.32", value);
+ }
+
+ public static Attribute buildEID_SECTOR_FOR_IDENTIFIER(String value) {
+ return buildStringAttribute("EID-SECTOR-FOR-IDENTIFIER",
+ "urn:oid:1.2.40.0.10.2.1.1.261.34", value);
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PVPAttributeBuilder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PVPAttributeBuilder.java
new file mode 100644
index 00000000..41623f3d
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PVPAttributeBuilder.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.builder;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ServiceLoader;
+
+import org.opensaml.saml2.core.Attribute;
+import org.opensaml.saml2.metadata.RequestedAttribute;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+import at.gv.egiz.eaaf.core.exceptions.InvalidDateFormatAttributeException;
+import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidDateFormatException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+
+public class PVPAttributeBuilder {
+
+ private static final Logger log = LoggerFactory.getLogger(PVPAttributeBuilder.class);
+
+ private static IAttributeGenerator<Attribute> generator = new SamlAttributeGenerator();
+ private static HashMap<String, IAttributeBuilder> builders;
+
+ private static ServiceLoader<IAttributeBuilder> attributBuilderLoader =
+ ServiceLoader.load(IAttributeBuilder.class);
+
+ private static void addBuilder(IAttributeBuilder builder) {
+ builders.put(builder.getName(), builder);
+ }
+
+ static {
+ builders = new HashMap<String, IAttributeBuilder>();
+
+ log.info("Loading protocol attribut-builder modules:");
+ if (attributBuilderLoader != null ) {
+ Iterator<IAttributeBuilder> moduleLoaderInterator = attributBuilderLoader.iterator();
+ while (moduleLoaderInterator.hasNext()) {
+ try {
+ IAttributeBuilder modul = moduleLoaderInterator.next();
+ log.info("Loading attribut-builder Modul Information: " + modul.getName());
+ addBuilder(modul);
+
+ } catch(Throwable e) {
+ log.error("Check configuration! " + "Some attribute-builder modul" +
+ " is not a valid IAttributeBuilder", e);
+ }
+ }
+ }
+
+ log.info("Loading attribute-builder modules done");
+
+ }
+
+
+ /**
+ * Get a specific attribute builder
+ *
+ * @param name Attribute-builder friendly name
+ *
+ * @return Attribute-builder with this name or null if builder does not exists
+ */
+ public static IAttributeBuilder getAttributeBuilder(String name) {
+ return builders.get(name);
+
+ }
+
+ public static Attribute buildAttribute(String name, ISPConfiguration oaParam,
+ IAuthData authData) throws PVP2Exception, AttributeBuilderException {
+ if (builders.containsKey(name)) {
+ try {
+ return builders.get(name).build(oaParam, authData, generator);
+ }
+ catch (AttributeBuilderException e) {
+ if (e instanceof UnavailableAttributeException) {
+ throw e;
+
+ } else if (e instanceof InvalidDateFormatAttributeException) {
+ throw new InvalidDateFormatException();
+
+ } else {
+ throw new UnavailableAttributeException(name);
+
+ }
+ }
+ }
+ return null;
+ }
+
+ public static Attribute buildEmptyAttribute(String name) {
+ if (builders.containsKey(name)) {
+ return builders.get(name).buildEmpty(generator);
+ }
+ return null;
+ }
+
+ public static Attribute buildAttribute(String name, String value) {
+ if (builders.containsKey(name)) {
+ return builders.get(name).buildEmpty(generator);
+ }
+ return null;
+ }
+
+
+
+ public static List<Attribute> buildSupportedEmptyAttributes() {
+ List<Attribute> attributes = new ArrayList<Attribute>();
+ Iterator<IAttributeBuilder> builderIt = builders.values().iterator();
+ while (builderIt.hasNext()) {
+ IAttributeBuilder builder = builderIt.next();
+ Attribute emptyAttribute = builder.buildEmpty(generator);
+ if (emptyAttribute != null) {
+ attributes.add(emptyAttribute);
+ }
+ }
+ return attributes;
+ }
+
+ public static RequestedAttribute buildReqAttribute(String name, String friendlyName, boolean required) {
+ RequestedAttribute attribute = SAML2Utils.createSAMLObject(RequestedAttribute.class);
+ attribute.setIsRequired(required);
+ attribute.setName(name);
+ attribute.setFriendlyName(friendlyName);
+ attribute.setNameFormat(Attribute.URI_REFERENCE);
+ return attribute;
+ }
+
+ /**
+ * Build a set of PVP Response-Attributes
+ * <br><br>
+ * <b>INFO:</b> If a specific attribute can not be build, a info is logged, but no execpetion is thrown.
+ * Therefore, the return List must not include all requested attributes.
+ *
+ * @param authData AuthenticationData <code>IAuthData</code> which is used to build the attribute values, but never <code>null</code>
+ * @param reqAttributenName List of PVP attribute names which are requested, but never <code>null</code>
+ * @return List of PVP attributes, but never <code>null</code>
+ */
+ public static List<Attribute> buildSetOfResponseAttributes(IAuthData authData,
+ Collection<String> reqAttributenName) {
+ List<Attribute> attrList = new ArrayList<Attribute>();
+ if (reqAttributenName != null) {
+ Iterator<String> it = reqAttributenName.iterator();
+ while (it.hasNext()) {
+ String reqAttributName = it.next();
+ try {
+ Attribute attr = PVPAttributeBuilder.buildAttribute(
+ reqAttributName, null, authData);
+ if (attr == null) {
+ log.info(
+ "Attribute generation failed! for "
+ + reqAttributName);
+
+ } else {
+ attrList.add(attr);
+
+ }
+
+ } catch (PVP2Exception e) {
+ log.info(
+ "Attribute generation failed! for "
+ + reqAttributName);
+
+ } catch (Exception e) {
+ log.warn(
+ "General Attribute generation failed! for "
+ + reqAttributName, e);
+
+ }
+ }
+ }
+
+ return attrList;
+ }
+
+
+}
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
new file mode 100644
index 00000000..abfac305
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PVPMetadataBuilder.java
@@ -0,0 +1,425 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.builder;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.opensaml.Configuration;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.metadata.AssertionConsumerService;
+import org.opensaml.saml2.metadata.AttributeConsumingService;
+import org.opensaml.saml2.metadata.ContactPerson;
+import org.opensaml.saml2.metadata.EntitiesDescriptor;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.KeyDescriptor;
+import org.opensaml.saml2.metadata.LocalizedString;
+import org.opensaml.saml2.metadata.NameIDFormat;
+import org.opensaml.saml2.metadata.Organization;
+import org.opensaml.saml2.metadata.RequestedAttribute;
+import org.opensaml.saml2.metadata.RoleDescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.ServiceName;
+import org.opensaml.saml2.metadata.SingleLogoutService;
+import org.opensaml.saml2.metadata.SingleSignOnService;
+import org.opensaml.xml.io.Marshaller;
+import org.opensaml.xml.io.MarshallingException;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.SecurityHelper;
+import org.opensaml.xml.security.credential.Credential;
+import org.opensaml.xml.security.credential.UsageType;
+import org.opensaml.xml.security.keyinfo.KeyInfoGenerator;
+import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory;
+import org.opensaml.xml.signature.Signature;
+import org.opensaml.xml.signature.SignatureException;
+import org.opensaml.xml.signature.Signer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Document;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataBuilderConfiguration;
+import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EAAFDefaultSAML2Bootstrap;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+
+/**
+ * @author tlenz
+ *
+ */
+
+@Service("PVPMetadataBuilder")
+public class PVPMetadataBuilder {
+
+ private static final Logger log = LoggerFactory.getLogger(PVPMetadataBuilder.class);
+
+ X509KeyInfoGeneratorFactory keyInfoFactory = null;
+
+ /**
+ *
+ */
+ public PVPMetadataBuilder() {
+ keyInfoFactory = new X509KeyInfoGeneratorFactory();
+ keyInfoFactory.setEmitEntityIDAsKeyName(true);
+ keyInfoFactory.setEmitEntityCertificate(true);
+
+ }
+
+
+ /**
+ *
+ * Build PVP 2.1 conform SAML2 metadata
+ *
+ * @param config
+ * PVPMetadataBuilder configuration
+ *
+ * @return PVP metadata as XML String
+ * @throws SecurityException
+ * @throws ConfigurationException
+ * @throws CredentialsNotAvailableException
+ * @throws TransformerFactoryConfigurationError
+ * @throws MarshallingException
+ * @throws TransformerException
+ * @throws ParserConfigurationException
+ * @throws IOException
+ * @throws SignatureException
+ */
+ public String buildPVPMetadata(IPVPMetadataBuilderConfiguration config) throws CredentialsNotAvailableException, EAAFException, SecurityException, TransformerFactoryConfigurationError, MarshallingException, TransformerException, ParserConfigurationException, IOException, SignatureException {
+ DateTime date = new DateTime();
+ EntityDescriptor entityDescriptor = SAML2Utils
+ .createSAMLObject(EntityDescriptor.class);
+
+ //set entityID
+ entityDescriptor.setEntityID(config.getEntityID());
+
+ //set contact and organisation information
+ List<ContactPerson> contactPersons = config.getContactPersonInformation();
+ if (contactPersons != null)
+ entityDescriptor.getContactPersons().addAll(contactPersons);
+
+ Organization organisation = config.getOrgansiationInformation();
+ if (organisation != null)
+ entityDescriptor.setOrganization(organisation);
+
+ //set IDP metadata
+ if (config.buildIDPSSODescriptor()) {
+ RoleDescriptor idpSSODesc = generateIDPMetadata(config);
+ if (idpSSODesc != null)
+ entityDescriptor.getRoleDescriptors().add(idpSSODesc);
+
+ }
+
+ //set SP metadata for interfederation
+ if (config.buildSPSSODescriptor()) {
+ RoleDescriptor spSSODesc = generateSPMetadata(config);
+ if (spSSODesc != null)
+ entityDescriptor.getRoleDescriptors().add(spSSODesc);
+
+ }
+
+ //set metadata signature parameters
+ Credential metadataSignCred = config.getMetadataSigningCredentials();
+ Signature signature = AbstractCredentialProvider.getIDPSignature(metadataSignCred);
+ SecurityHelper.prepareSignatureParams(signature, metadataSignCred, null, null);
+
+ //initialize XML document builder
+ DocumentBuilder builder;
+ DocumentBuilderFactory factory = DocumentBuilderFactory
+ .newInstance();
+
+ builder = factory.newDocumentBuilder();
+ Document document = builder.newDocument();
+
+
+ //build entities descriptor
+ if (config.buildEntitiesDescriptorAsRootElement()) {
+ EntitiesDescriptor entitiesDescriptor =
+ SAML2Utils.createSAMLObject(EntitiesDescriptor.class);
+ entitiesDescriptor.setName(config.getEntityFriendlyName());
+ entitiesDescriptor.setID(SAML2Utils.getSecureIdentifier());
+ entitiesDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil()));
+ entitiesDescriptor.getEntityDescriptors().add(entityDescriptor);
+
+ //load default PVP security configurations
+ EAAFDefaultSAML2Bootstrap.initializeDefaultPVPConfiguration();
+ entitiesDescriptor.setSignature(signature);
+
+
+ //marshall document
+ Marshaller out = Configuration.getMarshallerFactory()
+ .getMarshaller(entitiesDescriptor);
+ out.marshall(entitiesDescriptor, document);
+
+ } else {
+ entityDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil()));
+ entityDescriptor.setID(SAML2Utils.getSecureIdentifier());
+
+ entityDescriptor.setSignature(signature);
+
+
+
+ //marshall document
+ Marshaller out = Configuration.getMarshallerFactory()
+ .getMarshaller(entityDescriptor);
+ out.marshall(entityDescriptor, document);
+
+ }
+
+ //sign metadata
+ Signer.signObject(signature);
+
+ //transform metadata object to XML string
+ Transformer transformer = TransformerFactory.newInstance()
+ .newTransformer();
+
+ StringWriter sw = new StringWriter();
+ StreamResult sr = new StreamResult(sw);
+ DOMSource source = new DOMSource(document);
+ transformer.transform(source, sr);
+ sw.close();
+
+ return sw.toString();
+ }
+
+
+ private RoleDescriptor generateSPMetadata(IPVPMetadataBuilderConfiguration config) throws CredentialsNotAvailableException, SecurityException, EAAFException {
+ SPSSODescriptor spSSODescriptor = SAML2Utils.createSAMLObject(SPSSODescriptor.class);
+ spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);
+ spSSODescriptor.setAuthnRequestsSigned(config.wantAuthnRequestSigned());
+ spSSODescriptor.setWantAssertionsSigned(config.wantAssertionSigned());
+
+ KeyInfoGenerator keyInfoGenerator = keyInfoFactory.newInstance();
+
+ //Set AuthRequest Signing certificate
+ Credential authcredential = config.getRequestorResponseSigningCredentials();
+ if (authcredential == null) {
+ log.warn("SP Metadata generation FAILED! --> Builder has NO request signing-credential. ");
+ return null;
+
+ } else {
+ KeyDescriptor signKeyDescriptor = SAML2Utils
+ .createSAMLObject(KeyDescriptor.class);
+ signKeyDescriptor.setUse(UsageType.SIGNING);
+ signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authcredential));
+ spSSODescriptor.getKeyDescriptors().add(signKeyDescriptor);
+
+ }
+
+ //Set assertion encryption credentials
+ Credential authEncCredential = config.getEncryptionCredentials();
+
+ if (authEncCredential != null) {
+ KeyDescriptor encryKeyDescriptor = SAML2Utils
+ .createSAMLObject(KeyDescriptor.class);
+ encryKeyDescriptor.setUse(UsageType.ENCRYPTION);
+ encryKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authEncCredential));
+ spSSODescriptor.getKeyDescriptors().add(encryKeyDescriptor);
+
+ } else {
+ log.warn("No Assertion Encryption-Key defined. This setting is not recommended!");
+
+ }
+
+ //check nameID formates
+ if (config.getSPAllowedNameITTypes() == null || config.getSPAllowedNameITTypes().size() == 0) {
+ log.warn("SP Metadata generation FAILED! --> Builder has NO provideable SAML2 nameIDFormats. ");
+ return null;
+
+ } else {
+ for (String format : config.getSPAllowedNameITTypes()) {
+ NameIDFormat nameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class);
+ nameIDFormat.setFormat(format);
+ spSSODescriptor.getNameIDFormats().add(nameIDFormat);
+
+ }
+ }
+
+
+ //add POST-Binding assertion consumer services
+ if (StringUtils.isNotEmpty(config.getSPAssertionConsumerServicePostBindingURL())) {
+ AssertionConsumerService postassertionConsumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class);
+ postassertionConsumerService.setIndex(0);
+ postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
+ postassertionConsumerService.setLocation(config.getSPAssertionConsumerServicePostBindingURL());
+ postassertionConsumerService.setIsDefault(true);
+ spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService);
+
+ }
+
+ //add POST-Binding assertion consumer services
+ if (StringUtils.isNotEmpty(config.getSPAssertionConsumerServiceRedirectBindingURL())) {
+ AssertionConsumerService redirectassertionConsumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class);
+ redirectassertionConsumerService.setIndex(1);
+ redirectassertionConsumerService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ redirectassertionConsumerService.setLocation(config.getSPAssertionConsumerServiceRedirectBindingURL());
+ spSSODescriptor.getAssertionConsumerServices().add(redirectassertionConsumerService);
+
+ }
+
+ //validate WebSSO endpoints
+ if (spSSODescriptor.getAssertionConsumerServices().size() == 0) {
+ log.warn("SP Metadata generation FAILED! --> NO SAML2 AssertionConsumerService endpoint found. ");
+ return null;
+
+ }
+
+ //add POST-Binding SLO descriptor
+ if (StringUtils.isNotEmpty(config.getSPSLOPostBindingURL())) {
+ SingleLogoutService postSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ postSLOService.setLocation(config.getSPSLOPostBindingURL());
+ postSLOService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
+ spSSODescriptor.getSingleLogoutServices().add(postSLOService);
+
+ }
+
+ //add POST-Binding SLO descriptor
+ if (StringUtils.isNotEmpty(config.getSPSLORedirectBindingURL())) {
+ SingleLogoutService redirectSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ redirectSLOService.setLocation(config.getSPSLORedirectBindingURL());
+ redirectSLOService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ spSSODescriptor.getSingleLogoutServices().add(redirectSLOService);
+
+ }
+
+ //add POST-Binding SLO descriptor
+ if (StringUtils.isNotEmpty(config.getSPSLOSOAPBindingURL())) {
+ SingleLogoutService soapSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ soapSLOService.setLocation(config.getSPSLOSOAPBindingURL());
+ soapSLOService.setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI);
+ spSSODescriptor.getSingleLogoutServices().add(soapSLOService);
+
+ }
+
+
+ //add required attributes
+ List<RequestedAttribute> reqSPAttr = config.getSPRequiredAttributes();
+ AttributeConsumingService attributeService = SAML2Utils.createSAMLObject(AttributeConsumingService.class);
+
+ attributeService.setIndex(0);
+ attributeService.setIsDefault(true);
+ ServiceName serviceName = SAML2Utils.createSAMLObject(ServiceName.class);
+ serviceName.setName(new LocalizedString("Default Service", "en"));
+ attributeService.getNames().add(serviceName);
+
+ if (reqSPAttr != null && reqSPAttr.size() > 0) {
+ log.debug("Add " + reqSPAttr.size() + " attributes to SP metadata");
+ attributeService.getRequestAttributes().addAll(reqSPAttr);
+
+ } else {
+ log.debug("SP metadata contains NO requested attributes.");
+
+ }
+
+ spSSODescriptor.getAttributeConsumingServices().add(attributeService);
+
+ return spSSODescriptor;
+ }
+
+ private IDPSSODescriptor generateIDPMetadata(IPVPMetadataBuilderConfiguration config) throws EAAFException, CredentialsNotAvailableException, SecurityException {
+ //check response signing credential
+ Credential responseSignCred = config.getRequestorResponseSigningCredentials();
+ if (responseSignCred == null) {
+ log.warn("IDP Metadata generation FAILED! --> Builder has NO Response signing credential. ");
+ return null;
+
+ }
+
+ //check nameID formates
+ if (config.getIDPPossibleNameITTypes() == null || config.getIDPPossibleNameITTypes().size() == 0) {
+ log.warn("IDP Metadata generation FAILED! --> Builder has NO provideable SAML2 nameIDFormats. ");
+ return null;
+
+ }
+
+ // build SAML2 IDP-SSO descriptor element
+ IDPSSODescriptor idpSSODescriptor = SAML2Utils
+ .createSAMLObject(IDPSSODescriptor.class);
+
+ idpSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);
+
+ //set ass default value, because PVP 2.x specification defines this feature as MUST
+ idpSSODescriptor.setWantAuthnRequestsSigned(config.wantAuthnRequestSigned());
+
+ // add WebSSO descriptor for POST-Binding
+ if (StringUtils.isNotEmpty(config.getIDPWebSSOPostBindingURL())) {
+ SingleSignOnService postSingleSignOnService = SAML2Utils.createSAMLObject(SingleSignOnService.class);
+ postSingleSignOnService.setLocation(config.getIDPWebSSOPostBindingURL());
+ postSingleSignOnService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
+ idpSSODescriptor.getSingleSignOnServices().add(postSingleSignOnService);
+
+ }
+
+ // add WebSSO descriptor for Redirect-Binding
+ if (StringUtils.isNotEmpty(config.getIDPWebSSORedirectBindingURL())) {
+ SingleSignOnService postSingleSignOnService = SAML2Utils.createSAMLObject(SingleSignOnService.class);
+ postSingleSignOnService.setLocation(config.getIDPWebSSORedirectBindingURL());
+ postSingleSignOnService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ idpSSODescriptor.getSingleSignOnServices().add(postSingleSignOnService);
+
+ }
+
+ //add Single LogOut POST-Binding endpoing
+ if (StringUtils.isNotEmpty(config.getIDPSLOPostBindingURL())) {
+ SingleLogoutService postSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ postSLOService.setLocation(config.getIDPSLOPostBindingURL());
+ postSLOService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
+ idpSSODescriptor.getSingleLogoutServices().add(postSLOService);
+
+ }
+
+ //add Single LogOut Redirect-Binding endpoing
+ if (StringUtils.isNotEmpty(config.getIDPSLORedirectBindingURL())) {
+ SingleLogoutService redirectSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ redirectSLOService.setLocation(config.getIDPSLORedirectBindingURL());
+ redirectSLOService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ idpSSODescriptor.getSingleLogoutServices().add(redirectSLOService);
+
+ }
+
+ //validate WebSSO endpoints
+ if (idpSSODescriptor.getSingleSignOnServices().size() == 0) {
+ log.warn("IDP Metadata generation FAILED! --> NO SAML2 SingleSignOnService endpoint found. ");
+ return null;
+
+ }
+
+ //set assertion signing key
+ KeyDescriptor signKeyDescriptor = SAML2Utils
+ .createSAMLObject(KeyDescriptor.class);
+ signKeyDescriptor.setUse(UsageType.SIGNING);
+ KeyInfoGenerator keyInfoGenerator = keyInfoFactory.newInstance();
+ signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(config.getRequestorResponseSigningCredentials()));
+ idpSSODescriptor.getKeyDescriptors().add(signKeyDescriptor);
+
+ //set IDP attribute set
+ idpSSODescriptor.getAttributes().addAll(config.getIDPPossibleAttributes());
+
+ //set providable nameID formats
+ for (String format : config.getIDPPossibleNameITTypes()) {
+ NameIDFormat nameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class);
+ nameIDFormat.setFormat(format);
+ idpSSODescriptor.getNameIDFormats().add(nameIDFormat);
+
+ }
+
+ return idpSSODescriptor;
+
+ }
+
+}
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
new file mode 100644
index 00000000..cb36f202
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/SamlAttributeGenerator.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.builder;
+
+import org.opensaml.saml2.core.Attribute;
+import org.opensaml.saml2.core.AttributeValue;
+import org.opensaml.xml.Configuration;
+import org.opensaml.xml.XMLObject;
+import org.opensaml.xml.schema.XSInteger;
+import org.opensaml.xml.schema.XSString;
+import org.opensaml.xml.schema.impl.XSIntegerBuilder;
+import org.opensaml.xml.schema.impl.XSStringBuilder;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+
+public class SamlAttributeGenerator implements IAttributeGenerator<Attribute> {
+
+ private XMLObject buildAttributeStringValue(String value) {
+ XSStringBuilder stringBuilder = (XSStringBuilder) Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME);
+ XSString stringValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
+ stringValue.setValue(value);
+ return stringValue;
+ }
+
+ private XMLObject buildAttributeIntegerValue(int value) {
+ XSIntegerBuilder integerBuilder = (XSIntegerBuilder) Configuration.getBuilderFactory().getBuilder(XSInteger.TYPE_NAME);
+ XSInteger integerValue = integerBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSInteger.TYPE_NAME);
+ integerValue.setValue(value);
+ return integerValue;
+ }
+
+ public Attribute buildStringAttribute(final String friendlyName, final String name, final String value) {
+ Attribute attribute = SAML2Utils.createSAMLObject(Attribute.class);
+ attribute.setFriendlyName(friendlyName);
+ attribute.setName(name);
+ attribute.setNameFormat(Attribute.URI_REFERENCE);
+ attribute.getAttributeValues().add(buildAttributeStringValue(value));
+ return attribute;
+ }
+
+ public Attribute buildIntegerAttribute(final String friendlyName, final String name, final int value) {
+ Attribute attribute = SAML2Utils.createSAMLObject(Attribute.class);
+ attribute.setFriendlyName(friendlyName);
+ attribute.setName(name);
+ attribute.setNameFormat(Attribute.URI_REFERENCE);
+ attribute.getAttributeValues().add(buildAttributeIntegerValue(value));
+ return attribute;
+ }
+
+ public Attribute buildEmptyAttribute(final String friendlyName, final String name) {
+ Attribute attribute = SAML2Utils.createSAMLObject(Attribute.class);
+ attribute.setFriendlyName(friendlyName);
+ attribute.setName(name);
+ attribute.setNameFormat(Attribute.URI_REFERENCE);
+ return attribute;
+ }
+
+ public Attribute buildLongAttribute(String friendlyName, String name, long value) {
+ Attribute attribute = SAML2Utils.createSAMLObject(Attribute.class);
+ attribute.setFriendlyName(friendlyName);
+ attribute.setName(name);
+ attribute.setNameFormat(Attribute.URI_REFERENCE);
+ attribute.getAttributeValues().add(buildAttributeIntegerValue((int) value));
+ return attribute;
+ }
+
+}
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
new file mode 100644
index 00000000..adc2b516
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.message;
+
+import java.io.Serializable;
+
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.provider.MetadataProviderException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException;
+
+/**
+ * @author tlenz
+ *
+ */
+public class InboundMessage implements InboundMessageInterface, Serializable{
+ private static final Logger log = LoggerFactory.getLogger(InboundMessage.class);
+
+ private static final long serialVersionUID = 2395131650841669663L;
+
+ private Element samlMessage = null;
+ private boolean verified = false;
+ private String entityID = null;
+ private String relayState = null;
+
+
+ public EntityDescriptor getEntityMetadata(IPVPMetadataProvider metadataProvider) throws NoMetadataInformationException {
+ try {
+ if (metadataProvider == null)
+ throw new NullPointerException("No PVP MetadataProvider found.");
+
+ return metadataProvider.getEntityDescriptor(this.entityID);
+
+ } catch (MetadataProviderException e) {
+ log.warn("No Metadata for EntitiyID " + entityID);
+ throw new NoMetadataInformationException();
+ }
+ }
+
+ /**
+ * @param entitiyID the entitiyID to set
+ */
+ public void setEntityID(String entitiyID) {
+ this.entityID = entitiyID;
+ }
+
+ public void setVerified(boolean verified) {
+ this.verified = verified;
+ }
+
+ /**
+ * @param relayState the relayState to set
+ */
+ public void setRelayState(String relayState) {
+ this.relayState = relayState;
+ }
+
+ public void setSAMLMessage(Element msg) {
+ this.samlMessage = msg;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.messages.PVP21InboundMessage#getRelayState()
+ */
+ @Override
+ public String getRelayState() {
+ return relayState;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.messages.PVP21InboundMessage#getEntityID()
+ */
+ @Override
+ public String getEntityID() {
+ return entityID;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.messages.PVP21InboundMessage#isVerified()
+ */
+ @Override
+ public boolean isVerified() {
+ return verified;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.messages.PVP21InboundMessage#getInboundMessage()
+ */
+ @Override
+ public Element getInboundMessage() {
+ return samlMessage;
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PVPSProfileRequest.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PVPSProfileRequest.java
new file mode 100644
index 00000000..0a9a0c5b
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PVPSProfileRequest.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.message;
+
+
+import org.opensaml.Configuration;
+import org.opensaml.xml.io.Unmarshaller;
+import org.opensaml.xml.io.UnmarshallerFactory;
+import org.opensaml.xml.io.UnmarshallingException;
+import org.opensaml.xml.signature.SignableXMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PVPSProfileRequest extends InboundMessage{
+ private static final Logger log = LoggerFactory.getLogger(PVPSProfileRequest.class);
+
+ private static final long serialVersionUID = 8613921176727607896L;
+
+ private String binding = null;
+
+ public PVPSProfileRequest(SignableXMLObject inboundMessage, String binding) {
+ setSAMLMessage(inboundMessage.getDOM());
+ this.binding = binding;
+
+ }
+
+ public String getRequestBinding() {
+ return binding;
+ }
+
+ public SignableXMLObject getSamlRequest() {
+ UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
+ Unmarshaller unmashaller = unmarshallerFactory.getUnmarshaller(getInboundMessage());
+
+ try {
+ return (SignableXMLObject) unmashaller.unmarshall(getInboundMessage());
+
+ } catch (UnmarshallingException e) {
+ log.warn("AuthnRequest Unmarshaller error", e);
+ return null;
+ }
+
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PVPSProfileResponse.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PVPSProfileResponse.java
new file mode 100644
index 00000000..6102e1c8
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/PVPSProfileResponse.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.message;
+
+import org.opensaml.Configuration;
+import org.opensaml.saml2.core.StatusResponseType;
+import org.opensaml.xml.io.Unmarshaller;
+import org.opensaml.xml.io.UnmarshallerFactory;
+import org.opensaml.xml.io.UnmarshallingException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PVPSProfileResponse extends InboundMessage {
+
+ private static final Logger log = LoggerFactory.getLogger(PVPSProfileResponse.class);
+
+ private static final long serialVersionUID = -1133012928130138501L;
+
+ public PVPSProfileResponse(StatusResponseType response) {
+ setSAMLMessage(response.getDOM());
+ }
+
+ public StatusResponseType getResponse() {
+ UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
+ Unmarshaller unmashaller = unmarshallerFactory.getUnmarshaller(getInboundMessage());
+
+ try {
+ return (StatusResponseType) unmashaller.unmarshall(getInboundMessage());
+
+ } catch (UnmarshallingException e) {
+ log.warn("AuthnResponse Unmarshaller error", e);
+ return null;
+ }
+
+ }
+
+}
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
new file mode 100644
index 00000000..c3eaa9a3
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java
@@ -0,0 +1,446 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.metadata;
+
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.saml2.metadata.EntitiesDescriptor;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.RoleDescriptor;
+import org.opensaml.saml2.metadata.provider.ChainingMetadataProvider;
+import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
+import org.opensaml.saml2.metadata.provider.MetadataFilter;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.saml2.metadata.provider.MetadataProviderException;
+import org.opensaml.saml2.metadata.provider.ObservableMetadataProvider;
+import org.opensaml.xml.XMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.IDestroyableObject;
+import at.gv.egiz.eaaf.core.api.IGarbageCollectorProcessing;
+import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+
+public abstract class AbstractChainingMetadataProvider extends SimpleMetadataProvider
+ implements ObservableMetadataProvider, IGarbageCollectorProcessing,
+ IRefreshableMetadataProvider, IDestroyableObject, IPVPMetadataProvider {
+
+ private static final Logger log = LoggerFactory.getLogger(AbstractChainingMetadataProvider.class);
+
+ private MetadataProvider internalProvider = null;
+ private static Object mutex = new Object();
+ private Timer timer = null;
+
+
+ public AbstractChainingMetadataProvider() {
+ internalProvider = new ChainingMetadataProvider();
+
+ }
+
+ public final Timer getTimer() {
+ return this.timer;
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.config.auth.IGarbageCollectorProcessing#runGarbageCollector()
+ */
+ @Override
+ public void runGarbageCollector() {
+ synchronized (mutex) {
+ /**add new Metadataprovider or remove Metadataprovider which are not in use any more.**/
+ try {
+ log.trace("Check consistence of PVP2X metadata");
+ addAndRemoveMetadataProvider();
+
+ } catch (EAAFConfigurationException e) {
+ log.error("Access to MOA-ID configuration FAILED.", e);
+
+ }
+ }
+
+ }
+
+ public void fullyDestroy() {
+ internalDestroy();
+
+ }
+
+ @Override
+ public synchronized boolean refreshMetadataProvider(String entityID) {
+ try {
+ //check if metadata provider is already loaded
+ try {
+ if (internalProvider.getEntityDescriptor(entityID) != null)
+ return true;
+
+ } catch (MetadataProviderException e) {}
+
+
+ //reload metadata provider
+ String metadataURL = getMetadataURL(entityID);
+ if (StringUtils.isNotEmpty(metadataURL)) {
+ Map<String, HTTPMetadataProvider> actuallyLoadedProviders = getAllActuallyLoadedProviders();
+
+ // check if MetadataProvider is actually loaded
+ if (actuallyLoadedProviders.containsKey(metadataURL)) {
+ actuallyLoadedProviders.get(metadataURL).refresh();
+ log.info("SAML2 metadata for service provider: "
+ + entityID + " is refreshed.");
+ return true;
+
+ } else {
+ //load new Metadata Provider
+ if (timer == null)
+ timer = new Timer(true);
+
+ ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider;
+ chainProvider.addMetadataProvider(createNewMetadataProvider(entityID));
+
+ emitChangeEvent();
+ log.info("SAML2 metadata for service provider: "
+ + entityID + " is added.");
+ return true;
+
+ }
+
+ } else
+ log.debug("Can not refresh SAML2 metadata: NO SAML2 metadata URL for SP with Id: " + entityID);
+
+ } catch (MetadataProviderException e) {
+ log.warn("Refresh SAML2 metadata for service provider: "
+ + entityID + " FAILED.", e);
+
+ } catch (IOException e) {
+ log.warn("Refresh SAML2 metadata for service provider: "
+ + entityID + " FAILED.", e);
+
+ } catch (EAAFConfigurationException e) {
+ log.warn("Refresh SAML2 metadata for service provider: "
+ + entityID + " FAILED.", e);
+
+ } catch (CertificateException e) {
+ log.warn("Refresh SAML2 metadata for service provider: "
+ + entityID + " FAILED.", e);
+
+ }
+
+ return false;
+
+ }
+
+ public void internalDestroy() {
+ if (internalProvider != null && internalProvider instanceof ChainingMetadataProvider) {
+ log.info("Destrorying PVP-Authentication MetaDataProvider.");
+ ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider;
+
+ List<MetadataProvider> providers = chainProvider.getProviders();
+ for (MetadataProvider provider : providers) {
+ if (provider instanceof HTTPMetadataProvider) {
+ HTTPMetadataProvider httpprovider = (HTTPMetadataProvider) provider;
+ log.debug("Destroy HTTPMetadataProvider +" + httpprovider.getMetadataURI());
+ httpprovider.destroy();
+
+ } else {
+ log.warn("MetadataProvider can not be destroyed.");
+ }
+ }
+
+ internalProvider = new ChainingMetadataProvider();
+
+ if (timer != null)
+ timer.cancel();
+
+ } else {
+ log.warn("ReInitalize MOAMetaDataProvider is not possible! MOA-ID Instance has to be restarted manualy");
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider#requireValidMetadata()
+ */
+ @Override
+ public boolean requireValidMetadata() {
+ return internalProvider.requireValidMetadata();
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider#setRequireValidMetadata(boolean)
+ */
+ @Override
+ public void setRequireValidMetadata(boolean requireValidMetadata) {
+ internalProvider.setRequireValidMetadata(requireValidMetadata);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider#getMetadataFilter()
+ */
+ @Override
+ public MetadataFilter getMetadataFilter() {
+ return internalProvider.getMetadataFilter();
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider#setMetadataFilter(org.opensaml.saml2.metadata.provider.MetadataFilter)
+ */
+ @Override
+ public void setMetadataFilter(MetadataFilter newFilter)
+ throws MetadataProviderException {
+ internalProvider.setMetadataFilter(newFilter);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider#getMetadata()
+ */
+ @Override
+ public XMLObject getMetadata() throws MetadataProviderException {
+ return internalProvider.getMetadata();
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider#getEntitiesDescriptor(java.lang.String)
+ */
+ @Override
+ public EntitiesDescriptor getEntitiesDescriptor(String entitiesID)
+ throws MetadataProviderException {
+ EntitiesDescriptor entitiesDesc = null;
+ try {
+ entitiesDesc = internalProvider.getEntitiesDescriptor(entitiesID);
+
+ if (entitiesDesc == null) {
+ log.debug("Can not find PVP metadata for entityID: " + entitiesID
+ + " Start refreshing process ...");
+ if (refreshMetadataProvider(entitiesID))
+ return internalProvider.getEntitiesDescriptor(entitiesID);
+
+ }
+
+ } catch (MetadataProviderException e) {
+ log.debug("Can not find PVP metadata for entityID: " + entitiesID
+ + " Start refreshing process ...");
+ if (refreshMetadataProvider(entitiesID))
+ return internalProvider.getEntitiesDescriptor(entitiesID);
+
+ }
+
+ return entitiesDesc;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider#getEntityDescriptor(java.lang.String)
+ */
+ @Override
+ public EntityDescriptor getEntityDescriptor(String entityID)
+ throws MetadataProviderException {
+ EntityDescriptor entityDesc = null;
+ try {
+ entityDesc = internalProvider.getEntityDescriptor(entityID);
+ if (entityDesc == null) {
+ log.debug("Can not find PVP metadata for entityID: " + entityID
+ + " Start refreshing process ...");
+ if (refreshMetadataProvider(entityID))
+ return internalProvider.getEntityDescriptor(entityID);
+
+ }
+
+ } catch (MetadataProviderException e) {
+ log.debug("Can not find PVP metadata for entityID: " + entityID
+ + " Start refreshing process ...");
+ if (refreshMetadataProvider(entityID))
+ return internalProvider.getEntityDescriptor(entityID);
+
+ }
+
+// if (entityDesc != null)
+// lastAccess.put(entityID, new Date());
+
+ return entityDesc;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider#getRole(java.lang.String, javax.xml.namespace.QName)
+ */
+ @Override
+ public List<RoleDescriptor> getRole(String entityID, QName roleName)
+ throws MetadataProviderException {
+ List<RoleDescriptor> result = internalProvider.getRole(entityID, roleName);
+
+// if (result != null)
+// lastAccess.put(entityID, new Date());
+
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider#getRole(java.lang.String, javax.xml.namespace.QName, java.lang.String)
+ */
+ @Override
+ public RoleDescriptor getRole(String entityID, QName roleName,
+ String supportedProtocol) throws MetadataProviderException {
+ RoleDescriptor result = internalProvider.getRole(entityID, roleName, supportedProtocol);
+
+// if (result != null)
+// lastAccess.put(entityID, new Date());
+
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.opensaml.saml2.metadata.provider.ObservableMetadataProvider#getObservers()
+ */
+ @Override
+ public List<Observer> getObservers() {
+ return ((ChainingMetadataProvider) internalProvider).getObservers();
+ }
+
+
+ /**
+ * Get the URL to metadata for a specific entityID
+ *
+ * @param entityId
+ * @return
+ * @throws EAAFConfigurationException
+ */
+ protected abstract String getMetadataURL(String entityId) throws EAAFConfigurationException;
+
+ /**
+ * Creates a new implementation specific SAML2 metadata provider
+ *
+ * @param entityId
+ * @return
+ * @throws EAAFConfigurationException
+ * @throws IOException
+ * @throws CertificateException
+ * @throws ConfigurationException
+ */
+ protected abstract MetadataProvider createNewMetadataProvider(String entityId) throws EAAFConfigurationException, IOException, CertificateException;
+
+ /**
+ * Get a List of metadata URLs for all SAML2 SPs from configuration
+ *
+ * @throws EAAFConfigurationException
+ */
+ protected abstract List<String> getAllMetadataURLsFromConfiguration() throws EAAFConfigurationException;
+
+
+ protected void emitChangeEvent() {
+ if ((getObservers() == null) || (getObservers().size() == 0)) {
+ return;
+ }
+
+ List<Observer> tempObserverList = new ArrayList<Observer>(getObservers());
+ for (ObservableMetadataProvider.Observer observer : tempObserverList)
+ if (observer != null)
+ observer.onEvent(this);
+ }
+
+ private Map<String, HTTPMetadataProvider> getAllActuallyLoadedProviders() {
+ Map<String, HTTPMetadataProvider> loadedproviders = new HashMap<String, HTTPMetadataProvider>();
+ ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider;
+
+ //make a Map of all actually loaded HTTPMetadataProvider
+ List<MetadataProvider> providers = chainProvider.getProviders();
+ for (MetadataProvider provider : providers) {
+ if (provider instanceof HTTPMetadataProvider) {
+ HTTPMetadataProvider httpprovider = (HTTPMetadataProvider) provider;
+ loadedproviders.put(httpprovider.getMetadataURI(), httpprovider);
+
+ }
+ }
+
+ return loadedproviders;
+ }
+
+ private void addAndRemoveMetadataProvider() throws EAAFConfigurationException {
+ if (internalProvider != null && internalProvider instanceof ChainingMetadataProvider) {
+ log.info("Reload MOAMetaDataProvider.");
+
+ /*OpenSAML ChainingMetadataProvider can not remove a MetadataProvider (UnsupportedOperationException)
+ *The ChainingMetadataProvider use internal a unmodifiableList to hold all registrated MetadataProviders.*/
+ Map<String, MetadataProvider> providersinuse = new HashMap<String, MetadataProvider>();
+ ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider;
+
+ //get all actually loaded metadata providers
+ Map<String, HTTPMetadataProvider> loadedproviders = getAllActuallyLoadedProviders();
+
+ /* 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
+ List<String> allMetadataURLs = getAllMetadataURLsFromConfiguration();
+
+ if (allMetadataURLs != null) {
+ Iterator<String> metadataURLInterator = allMetadataURLs.iterator();
+ while (metadataURLInterator.hasNext()) {
+ String metadataurl = metadataURLInterator.next();
+ try {
+ if (StringUtils.isNotEmpty(metadataurl)) {
+ if (loadedproviders.containsKey(metadataurl)) {
+ // SAML2 SP is actually loaded, to nothing
+ providersinuse.put(metadataurl, loadedproviders.get(metadataurl));
+ loadedproviders.remove(metadataurl);
+
+ }
+ }
+ } catch (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
+ Collection<HTTPMetadataProvider> notusedproviders = loadedproviders.values();
+ for (HTTPMetadataProvider provider : notusedproviders) {
+ String metadataurl = provider.getMetadataURI();
+ try {
+ provider.destroy();
+
+ /*OpenSAML ChainingMetadataProvider can not remove a MetadataProvider (UnsupportedOperationException)
+ *The ChainingMetadataProvider use internal a unmodifiableList to hold all registrated MetadataProviders.*/
+ //chainProvider.removeMetadataProvider(provider);
+ log.info("Remove not used MetadataProvider with MetadataURL " + metadataurl);
+
+ } catch (Throwable e) {
+ log.error("HTTPMetadataProvider with URL " + metadataurl
+ + " can not be removed from the list of actually loaded Providers.", e);
+
+ }
+
+ }
+
+ try {
+ chainProvider.setProviders(new ArrayList<MetadataProvider>(providersinuse.values()));
+ emitChangeEvent();
+
+ } catch (MetadataProviderException e) {
+ log.warn("ReInitalize AbstractMetaDataProvider is not possible! Service has to be restarted manualy", e);
+
+ }
+
+ } else
+ log.warn("ReInitalize AbstractMetaDataProvider is not possible! Service has to be restarted manualy");
+
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java
new file mode 100644
index 00000000..37204520
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opensaml.saml2.metadata.provider.FilterException;
+import org.opensaml.saml2.metadata.provider.MetadataFilter;
+import org.opensaml.xml.XMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * @author tlenz
+ *
+ */
+public class MetadataFilterChain implements MetadataFilter {
+ private static final Logger log = LoggerFactory.getLogger(MetadataFilterChain.class);
+
+
+ private List<MetadataFilter> filters = new ArrayList<MetadataFilter>();
+
+ /**
+ * Return all actually used Metadata filters
+ *
+ * @return List of Metadata filters
+ */
+ public List<MetadataFilter> getFilters() {
+ return filters;
+ }
+
+ /**
+ * Add a new Metadata filter to filterchain
+ *
+ * @param filter
+ */
+ public void addFilter(MetadataFilter filter) {
+ filters.add(filter);
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml.XMLObject)
+ */
+ @Override
+ public void doFilter(XMLObject arg0) throws FilterException {
+ for (MetadataFilter filter : filters) {
+ log.trace("Use EAAFMetadataFilter " + filter.getClass().getName());
+ filter.doFilter(arg0);
+ }
+
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java
new file mode 100644
index 00000000..0c6ffb49
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.metadata;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.util.Timer;
+
+import javax.net.ssl.SSLHandshakeException;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider;
+import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
+import org.opensaml.saml2.metadata.provider.MetadataFilter;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.xml.parse.ParserPool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.impl.utils.FileUtils;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SignatureValidationException;
+
+/**
+ * @author tlenz
+ *
+ */
+public abstract class SimpleMetadataProvider implements MetadataProvider{
+ private static final Logger log = LoggerFactory.getLogger(SimpleMetadataProvider.class);
+
+ private static final String URI_PREFIX_HTTP = "http:";
+ private static final String URI_PREFIX_HTTPS = "https:";
+ private static final String URI_PREFIX_FILE = "file:";
+
+
+ @Autowired
+ protected IConfiguration authConfig;
+
+
+ /**
+ * Create a single SAML2 metadata provider
+ *
+ * @param metadataLocation where the metadata should be loaded, but never null. If the location starts with http(s):, than a http
+ * based metadata provider is used. If the location starts with file:, than a filesystem based metadata provider is used
+ * @param filter Filters, which should be used to validate the metadata
+ * @param IdForLogging Id, which is used for Logging
+ * @param timer {@link Timer} which is used to schedule metadata refresh operations
+ * @param httpClient Apache commons 3.x http client
+ *
+ * @return SAML2 Metadata Provider, or null if the metadata provider can not initialized
+ */
+ protected MetadataProvider createNewSimpleMetadataProvider(String metadataLocation, MetadataFilter filter,
+ String IdForLogging, Timer timer, ParserPool pool, HttpClient httpClient) {
+ if (metadataLocation.startsWith(URI_PREFIX_HTTP) || metadataLocation.startsWith(URI_PREFIX_HTTPS)) {
+ if (httpClient != null)
+ return createNewHTTPMetaDataProvider(metadataLocation, filter, IdForLogging, timer, pool, httpClient);
+
+ else {
+ log.warn("Can not load http(s) based SAML2 metadata without a HTTP client");
+ return null;
+ }
+
+ } else {
+ String absoluteMetadataLocation;
+ try {
+ absoluteMetadataLocation = FileUtils.makeAbsoluteURL(
+ metadataLocation,
+ authConfig.getConfigurationRootDirectory());
+
+ if (absoluteMetadataLocation.startsWith(URI_PREFIX_FILE)) {
+ File metadataFile = new File(absoluteMetadataLocation);
+ if (metadataFile.exists())
+ return createNewFileSystemMetaDataProvider(metadataFile, filter, IdForLogging, timer, pool);
+
+ else {
+ log.warn("SAML2 metadata file: " + absoluteMetadataLocation + " not found or not exist");
+ return null;
+ }
+
+ }
+
+
+ } catch (MalformedURLException e) {
+ log.warn("SAML2 metadata URL is invalid: " + metadataLocation, e);
+
+ }
+
+ }
+
+ log.warn("SAML2 metadata has an unsupported metadata location prefix: " + metadataLocation);
+ return null;
+
+ }
+
+
+ /**
+ * Create a single SAML2 filesystem based metadata provider
+ *
+ * @param metadataFile File, where the metadata should be loaded
+ * @param filter Filters, which should be used to validate the metadata
+ * @param IdForLogging Id, which is used for Logging
+ * @param timer {@link Timer} which is used to schedule metadata refresh operations
+ * @param pool
+ *
+ * @return SAML2 Metadata Provider
+ */
+ private MetadataProvider createNewFileSystemMetaDataProvider(File metadataFile, MetadataFilter filter, String IdForLogging, Timer timer, ParserPool pool) {
+ FilesystemMetadataProvider fileSystemProvider = null;
+ try {
+ fileSystemProvider = new FilesystemMetadataProvider(timer, metadataFile);
+ fileSystemProvider.setParserPool(pool);
+ fileSystemProvider.setRequireValidMetadata(true);
+ fileSystemProvider.setMinRefreshDelay(1000*60*15); //15 minutes
+ fileSystemProvider.setMaxRefreshDelay(1000*60*60*24); //24 hours
+ //httpProvider.setRefreshDelayFactor(0.1F);
+
+ fileSystemProvider.setMetadataFilter(filter);
+ fileSystemProvider.initialize();
+
+ fileSystemProvider.setRequireValidMetadata(true);
+
+ return fileSystemProvider;
+
+ } catch (Exception e) {
+ log.warn(
+ "Failed to load Metadata file for "
+ + IdForLogging + "[ "
+ + "File: " + metadataFile.getAbsolutePath()
+ + " Msg: " + e.getMessage() + " ]", e);
+
+
+ log.warn("Can not initialize SAML2 metadata provider from filesystem: " + metadataFile.getAbsolutePath()
+ + " Reason: " + e.getMessage(), e);
+
+ if (fileSystemProvider != null)
+ fileSystemProvider.destroy();
+
+ }
+
+ return null;
+
+ }
+
+
+
+ /**
+ * Create a single SAML2 HTTP metadata provider
+ *
+ * @param metadataURL URL, where the metadata should be loaded
+ * @param filter Filters, which should be used to validate the metadata
+ * @param IdForLogging Id, which is used for Logging
+ * @param timer {@link Timer} which is used to schedule metadata refresh operations
+ * @param pool
+ *
+ * @return SAML2 Metadata Provider
+ */
+ private MetadataProvider createNewHTTPMetaDataProvider(String metadataURL, MetadataFilter filter, String IdForLogging, Timer timer, ParserPool pool, HttpClient httpClient) {
+ HTTPMetadataProvider httpProvider = null;
+ try {
+ httpProvider = new HTTPMetadataProvider(timer, httpClient,
+ metadataURL);
+ httpProvider.setParserPool(pool);
+ httpProvider.setRequireValidMetadata(true);
+ httpProvider.setMinRefreshDelay(1000*60*15); //15 minutes
+ httpProvider.setMaxRefreshDelay(1000*60*60*24); //24 hours
+ //httpProvider.setRefreshDelayFactor(0.1F);
+
+ httpProvider.setMetadataFilter(filter);
+ httpProvider.initialize();
+
+ httpProvider.setRequireValidMetadata(true);
+
+ return httpProvider;
+
+ } catch (Throwable e) {
+ if (e.getCause() != null && e.getCause().getCause() instanceof SSLHandshakeException) {
+ log.warn("SSL-Server certificate for metadata "
+ + metadataURL + " not trusted.", e);
+
+ } if (e.getCause() != null && e.getCause().getCause() instanceof SignatureValidationException) {
+ log.warn("Signature verification for metadata"
+ + metadataURL + " FAILED.", e);
+
+ } if (e.getCause() != null && e.getCause().getCause() instanceof SchemaValidationException) {
+ log.warn("Schema validation for metadata "
+ + metadataURL + " FAILED.", e);
+ }
+
+ log.warn(
+ "Failed to load Metadata file for "
+ + IdForLogging + "[ "
+ + e.getMessage() + " ]", e);
+
+ if (httpProvider != null) {
+ log.debug("Destroy failed Metadata provider");
+ httpProvider.destroy();
+ }
+
+// if (timer != null) {
+// log.debug("Destroy Timer.");
+// timer.cancel();
+// }
+
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HTTPPostEncoderWithOwnTemplate.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HTTPPostEncoderWithOwnTemplate.java
new file mode 100644
index 00000000..d7491a88
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/HTTPPostEncoderWithOwnTemplate.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.opensaml.common.binding.SAMLMessageContext;
+import org.opensaml.saml2.binding.encoding.HTTPPostEncoder;
+import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.opensaml.ws.transport.http.HTTPOutTransport;
+import org.opensaml.ws.transport.http.HTTPTransportUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfiguration;
+import at.gv.egiz.eaaf.core.api.gui.IGUIFormBuilder;
+
+/**
+ * @author tlenz
+ *
+ */
+public class HTTPPostEncoderWithOwnTemplate extends HTTPPostEncoder {
+ private static final Logger log = LoggerFactory.getLogger(HTTPPostEncoderWithOwnTemplate.class);
+
+
+ private VelocityEngine velocityEngine;
+ private IGUIBuilderConfiguration guiConfig;
+ private IGUIFormBuilder guiBuilder;
+
+ /**
+ * @param engine
+ * @param templateId
+ */
+ public HTTPPostEncoderWithOwnTemplate(IGUIBuilderConfiguration guiConfig, IGUIFormBuilder guiBuilder, VelocityEngine engine) {
+ super(engine, null);
+ this.velocityEngine = engine;
+ this.guiConfig = guiConfig;
+ this.guiBuilder = guiBuilder;
+
+ }
+
+ /**
+ * Base64 and POST encodes the outbound message and writes it to the outbound transport.
+ *
+ * @param messageContext current message context
+ * @param endpointURL endpoint URL to which to encode message
+ *
+ * @throws MessageEncodingException thrown if there is a problem encoding the message
+ */
+ protected void postEncode(SAMLMessageContext messageContext, String endpointURL) throws MessageEncodingException {
+ log.debug("Invoking Velocity template to create POST body");
+ InputStream is = null;
+ try {
+ //build Velocity Context from GUI input paramters
+ VelocityContext context = guiBuilder.generateVelocityContextFromConfiguration(guiConfig);
+
+ //load template
+ is = guiBuilder.getTemplateInputStream(guiConfig);
+
+ //populate velocity context with SAML2 parameters
+ populateVelocityContext(context, messageContext, endpointURL);
+
+ //populate transport parameter
+ HTTPOutTransport outTransport = (HTTPOutTransport) messageContext.getOutboundMessageTransport();
+ HTTPTransportUtils.addNoCacheHeaders(outTransport);
+ HTTPTransportUtils.setUTF8Encoding(outTransport);
+ HTTPTransportUtils.setContentType(outTransport, "text/html");
+
+ //evaluate template and write content to response
+ Writer out = new OutputStreamWriter(outTransport.getOutgoingStream(), "UTF-8");
+ velocityEngine.evaluate(context, out, "SAML2_POST_BINDING", new BufferedReader(new InputStreamReader(is)));
+ out.flush();
+
+ } catch (Exception e) {
+ log.error("Error invoking Velocity template", e);
+ throw new MessageEncodingException("Error creating output document", e);
+
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+
+ } catch (IOException e) {
+ log.error("Can NOT close GUI-Template InputStream.", e);
+ }
+ }
+
+ }
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/KeyStoreX509CredentialAdapter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/KeyStoreX509CredentialAdapter.java
new file mode 100644
index 00000000..854a291e
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/KeyStoreX509CredentialAdapter.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml;
+
+import java.security.KeyStore;
+
+import org.opensaml.xml.security.x509.X509Credential;
+
+
+/**
+ * @author tlenz
+ *
+ */
+public class KeyStoreX509CredentialAdapter extends
+ org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter {
+
+ /**
+ * @param store
+ * @param alias
+ * @param password
+ */
+ public KeyStoreX509CredentialAdapter(KeyStore store, String alias,
+ char[] password) {
+ super(store, alias, password);
+ }
+
+ public Class<? extends X509Credential> getCredentialType() {
+ return X509Credential.class;
+ }
+
+
+}
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
new file mode 100644
index 00000000..8d0634fb
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/StringRedirectDeflateEncoder.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml;
+
+import org.opensaml.common.binding.SAMLMessageContext;
+import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder;
+import org.opensaml.ws.message.MessageContext;
+import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EAAFDefaultSAML2Bootstrap;
+
+/**
+ * @author tlenz
+ *
+ */
+public class StringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder {
+ private static final Logger log = LoggerFactory.getLogger(StringRedirectDeflateEncoder.class);
+
+ private String redirectURL = null;
+
+ public void encode(MessageContext messageContext)
+ throws MessageEncodingException {
+ if (!(messageContext instanceof SAMLMessageContext)) {
+ log.error("Invalid message context type, this encoder only support SAMLMessageContext");
+ throw new MessageEncodingException(
+ "Invalid message context type, this encoder only support SAMLMessageContext");
+ }
+
+ //load default PVP security configurations
+ EAAFDefaultSAML2Bootstrap.initializeDefaultPVPConfiguration();
+
+ SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext;
+
+ String endpointURL = getEndpointURL(samlMsgCtx).buildURL();
+
+ setResponseDestination(samlMsgCtx.getOutboundSAMLMessage(), endpointURL);
+
+ removeSignature(samlMsgCtx);
+
+ String encodedMessage = deflateAndBase64Encode(samlMsgCtx
+ .getOutboundSAMLMessage());
+
+ redirectURL = buildRedirectURL(samlMsgCtx, endpointURL,
+ encodedMessage);
+ }
+
+ /**
+ * @return the redirectURL
+ */
+ public String getRedirectURL() {
+ return redirectURL;
+ }
+
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EAAFDefaultSAML2Bootstrap.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EAAFDefaultSAML2Bootstrap.java
new file mode 100644
index 00000000..7b9bef88
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EAAFDefaultSAML2Bootstrap.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize;
+
+import org.opensaml.Configuration;
+import org.opensaml.DefaultBootstrap;
+import org.opensaml.xml.ConfigurationException;
+
+/**
+ * @author tlenz
+ *
+ */
+public class EAAFDefaultSAML2Bootstrap extends DefaultBootstrap {
+
+ public static synchronized void bootstrap() throws ConfigurationException {
+
+ initializeXMLSecurity();
+
+ initializeXMLTooling();
+
+ initializeArtifactBuilderFactories();
+
+ initializeGlobalSecurityConfiguration();
+
+ initializeParserPool();
+
+ initializeESAPI();
+
+ }
+
+ public static void initializeDefaultPVPConfiguration() {
+ initializeGlobalSecurityConfiguration();
+
+ }
+
+ /**
+ * Initializes the default global security configuration.
+ */
+ protected static void initializeGlobalSecurityConfiguration() {
+ Configuration.setGlobalSecurityConfiguration(EAAFDefaultSecurityConfigurationBootstrap.buildDefaultConfig());
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EAAFDefaultSecurityConfigurationBootstrap.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EAAFDefaultSecurityConfigurationBootstrap.java
new file mode 100644
index 00000000..0008ac87
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/initialize/EAAFDefaultSecurityConfigurationBootstrap.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize;
+
+import org.opensaml.xml.encryption.EncryptionConstants;
+import org.opensaml.xml.security.BasicSecurityConfiguration;
+import org.opensaml.xml.security.DefaultSecurityConfigurationBootstrap;
+import org.opensaml.xml.security.credential.BasicKeyInfoGeneratorFactory;
+import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorManager;
+import org.opensaml.xml.security.keyinfo.NamedKeyInfoGeneratorManager;
+import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory;
+import org.opensaml.xml.signature.SignatureConstants;
+
+/**
+ * @author tlenz
+ *
+ */
+public class EAAFDefaultSecurityConfigurationBootstrap extends
+ DefaultSecurityConfigurationBootstrap {
+
+ public static BasicSecurityConfiguration buildDefaultConfig() {
+ BasicSecurityConfiguration config = new BasicSecurityConfiguration();
+
+ populateSignatureParams(config);
+ populateEncryptionParams(config);
+ populateKeyInfoCredentialResolverParams(config);
+ populateKeyInfoGeneratorManager(config);
+ populateKeyParams(config);
+
+ return config;
+ }
+
+ protected static void populateKeyInfoGeneratorManager(
+ BasicSecurityConfiguration config) {
+ NamedKeyInfoGeneratorManager namedManager = new NamedKeyInfoGeneratorManager();
+ config.setKeyInfoGeneratorManager(namedManager);
+
+ namedManager.setUseDefaultManager(true);
+ KeyInfoGeneratorManager defaultManager = namedManager
+ .getDefaultManager();
+
+ BasicKeyInfoGeneratorFactory basicFactory = new BasicKeyInfoGeneratorFactory();
+ basicFactory.setEmitPublicKeyValue(true);
+
+ X509KeyInfoGeneratorFactory x509Factory = new X509KeyInfoGeneratorFactory();
+ x509Factory.setEmitEntityCertificate(true);
+
+ defaultManager.registerFactory(basicFactory);
+ defaultManager.registerFactory(x509Factory);
+ }
+
+ protected static void populateSignatureParams(
+ BasicSecurityConfiguration config) {
+
+ //use SHA256 instead of SHA1
+ config.registerSignatureAlgorithmURI("RSA",
+ SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
+
+ config.registerSignatureAlgorithmURI("DSA",
+ "http://www.w3.org/2000/09/xmldsig#dsa-sha1");
+
+ //use SHA256 instead of SHA1
+ config.registerSignatureAlgorithmURI("EC",
+ SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256);
+
+ //use SHA256 instead of SHA1
+ config.registerSignatureAlgorithmURI("AES",
+ SignatureConstants.ALGO_ID_MAC_HMAC_SHA256);
+
+
+ config.registerSignatureAlgorithmURI("DESede",
+ SignatureConstants.ALGO_ID_MAC_HMAC_SHA256);
+
+ config.setSignatureCanonicalizationAlgorithm("http://www.w3.org/2001/10/xml-exc-c14n#");
+ config.setSignatureHMACOutputLength(null);
+
+ //use SHA256 instead of SHA1
+ config.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256);
+ }
+
+ protected static void populateEncryptionParams(
+ BasicSecurityConfiguration config) {
+ config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(128),
+ "http://www.w3.org/2001/04/xmlenc#aes128-cbc");
+ config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(192),
+ "http://www.w3.org/2001/04/xmlenc#aes192-cbc");
+ config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(256),
+ "http://www.w3.org/2001/04/xmlenc#aes256-cbc");
+
+ //support GCM mode
+ config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(128),
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM);
+
+ config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(192),
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192_GCM);
+
+ config.registerDataEncryptionAlgorithmURI("AES", Integer.valueOf(256),
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM);
+
+
+ config.registerDataEncryptionAlgorithmURI("DESede",
+ Integer.valueOf(168),
+ "http://www.w3.org/2001/04/xmlenc#tripledes-cbc");
+ config.registerDataEncryptionAlgorithmURI("DESede",
+ Integer.valueOf(192),
+ "http://www.w3.org/2001/04/xmlenc#tripledes-cbc");
+
+ config.registerKeyTransportEncryptionAlgorithmURI("RSA", null, "AES",
+ "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
+
+ config.registerKeyTransportEncryptionAlgorithmURI("RSA", null,
+ "DESede", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
+
+ config.registerKeyTransportEncryptionAlgorithmURI("AES",
+ Integer.valueOf(128), null,
+ "http://www.w3.org/2001/04/xmlenc#kw-aes128");
+ config.registerKeyTransportEncryptionAlgorithmURI("AES",
+ Integer.valueOf(192), null,
+ "http://www.w3.org/2001/04/xmlenc#kw-aes192");
+ config.registerKeyTransportEncryptionAlgorithmURI("AES",
+ Integer.valueOf(256), null,
+ "http://www.w3.org/2001/04/xmlenc#kw-aes256");
+ config.registerKeyTransportEncryptionAlgorithmURI("DESede",
+ Integer.valueOf(168), null,
+ "http://www.w3.org/2001/04/xmlenc#kw-tripledes");
+ config.registerKeyTransportEncryptionAlgorithmURI("DESede",
+ Integer.valueOf(192), null,
+ "http://www.w3.org/2001/04/xmlenc#kw-tripledes");
+
+ config.setAutoGeneratedDataEncryptionKeyAlgorithmURI("http://www.w3.org/2001/04/xmlenc#aes128-cbc");
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java
new file mode 100644
index 00000000..40ad8a82
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.utils;
+
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.RSAPrivateKey;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.xml.security.credential.Credential;
+import org.opensaml.xml.security.credential.UsageType;
+import org.opensaml.xml.security.x509.X509Credential;
+import org.opensaml.xml.signature.Signature;
+import org.opensaml.xml.signature.SignatureConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils;
+import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.KeyStoreX509CredentialAdapter;
+
+public abstract class AbstractCredentialProvider {
+
+ private static final Logger log = LoggerFactory.getLogger(AbstractCredentialProvider.class);
+
+ private KeyStore keyStore = null;
+
+ /**
+ * Get a friendlyName for this keyStore implementation
+ * This friendlyName is used for logging
+ *
+ * @return keyStore friendlyName
+ */
+ public abstract String getFriendlyName();
+
+ /**
+ * Get KeyStore
+ *
+ * @return URL to the keyStore
+ * @throws EAAFException
+ */
+ public abstract String getKeyStoreFilePath() throws EAAFException;
+
+ /**
+ * Get keyStore password
+ *
+ * @return Password of the keyStore
+ */
+ public abstract String getKeyStorePassword();
+
+ /**
+ * Get alias of key for metadata signing
+ *
+ * @return key alias
+ */
+ public abstract String getMetadataKeyAlias();
+
+ /**
+ * Get password of key for metadata signing
+ *
+ * @return key password
+ */
+ public abstract String getMetadataKeyPassword();
+
+ /**
+ * Get alias of key for request/response signing
+ *
+ * @return key alias
+ */
+ public abstract String getSignatureKeyAlias();
+
+ /**
+ * Get password of key for request/response signing
+ *
+ * @return key password
+ */
+ public abstract String getSignatureKeyPassword();
+
+ /**
+ * Get alias of key for IDP response encryption
+ *
+ * @return key alias
+ */
+ public abstract String getEncryptionKeyAlias();
+
+ /**
+ * Get password of key for IDP response encryption
+ *
+ * @return key password
+ */
+ public abstract String getEncryptionKeyPassword();
+
+
+ public X509Credential getIDPMetaDataSigningCredential()
+ throws CredentialsNotAvailableException {
+ try {
+
+ if (keyStore == null)
+ keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(),
+ getKeyStorePassword());
+
+ KeyStoreX509CredentialAdapter credentials = new KeyStoreX509CredentialAdapter(
+ keyStore, getMetadataKeyAlias(), getMetadataKeyPassword().toCharArray());
+
+ credentials.setUsageType(UsageType.SIGNING);
+ if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) {
+ log.error(getFriendlyName() + " Metadata Signing credentials is not found or contains no PrivateKey.");
+ throw new CredentialsNotAvailableException("config.27", new Object[]{getFriendlyName() + " Assertion Signing credentials (Alias: "
+ + getMetadataKeyAlias() + ") is not found or contains no PrivateKey."});
+
+ }
+ return credentials;
+ } catch (Exception e) {
+ log.error("Failed to generate " + getFriendlyName() + " Metadata Signing credentials");
+ e.printStackTrace();
+ throw new CredentialsNotAvailableException("config.27", new Object[]{e.getMessage()}, e);
+ }
+ }
+
+ public X509Credential getIDPAssertionSigningCredential()
+ throws CredentialsNotAvailableException {
+ try {
+ if (keyStore == null)
+ keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(),
+ getKeyStorePassword());
+
+ KeyStoreX509CredentialAdapter credentials = new KeyStoreX509CredentialAdapter(
+ keyStore, getSignatureKeyAlias(), getSignatureKeyPassword().toCharArray());
+
+ credentials.setUsageType(UsageType.SIGNING);
+ if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) {
+ log.error(getFriendlyName() + " Assertion Signing credentials is not found or contains no PrivateKey.");
+ throw new CredentialsNotAvailableException("config.27", new Object[]{getFriendlyName() + " Assertion Signing credentials (Alias: "
+ + getSignatureKeyAlias() + ") is not found or contains no PrivateKey."});
+
+ }
+
+ return (X509Credential) credentials;
+ } catch (Exception e) {
+ log.error("Failed to generate " + getFriendlyName() + " Assertion Signing credentials");
+ e.printStackTrace();
+ throw new CredentialsNotAvailableException("config.27", new Object[]{e.getMessage()}, e);
+ }
+ }
+
+ public X509Credential getIDPAssertionEncryptionCredential()
+ throws CredentialsNotAvailableException {
+ try {
+ if (keyStore == null)
+ keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(),
+ getKeyStorePassword());
+
+ //if no encryption key is configured return null
+ if (StringUtils.isEmpty(getEncryptionKeyAlias()))
+ return null;
+
+ KeyStoreX509CredentialAdapter credentials = new KeyStoreX509CredentialAdapter(
+ keyStore, getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray());
+
+ credentials.setUsageType(UsageType.ENCRYPTION);
+
+ if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) {
+ log.error(getFriendlyName() + " Assertion Encryption credentials is not found or contains no PrivateKey.");
+ throw new CredentialsNotAvailableException("config.27", new Object[]{getFriendlyName() + " Assertion Encryption credentials (Alias: "
+ + getEncryptionKeyAlias() + ") is not found or contains no PrivateKey."});
+
+ }
+
+ return (X509Credential) credentials;
+
+ } catch (Exception e) {
+ log.error("Failed to generate " + getFriendlyName() + " Assertion Encryption credentials");
+ e.printStackTrace();
+ throw new CredentialsNotAvailableException("config.27", new Object[]{e.getMessage()}, e);
+ }
+ }
+
+ public static Signature getIDPSignature(Credential credentials) {
+ PrivateKey privatekey = credentials.getPrivateKey();
+ Signature signer = SAML2Utils.createSAMLObject(Signature.class);
+
+ if (privatekey instanceof RSAPrivateKey) {
+ signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
+
+ } else if (privatekey instanceof ECPrivateKey) {
+ signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256);
+
+ } else {
+ log.warn("Could NOT evaluate the Private-Key type from " + credentials.getEntityId() + " credential.");
+
+
+ }
+
+ signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
+ signer.setSigningCredential(credentials);
+ return signer;
+
+ }
+}
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
new file mode 100644
index 00000000..707f12e2
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QAALevelVerifier.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.utils;
+
+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;
+
+/**
+ * @author tlenz
+ *
+ */
+public class QAALevelVerifier {
+
+ private static final Logger log = LoggerFactory.getLogger(QAALevelVerifier.class);
+
+ public static void verifyQAALevel(String qaaAuth, String qaaRequest) throws QAANotAllowedException {
+
+ if (EAAFConstants.EIDAS_QAA_LOW.equals(qaaRequest) &&
+ (EAAFConstants.EIDAS_QAA_LOW.equals(qaaAuth) ||
+ EAAFConstants.EIDAS_QAA_SUBSTANTIAL.equals(qaaAuth) ||
+ EAAFConstants.EIDAS_QAA_HIGH.equals(qaaAuth))
+ )
+ log.debug("Requesed LoA fits LoA from authentication. Continue auth process ... ");
+
+ else if (EAAFConstants.EIDAS_QAA_SUBSTANTIAL.equals(qaaRequest) &&
+ (EAAFConstants.EIDAS_QAA_SUBSTANTIAL.equals(qaaAuth) ||
+ EAAFConstants.EIDAS_QAA_HIGH.equals(qaaAuth))
+ )
+ log.debug("Requesed LoA fits LoA from authentication. Continue auth process ... ");
+
+ else if (EAAFConstants.EIDAS_QAA_HIGH.equals(qaaRequest) && EAAFConstants.EIDAS_QAA_HIGH.equals(qaaAuth))
+ log.debug("Requesed LoA fits LoA from authentication. Continue auth process ... ");
+
+ else
+ throw new QAANotAllowedException(qaaAuth, qaaRequest);
+
+ }
+}
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
new file mode 100644
index 00000000..1da3fea3
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SAML2Utils.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.utils;
+
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.opensaml.Configuration;
+import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
+import org.opensaml.saml2.core.Status;
+import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.metadata.AssertionConsumerService;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.ws.soap.soap11.Body;
+import org.opensaml.ws.soap.soap11.Envelope;
+import org.opensaml.xml.XMLObject;
+import org.opensaml.xml.XMLObjectBuilderFactory;
+import org.opensaml.xml.io.Marshaller;
+import org.opensaml.xml.io.MarshallingException;
+import org.w3c.dom.Document;
+
+import at.gv.egiz.eaaf.core.impl.utils.Random;
+
+public class SAML2Utils {
+
+ public static <T> T createSAMLObject(final Class<T> clazz) {
+ try {
+ XMLObjectBuilderFactory builderFactory = Configuration
+ .getBuilderFactory();
+
+ QName defaultElementName = (QName) clazz.getDeclaredField(
+ "DEFAULT_ELEMENT_NAME").get(null);
+ @SuppressWarnings("unchecked")
+ T object = (T) builderFactory.getBuilder(defaultElementName)
+ .buildObject(defaultElementName);
+ return object;
+ } catch (Throwable e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static String getSecureIdentifier() {
+ return "_".concat(Random.nextHexRandom16());
+
+ /*Bug-Fix: There are open problems with RandomNumberGenerator via Java SPI and Java JDK 8.121
+ * Generation of a 16bit Random identifier FAILES with an Caused by: java.lang.ArrayIndexOutOfBoundsException
+ * Caused by: java.lang.ArrayIndexOutOfBoundsException
+ at iaik.security.random.o.engineNextBytes(Unknown Source)
+ at iaik.security.random.SecRandomSpi.engineNextBytes(Unknown Source)
+ at java.security.SecureRandom.nextBytes(SecureRandom.java:468)
+ at org.opensaml.common.impl.SecureRandomIdentifierGenerator.generateIdentifier(SecureRandomIdentifierGenerator.java:62)
+ at org.opensaml.common.impl.SecureRandomIdentifierGenerator.generateIdentifier(SecureRandomIdentifierGenerator.java:56)
+ at at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils.getSecureIdentifier(SAML2Utils.java:69)
+ */
+ //return idGenerator.generateIdentifier();
+ }
+
+ private static SecureRandomIdentifierGenerator idGenerator;
+
+ private static DocumentBuilder builder;
+ static {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ try {
+ idGenerator = new SecureRandomIdentifierGenerator();
+ } catch(NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static Document asDOMDocument(XMLObject object) throws IOException,
+ MarshallingException, TransformerException {
+ Document document = builder.newDocument();
+ Marshaller out = Configuration.getMarshallerFactory().getMarshaller(
+ object);
+ out.marshall(object, document);
+ return document;
+ }
+
+ public static Status getSuccessStatus() {
+ Status status = SAML2Utils.createSAMLObject(Status.class);
+ StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class);
+ statusCode.setValue(StatusCode.SUCCESS_URI);
+ status.setStatusCode(statusCode);
+ return status;
+ }
+
+ public static int getDefaultAssertionConsumerServiceIndex(SPSSODescriptor spSSODescriptor) {
+
+ List<AssertionConsumerService> assertionConsumerList = spSSODescriptor.getAssertionConsumerServices();
+
+ for (AssertionConsumerService el : assertionConsumerList) {
+ if (el.isDefault())
+ return el.getIndex();
+
+ }
+
+ return 0;
+ }
+
+ public static Envelope buildSOAP11Envelope(XMLObject payload) {
+ XMLObjectBuilderFactory bf = Configuration.getBuilderFactory();
+ Envelope envelope = (Envelope) bf.getBuilder(Envelope.DEFAULT_ELEMENT_NAME).buildObject(Envelope.DEFAULT_ELEMENT_NAME);
+ Body body = (Body) bf.getBuilder(Body.DEFAULT_ELEMENT_NAME).buildObject(Body.DEFAULT_ELEMENT_NAME);
+
+ body.getUnknownXMLObjects().add(payload);
+ envelope.setBody(body);
+
+ return envelope;
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/EAAFURICompare.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/EAAFURICompare.java
new file mode 100644
index 00000000..4d0963cb
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/EAAFURICompare.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.validation;
+
+import org.opensaml.common.binding.decoding.URIComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class EAAFURICompare implements URIComparator {
+ private static final Logger log = LoggerFactory.getLogger(EAAFURICompare.class);
+
+ private String serviceURL = "";
+
+ /**
+ *
+ *
+ * @param serviceURL public URL of the PVP S-Profile endpoint
+ */
+ public EAAFURICompare(String serviceURL) {
+ this.serviceURL = serviceURL;
+ }
+
+ public boolean compare(String uri1, String uri2) {
+ if (this.serviceURL.equals(uri1))
+ return true;
+
+ else {
+ log.warn("PVP request destination-endpoint: " + uri1
+ + " does not match to IDP endpoint:" + serviceURL);
+ return false;
+
+ }
+ }
+
+}
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
new file mode 100644
index 00000000..529f1ab6
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/TrustEngineFactory.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.validation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.security.MetadataCredentialResolver;
+import org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver;
+import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver;
+import org.opensaml.xml.security.keyinfo.KeyInfoProvider;
+import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider;
+import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider;
+import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider;
+import org.opensaml.xml.signature.SignatureTrustEngine;
+import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine;
+
+public class TrustEngineFactory {
+
+ public static SignatureTrustEngine getSignatureKnownKeysTrustEngine(MetadataProvider provider) {
+ MetadataCredentialResolver resolver;
+
+ resolver = new MetadataCredentialResolver(provider);
+
+ List<KeyInfoProvider> keyInfoProvider = new ArrayList<KeyInfoProvider>();
+ keyInfoProvider.add(new DSAKeyValueProvider());
+ keyInfoProvider.add(new RSAKeyValueProvider());
+ keyInfoProvider.add(new InlineX509DataProvider());
+
+ KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver(
+ keyInfoProvider);
+
+ ExplicitKeySignatureTrustEngine engine = new ExplicitKeySignatureTrustEngine(
+ resolver, keyInfoResolver);
+
+ return engine;
+
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/AbstractMetadataSignatureFilter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/AbstractMetadataSignatureFilter.java
new file mode 100644
index 00000000..286c1999
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/AbstractMetadataSignatureFilter.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.opensaml.saml2.metadata.EntitiesDescriptor;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.provider.MetadataFilter;
+import org.opensaml.xml.XMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2MetadataException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SignatureValidationException;
+
+public abstract class AbstractMetadataSignatureFilter implements MetadataFilter {
+ private static final Logger log = LoggerFactory.getLogger(AbstractMetadataSignatureFilter.class);
+
+ public void doFilter(XMLObject metadata) throws SignatureValidationException {
+ try {
+ if (metadata instanceof EntitiesDescriptor) {
+ EntitiesDescriptor entitiesDescriptor = (EntitiesDescriptor) metadata;
+ if(entitiesDescriptor.getSignature() == null) {
+ throw new PVP2MetadataException("Root element of metadata file has to be signed", null);
+ }
+ processEntitiesDescriptor(entitiesDescriptor);
+
+
+ if (entitiesDescriptor.getEntityDescriptors().size() == 0) {
+ throw new PVP2MetadataException("No valid entity in metadata "
+ + entitiesDescriptor.getName() + ". Metadata is not loaded.", null);
+ }
+
+
+ } else if (metadata instanceof EntityDescriptor) {
+ EntityDescriptor entityDescriptor = (EntityDescriptor) metadata;
+ processEntityDescriptorr(entityDescriptor);
+
+ } else {
+ throw new PVP2MetadataException("Invalid Metadata file Root element is no EntitiesDescriptor", null);
+ }
+
+
+
+ log.info("Metadata signature policy check done OK");
+ } catch (EAAFException e) {
+ log.warn("Metadata signature policy check FAILED.", e);
+ throw new SignatureValidationException(e);
+ }
+ }
+
+ /**
+ * Signature verification of a SAML2 EntityDescriptor element
+ *
+ * @param desc
+ * @throws PVP2MetadataException if the signature is not valid or can not verified
+ */
+ protected abstract void verify(EntityDescriptor desc) throws PVP2MetadataException;
+
+ /**
+ * Signature verification of a SAML2 EntitiesDescriptor element
+ *
+ * @param desc
+ * @throws PVP2MetadataException if the signature is not valid or can not verified
+ */
+ protected abstract void verify(EntitiesDescriptor desc) throws PVP2MetadataException;
+
+ /**
+ * Verify a EntityDescriptor element of an EntitiesDescriptor
+ *
+ * @param entity EntityDescriptor to verify
+ * @param desc Full EntitiesDescriptor that contains the EntityDescriptor
+ * @throws PVP2MetadataException
+ */
+ protected abstract void verify(EntityDescriptor entity, EntitiesDescriptor desc) throws PVP2MetadataException;
+
+
+ private void processEntityDescriptorr(EntityDescriptor desc) throws EAAFException {
+ verify(desc);
+
+ }
+
+ private void processEntitiesDescriptor(EntitiesDescriptor desc) throws EAAFException {
+ Iterator<EntitiesDescriptor> entID = desc.getEntitiesDescriptors().iterator();
+
+ if(desc.getSignature() != null) {
+ verify(desc);
+
+ }
+
+ while(entID.hasNext()) {
+ processEntitiesDescriptor(entID.next());
+ }
+
+ Iterator<EntityDescriptor> entIT = desc.getEntityDescriptors().iterator();
+ List<EntityDescriptor> verifiedEntIT = new ArrayList<EntityDescriptor>();
+
+ //check every Entity
+ while(entIT.hasNext()) {
+ EntityDescriptor entity = entIT.next();
+ log.debug("Validate metadata for entityID: " + entity.getEntityID() + " ..... ");
+ try {
+ verify(entity, desc);
+
+ //add entity to verified entity-list
+ verifiedEntIT.add(entity);
+ log.debug("Metadata for entityID: " + entity.getEntityID() + " valid");
+
+
+ } catch (Exception e) {
+ //remove entity of signature can not be verified.
+ log.info("Entity " + entity.getEntityID() + " is removed from metadata "
+ + desc.getName() + ". Entity verification error: " + e.getMessage());
+
+ }
+
+ }
+
+ //set only verified entity elements
+ desc.getEntityDescriptors().clear();
+ desc.getEntityDescriptors().addAll(verifiedEntIT);
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/PVPEntityCategoryFilter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/PVPEntityCategoryFilter.java
new file mode 100644
index 00000000..e29fb145
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/PVPEntityCategoryFilter.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.common.Extensions;
+import org.opensaml.saml2.core.Attribute;
+import org.opensaml.saml2.metadata.AttributeConsumingService;
+import org.opensaml.saml2.metadata.EntitiesDescriptor;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.LocalizedString;
+import org.opensaml.saml2.metadata.RequestedAttribute;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.ServiceName;
+import org.opensaml.saml2.metadata.provider.FilterException;
+import org.opensaml.saml2.metadata.provider.MetadataFilter;
+import org.opensaml.samlext.saml2mdattr.EntityAttributes;
+import org.opensaml.xml.XMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.impl.data.Trible;
+import at.gv.egiz.eaaf.modules.pvp2.PVPConstants;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2MetadataException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPAttributeBuilder;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+
+/**
+ * @author tlenz
+ *
+ */
+public class PVPEntityCategoryFilter implements MetadataFilter {
+ private static final Logger log = LoggerFactory.getLogger(PVPEntityCategoryFilter.class);
+
+ private boolean isUsed = false;
+
+ /**
+ * Filter to map PVP EntityCategories into a set of single PVP attributes
+ *
+ * @param isUsed if true PVP EntityCategories are mapped, otherwise they are ignored
+ *
+ */
+ public PVPEntityCategoryFilter(boolean isUsed) {
+ this.isUsed = isUsed;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml.XMLObject)
+ */
+ @Override
+ public void doFilter(XMLObject metadata) throws FilterException {
+
+ if (isUsed) {
+ log.trace("Map PVP EntityCategory to single PVP Attributes ... ");
+ String entityId = null;
+ try {
+ if (metadata instanceof EntitiesDescriptor) {
+ log.trace("Find EnitiesDescriptor ... ");
+ EntitiesDescriptor entitiesDesc = (EntitiesDescriptor) metadata;
+ if (entitiesDesc.getEntityDescriptors() != null) {
+ for (EntityDescriptor el : entitiesDesc.getEntityDescriptors())
+ resolveEntityCategoriesToAttributes(el);
+
+ }
+
+ } else if (metadata instanceof EntityDescriptor) {
+ log.trace("Find EntityDescriptor");
+ resolveEntityCategoriesToAttributes((EntityDescriptor)metadata);
+
+
+ } else
+ throw new PVP2MetadataException("Invalid Metadata file Root element is no Entities- or EntityDescriptor", null);
+
+
+
+ } catch (Exception e) {
+ log.warn("SAML2 Metadata processing FAILED: Can not resolve EntityCategories for metadata: " + entityId, e);
+
+ }
+
+ } else
+ log.trace("Filter to map PVP EntityCategory to single PVP Attributes is deactivated");
+
+ }
+
+ private void resolveEntityCategoriesToAttributes(EntityDescriptor metadata) {
+ log.debug("Resolving EntityCategorie for Entity: " + metadata.getEntityID() + " ...");
+ Extensions extensions = metadata.getExtensions();
+ if (extensions != null) {
+ List<XMLObject> listOfExt = extensions.getUnknownXMLObjects();
+ if (listOfExt != null && !listOfExt.isEmpty()) {
+ log.trace("Find #" + listOfExt.size() + " 'Extension' elements ");
+ for (XMLObject el : listOfExt) {
+ log.trace("Find ExtensionElement: " + el.getElementQName().toString());
+ if (el instanceof EntityAttributes) {
+ EntityAttributes entityAttrElem = (EntityAttributes)el;
+ if (entityAttrElem.getAttributes() != null) {
+ log.trace("Find EntityAttributes. Start attribute processing ...");
+ for (Attribute entityAttr : entityAttrElem.getAttributes()) {
+ if (entityAttr.getName().equals(PVPConstants.ENTITY_CATEGORY_ATTRIBITE)) {
+ if (!entityAttr.getAttributeValues().isEmpty()) {
+ String entityAttrValue = entityAttr.getAttributeValues().get(0).getDOM().getTextContent();
+ if (PVPConstants.EGOVTOKEN.equals(entityAttrValue)) {
+ log.debug("Find 'EGOVTOKEN' EntityAttribute. Adding single pvp attributes ... ");
+ addAttributesToEntityDescriptor(metadata,
+ buildAttributeList(PVPConstants.EGOVTOKEN_PVP_ATTRIBUTES),
+ entityAttrValue);
+
+
+ } else if (PVPConstants.CITIZENTOKEN.equals(entityAttrValue)) {
+ log.debug("Find 'CITIZENTOKEN' EntityAttribute. Adding single pvp attributes ... ");
+ addAttributesToEntityDescriptor(metadata,
+ buildAttributeList(PVPConstants.CITIZENTOKEN_PVP_ATTRIBUTES),
+ entityAttrValue);
+
+ } else
+ log.info("EntityAttributeValue: " + entityAttrValue + " is UNKNOWN!");
+
+ } else
+ log.info("EntityAttribute: No attribute value");
+
+ } else
+ log.info("EntityAttribute: " + entityAttr.getName() + " is NOT supported");
+
+ }
+
+ } else
+ log.info("Can NOT resolve EntityAttributes! Reason: Only EntityAttributes are supported!");
+
+ }
+ }
+
+ } else
+ log.trace("'Extension' element is 'null' or empty");
+
+ } else
+ log.trace("No 'Extension' element found");
+
+ }
+
+ /**
+ * @param metadata
+ * @param attrList
+ */
+ private void addAttributesToEntityDescriptor(EntityDescriptor metadata, List<RequestedAttribute> attrList, String entityAttr) {
+ SPSSODescriptor spSSODesc = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS);
+ if (spSSODesc != null) {
+ if (spSSODesc.getAttributeConsumingServices() == null ||
+ spSSODesc.getAttributeConsumingServices().isEmpty()) {
+ log.trace("No 'AttributeConsumingServices' found. Added it ...");
+
+ AttributeConsumingService attributeService = SAML2Utils.createSAMLObject(AttributeConsumingService.class);
+ attributeService.setIndex(0);
+ attributeService.setIsDefault(true);
+ ServiceName serviceName = SAML2Utils.createSAMLObject(ServiceName.class);
+ serviceName.setName(new LocalizedString("Default Service", "en"));
+ attributeService.getNames().add(serviceName);
+
+ if (attrList != null && !attrList.isEmpty()) {
+ attributeService.getRequestAttributes().addAll(attrList);
+ log.info("Add " + attrList.size() + " attributes for 'EntityAttribute': " + entityAttr);
+
+ }
+
+ spSSODesc.getAttributeConsumingServices().add(attributeService);
+
+ } else {
+ log.debug("Find 'AttributeConsumingServices'. Starting updating process ... ");
+ for (AttributeConsumingService el : spSSODesc.getAttributeConsumingServices()) {
+ log.debug("Update 'AttributeConsumingService' with Index: " + el.getIndex());
+
+ //load currently requested attributes
+ List<String> currentlyReqAttr = new ArrayList<String>();
+ for (RequestedAttribute reqAttr : el.getRequestAttributes())
+ currentlyReqAttr.add(reqAttr.getName());
+
+
+ //check against EntityAttribute List
+ for (RequestedAttribute entityAttrListEl : attrList) {
+ if (!currentlyReqAttr.contains(entityAttrListEl.getName())) {
+ el.getRequestAttributes().add(entityAttrListEl);
+
+ } else
+ log.debug("'AttributeConsumingService' already contains attr: " + entityAttrListEl.getName());
+
+ }
+
+ }
+
+ }
+
+ } else
+ log.info("Can ONLY add 'EntityAttributes' to 'SPSSODescriptor'");
+
+ }
+
+ private List<RequestedAttribute> buildAttributeList(List<Trible<String, String, Boolean>> attrSet) {
+ List<RequestedAttribute> requestedAttributes = new ArrayList<RequestedAttribute>();
+ for (Trible<String, String, Boolean> el : attrSet)
+ requestedAttributes.add(PVPAttributeBuilder.buildReqAttribute(el.getFirst(), el.getSecond(), el.getThird()));
+
+ return requestedAttributes;
+
+
+ }
+
+}
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
new file mode 100644
index 00000000..a7dddd32
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SchemaValidationFilter.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata;
+
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.Validator;
+
+import org.opensaml.common.xml.SAMLSchemaBuilder;
+import org.opensaml.saml2.metadata.provider.FilterException;
+import org.opensaml.saml2.metadata.provider.MetadataFilter;
+import org.opensaml.xml.XMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
+
+/**
+ * @author tlenz
+ *
+ */
+public class SchemaValidationFilter implements MetadataFilter {
+ private static final Logger log = LoggerFactory.getLogger(SchemaValidationFilter.class);
+ private boolean isActive = true;
+
+ public SchemaValidationFilter() {
+ }
+
+ /**
+ *
+ */
+ public SchemaValidationFilter(boolean useSchemaValidation) {
+ this.isActive = useSchemaValidation;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml.XMLObject)
+ */
+ @Override
+ public void doFilter(XMLObject arg0) throws FilterException {
+
+ String errString = null;
+
+ if (isActive) {
+ try {
+ Schema test = SAMLSchemaBuilder.getSAML11Schema();
+ Validator val = test.newValidator();
+ DOMSource source = new DOMSource(arg0.getDOM());
+ val.validate(source);
+ log.info("Metadata Schema validation check done OK");
+ return;
+
+ } catch (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 (Exception 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();
+
+ }
+
+ throw new FilterException(
+ new SchemaValidationException("Metadata Schema validation FAILED with message: "+ errString, null));
+
+ } 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/verification/AbstractRequestSignedSecurityPolicyRule.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java
new file mode 100644
index 00000000..32615d64
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.Validator;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.common.SignableSAMLObject;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.common.xml.SAMLSchemaBuilder;
+import org.opensaml.security.MetadataCriteria;
+import org.opensaml.security.SAMLSignatureProfileValidator;
+import org.opensaml.ws.message.MessageContext;
+import org.opensaml.ws.security.SecurityPolicyException;
+import org.opensaml.ws.security.SecurityPolicyRule;
+import org.opensaml.xml.XMLObject;
+import org.opensaml.xml.security.CriteriaSet;
+import org.opensaml.xml.security.credential.UsageType;
+import org.opensaml.xml.security.criteria.EntityIDCriteria;
+import org.opensaml.xml.security.criteria.UsageCriteria;
+import org.opensaml.xml.signature.SignatureTrustEngine;
+import org.opensaml.xml.validation.ValidationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
+
+/**
+ * @author tlenz
+ *
+ */
+public abstract class AbstractRequestSignedSecurityPolicyRule implements SecurityPolicyRule {
+
+ private static final Logger log = LoggerFactory.getLogger(AbstractRequestSignedSecurityPolicyRule.class);
+
+
+ private SignatureTrustEngine trustEngine = null;
+ private QName peerEntityRole = null;
+ /**
+ * @param peerEntityRole
+ *
+ */
+ public AbstractRequestSignedSecurityPolicyRule(SignatureTrustEngine trustEngine, QName peerEntityRole) {
+ this.trustEngine = trustEngine;
+ this.peerEntityRole = peerEntityRole;
+
+ }
+
+
+ /**
+ * Reload the PVP metadata for a given entity
+ *
+ * @param entityID for which the metadata should be refreshed.
+ * @return true if the refresh was successful, otherwise false
+ */
+ protected abstract boolean refreshMetadataProvider(String entityID);
+
+
+ protected abstract SignableSAMLObject getSignedSAMLObject(XMLObject inboundData);
+
+ /* (non-Javadoc)
+ * @see org.opensaml.ws.security.SecurityPolicyRule#evaluate(org.opensaml.ws.message.MessageContext)
+ */
+ @Override
+ public void evaluate(MessageContext context) throws SecurityPolicyException {
+ try {
+ verifySignature(context);
+
+ } catch (SecurityPolicyException e) {
+ if (StringUtils.isEmpty(context.getInboundMessageIssuer())) {
+ throw e;
+
+ }
+ log.debug("PVP2X message validation FAILED. Reload metadata for entityID: " + context.getInboundMessageIssuer());
+ if (!refreshMetadataProvider(context.getInboundMessageIssuer()))
+ throw e;
+
+ else {
+ log.trace("PVP2X metadata reload finished. Check validate message again.");
+ verifySignature(context);
+
+ }
+ log.trace("Second PVP2X message validation finished");
+
+ }
+
+
+ }
+
+ private void verifySignature(MessageContext context) throws SecurityPolicyException {
+ SignableSAMLObject samlObj = getSignedSAMLObject(context.getInboundMessage());
+ if (samlObj != null && samlObj.getSignature() != null) {
+
+ SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
+ try {
+ profileValidator.validate(samlObj.getSignature());
+ performSchemaValidation(samlObj.getDOM());
+
+ } catch (ValidationException e) {
+ log.warn("Signature is not conform to SAML signature profile", e);
+ throw new SecurityPolicyException("Signature is not conform to SAML signature profile");
+
+ } catch (SchemaValidationException e) {
+ log.warn("Signature is not conform to SAML signature profile", e);
+ throw new SecurityPolicyException("Signature is not conform to SAML signature profile");
+
+ }
+
+
+
+ CriteriaSet criteriaSet = new CriteriaSet();
+ criteriaSet.add( new EntityIDCriteria(context.getInboundMessageIssuer()) );
+ criteriaSet.add( new MetadataCriteria(peerEntityRole, SAMLConstants.SAML20P_NS) );
+ criteriaSet.add( new UsageCriteria(UsageType.SIGNING) );
+
+ try {
+ if (!trustEngine.validate(samlObj.getSignature(), criteriaSet)) {
+ throw new SecurityPolicyException("Signature validation FAILED.");
+
+ }
+ log.debug("PVP message signature valid.");
+
+ } catch (org.opensaml.xml.security.SecurityException e) {
+ log.info("PVP2x message signature validation FAILED. Message:" + e.getMessage());
+ throw new SecurityPolicyException("Signature validation FAILED.");
+
+ }
+
+ } else {
+ throw new SecurityPolicyException("PVP Message is not signed.");
+
+ }
+
+ }
+
+ private void performSchemaValidation(Element source) throws SchemaValidationException {
+
+ String err = null;
+ try {
+ Schema test = SAMLSchemaBuilder.getSAML11Schema();
+ Validator val = test.newValidator();
+ val.validate(new DOMSource(source));
+ log.debug("Schema validation check done OK");
+ return;
+
+ } catch (SAXException e) {
+ err = e.getMessage();
+ if (log.isDebugEnabled() || log.isTraceEnabled())
+ log.warn("Schema validation FAILED with exception:", e);
+ else
+ log.warn("Schema validation FAILED with message: "+ e.getMessage());
+
+ } catch (Exception e) {
+ err = e.getMessage();
+ if (log.isDebugEnabled() || log.isTraceEnabled())
+ log.warn("Schema validation FAILED with exception:", e);
+ else
+ log.warn("Schema validation FAILED with message: "+ e.getMessage());
+
+ }
+
+ throw new SchemaValidationException("pvp2.22", new Object[]{err});
+
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AuthnRequestValidator.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AuthnRequestValidator.java
new file mode 100644
index 00000000..86c7f309
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AuthnRequestValidator.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+
+import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.saml2.core.NameIDPolicy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.NameIDFormatNotSupportedException;
+
+
+/**
+ * @author tlenz
+ *
+ */
+public class AuthnRequestValidator {
+ private static final Logger log = LoggerFactory.getLogger(AuthnRequestValidator.class);
+
+ public static void validate(AuthnRequest req) throws AuthnRequestValidatorException{
+
+ //validate NameIDPolicy
+ NameIDPolicy nameIDPolicy = req.getNameIDPolicy();
+ if (nameIDPolicy != null) {
+ String nameIDFormat = nameIDPolicy.getFormat();
+ if (nameIDFormat != null) {
+ if ( !(NameID.TRANSIENT.equals(nameIDFormat) ||
+ NameID.PERSISTENT.equals(nameIDFormat) ||
+ NameID.UNSPECIFIED.equals(nameIDFormat)) ) {
+
+ throw new NameIDFormatNotSupportedException(nameIDFormat);
+
+ }
+
+ } else
+ log.trace("Find NameIDPolicy, but NameIDFormat is 'null'");
+ } else
+ log.trace("AuthnRequest includes no 'NameIDPolicy'");
+
+
+
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPAuthRequestSignedRole.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPAuthRequestSignedRole.java
new file mode 100644
index 00000000..458d28c2
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPAuthRequestSignedRole.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+
+import org.opensaml.common.binding.SAMLMessageContext;
+import org.opensaml.saml2.binding.security.SAML2AuthnRequestsSignedRule;
+import org.opensaml.ws.transport.http.HTTPInTransport;
+import org.opensaml.xml.util.DatatypeHelper;
+
+/**
+ * @author tlenz
+ *
+ */
+public class PVPAuthRequestSignedRole extends SAML2AuthnRequestsSignedRule {
+
+ @Override
+ protected boolean isMessageSigned(SAMLMessageContext messageContext) {
+ // This handles HTTP-Redirect and HTTP-POST-SimpleSign bindings.
+ HTTPInTransport inTransport = (HTTPInTransport) messageContext.getInboundMessageTransport();
+ String sigParam = inTransport.getParameterValue("Signature");
+ boolean isSigned = !DatatypeHelper.isEmpty(sigParam);
+
+ String sigAlgParam = inTransport.getParameterValue("SigAlg");
+ boolean isSigAlgExists = !DatatypeHelper.isEmpty(sigAlgParam);
+
+ return isSigned && isSigAlgExists;
+
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPSignedRequestPolicyRule.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPSignedRequestPolicyRule.java
new file mode 100644
index 00000000..af6c864e
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPSignedRequestPolicyRule.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+
+import javax.xml.namespace.QName;
+
+import org.opensaml.common.SignableSAMLObject;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.xml.XMLObject;
+import org.opensaml.xml.signature.SignatureTrustEngine;
+
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+
+/**
+ * @author tlenz
+ *
+ */
+public class PVPSignedRequestPolicyRule extends
+ AbstractRequestSignedSecurityPolicyRule {
+
+ private IRefreshableMetadataProvider metadataProvider = null;
+
+ /**
+ * @param metadataProvider
+ * @param trustEngine
+ * @param peerEntityRole
+ */
+ public PVPSignedRequestPolicyRule(MetadataProvider metadataProvider, SignatureTrustEngine trustEngine,
+ QName peerEntityRole) {
+ super(trustEngine, peerEntityRole);
+ if (metadataProvider instanceof IRefreshableMetadataProvider)
+ this.metadataProvider = (IRefreshableMetadataProvider) metadataProvider;
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.validation.AbstractRequestSignedSecurityPolicyRule#refreshMetadataProvider(java.lang.String)
+ */
+ @Override
+ protected boolean refreshMetadataProvider(String entityID) {
+ if (metadataProvider != null)
+ return metadataProvider.refreshMetadataProvider(entityID);
+
+ return false;
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.pvp2x.validation.AbstractRequestSignedSecurityPolicyRule#getSignedSAMLObject(org.opensaml.xml.XMLObject)
+ */
+ @Override
+ protected SignableSAMLObject getSignedSAMLObject(XMLObject inboundData) {
+ if (inboundData instanceof SignableSAMLObject)
+ return (SignableSAMLObject) inboundData;
+
+ else
+ return null;
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java
new file mode 100644
index 00000000..fe147ea7
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.Validator;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.common.xml.SAMLSchemaBuilder;
+import org.opensaml.saml2.core.RequestAbstractType;
+import org.opensaml.saml2.core.StatusResponseType;
+import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.security.MetadataCriteria;
+import org.opensaml.security.SAMLSignatureProfileValidator;
+import org.opensaml.xml.security.CriteriaSet;
+import org.opensaml.xml.security.credential.UsageType;
+import org.opensaml.xml.security.criteria.EntityIDCriteria;
+import org.opensaml.xml.security.criteria.UsageCriteria;
+import org.opensaml.xml.signature.SignatureTrustEngine;
+import org.opensaml.xml.validation.ValidationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileRequest;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileResponse;
+
+@Service("SAMLVerificationEngine")
+public class SAMLVerificationEngine {
+ private static final Logger log = LoggerFactory.getLogger(SAMLVerificationEngine.class);
+
+
+ @Autowired(required=true) IPVPMetadataProvider metadataProvider;
+
+ public void verify(InboundMessage msg, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception {
+ try {
+ if (msg instanceof PVPSProfileRequest &&
+ ((PVPSProfileRequest)msg).getSamlRequest() instanceof RequestAbstractType)
+ verifyRequest(((RequestAbstractType)((PVPSProfileRequest)msg).getSamlRequest()), sigTrustEngine);
+
+ else
+ verifyIDPResponse(((PVPSProfileResponse)msg).getResponse(), sigTrustEngine);
+
+ } catch (InvalidProtocolRequestException e) {
+ if (StringUtils.isEmpty(msg.getEntityID())) {
+ throw e;
+
+ }
+ log.debug("PVP2X message validation FAILED. Relead metadata for entityID: " + msg.getEntityID());
+
+ if (metadataProvider == null ||
+ !(metadataProvider instanceof IRefreshableMetadataProvider) ||
+ !((IRefreshableMetadataProvider)metadataProvider).refreshMetadataProvider(msg.getEntityID()))
+ throw e;
+
+ else {
+ log.trace("PVP2X metadata reload finished. Check validate message again.");
+
+ if (msg instanceof PVPSProfileRequest &&
+ ((PVPSProfileRequest)msg).getSamlRequest() instanceof RequestAbstractType)
+ verifyRequest(((RequestAbstractType)((PVPSProfileRequest)msg).getSamlRequest()), sigTrustEngine);
+
+ else
+ verifyIDPResponse(((PVPSProfileResponse)msg).getResponse(), sigTrustEngine);
+
+ }
+ log.trace("Second PVP2X message validation finished");
+ }
+ }
+
+ public void verifySLOResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine ) throws InvalidProtocolRequestException {
+ verifyResponse(samlObj, sigTrustEngine, SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+ }
+
+ public void verifyIDPResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine) throws InvalidProtocolRequestException{
+ verifyResponse(samlObj, sigTrustEngine, IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+ }
+
+ private void verifyResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine, QName defaultElementName) throws InvalidProtocolRequestException{
+ SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
+ try {
+ profileValidator.validate(samlObj.getSignature());
+ performSchemaValidation(samlObj.getDOM());
+
+ } catch (ValidationException e) {
+ log.warn("Signature is not conform to SAML signature profile", e);
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature is not conform to SAML signature profile");
+
+ } catch (SchemaValidationException e) {
+ throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}, "SAML response does not fit XML scheme");
+
+ }
+
+ CriteriaSet criteriaSet = new CriteriaSet();
+ criteriaSet.add( new EntityIDCriteria(samlObj.getIssuer().getValue()) );
+ criteriaSet.add( new MetadataCriteria(defaultElementName, SAMLConstants.SAML20P_NS) );
+ criteriaSet.add( new UsageCriteria(UsageType.SIGNING) );
+
+ try {
+ if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) {
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature verification FAILED on SAML response");
+ }
+ } catch (org.opensaml.xml.security.SecurityException e) {
+ log.warn("PVP2x message signature validation FAILED.", e);
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature verification FAILED on SAML response");
+ }
+ }
+
+ private void verifyRequest(RequestAbstractType samlObj, SignatureTrustEngine sigTrustEngine ) throws InvalidProtocolRequestException {
+ SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
+ try {
+ profileValidator.validate(samlObj.getSignature());
+ performSchemaValidation(samlObj.getDOM());
+
+ } catch (ValidationException e) {
+ log.warn("Signature is not conform to SAML signature profile", e);
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Scheme validation FAILED on SAML request");
+
+ } catch (SchemaValidationException e) {
+ throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}, "Scheme verification FAILED on SAML request");
+
+ }
+
+ CriteriaSet criteriaSet = new CriteriaSet();
+ criteriaSet.add( new EntityIDCriteria(samlObj.getIssuer().getValue()) );
+ criteriaSet.add( new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) );
+ criteriaSet.add( new UsageCriteria(UsageType.SIGNING) );
+
+ try {
+ if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) {
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature verification FAILED on SAML request");
+ }
+ } catch (org.opensaml.xml.security.SecurityException e) {
+ log.warn("PVP2x message signature validation FAILED.", e);
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature verification FAILED on SAML request");
+ }
+ }
+
+ protected void performSchemaValidation(Element source) throws SchemaValidationException {
+
+ String err = null;
+ try {
+ Schema test = SAMLSchemaBuilder.getSAML11Schema();
+ Validator val = test.newValidator();
+ val.validate(new DOMSource(source));
+ log.debug("Schema validation check done OK");
+ return;
+
+ } catch (SAXException e) {
+ err = e.getMessage();
+ if (log.isDebugEnabled() || log.isTraceEnabled())
+ log.warn("Schema validation FAILED with exception:", e);
+ else
+ log.warn("Schema validation FAILED with message: "+ e.getMessage());
+
+ } catch (Exception e) {
+ err = e.getMessage();
+ if (log.isDebugEnabled() || log.isTraceEnabled())
+ log.warn("Schema validation FAILED with exception:", e);
+ else
+ log.warn("Schema validation FAILED with message: "+ e.getMessage());
+
+ }
+
+ throw new SchemaValidationException("pvp2.22", new Object[]{err});
+
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider
new file mode 100644
index 00000000..9c60d724
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider
@@ -0,0 +1 @@
+at.gv.egiz.eaaf.modules.pvp2.PVP2SProfileCoreSpringResourceProvider \ No newline at end of file
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml
new file mode 100644
index 00000000..2c64b5f1
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
+
+ <bean id="PVPMetadataBuilder"
+ class="at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPMetadataBuilder" />
+
+ <bean id="PVPPOSTBinding"
+ class="at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding" />
+
+ <bean id="PVPRedirectBinding"
+ class="at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding" />
+
+ <bean id="PVPSOAPBinding"
+ class="at.gv.egiz.eaaf.modules.pvp2.impl.binding.SoapBinding" />
+
+ <bean id="SAMLVerificationEngine"
+ class="at.gv.egiz.eaaf.modules.pvp2.impl.verification.SAMLVerificationEngine" />
+
+</beans> \ No newline at end of file