summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_pvp2_idp
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_idp
downloadEAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.tar.gz
EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.tar.bz2
EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.zip
initial commit
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_idp')
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/pom.xml71
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/META-INF/MANIFEST.MF3
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java30
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java21
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java30
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java18
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java21
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java26
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java26
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java22
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java19
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java537
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java154
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java99
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PVPSProfilePendingRequest.java103
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java129
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java448
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider1
-rw-r--r--eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml19
19 files changed, 1777 insertions, 0 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/pom.xml b/eaaf_modules/eaaf_module_pvp2_idp/pom.xml
new file mode 100644
index 00000000..90b38119
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/pom.xml
@@ -0,0 +1,71 @@
+<?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_idp</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_module_pvp2_core</artifactId>
+ <version>${egiz.eaaf.version}</version>
+ </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_idp</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_idp/src/main/java/META-INF/MANIFEST.MF b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..254272e1
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java
new file mode 100644
index 00000000..7a9ac92b
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+import at.gv.egiz.components.spring.api.SpringResourceProvider;
+
+public class PVP2SProfileIDPSpringResourceProvider implements SpringResourceProvider {
+
+ @Override
+ public String getName() {
+ return "EAAF PVP2 S-Profile IDP SpringResourceProvider";
+ }
+
+ @Override
+ public String[] getPackagesToScan() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Resource[] getResourcesToLoad() {
+ ClassPathResource sl20AuthConfig = new ClassPathResource("/eaaf_pvp_idp.beans.xml", PVP2SProfileIDPSpringResourceProvider.class);
+
+ return new Resource[] {sl20AuthConfig};
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java
new file mode 100644
index 00000000..ac999ffc
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.api.builder;
+
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+public interface ISubjectNameIdGenerator {
+
+ /**
+ * Generates a SAML2 subjectNameId from authentication data
+ *
+ * @param authData Authentication data for the current pending request
+ * @param spConfig Service provider configuration
+ * @return Pair of subjectNameId and NameIdFormat
+ * @throws PVP2Exception
+ */
+ public Pair<String, String> generateSubjectNameId(IAuthData authData, ISPConfiguration spConfig) throws PVP2Exception;
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java
new file mode 100644
index 00000000..d9ffa2f2
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+public class InvalidAssertionConsumerServiceException extends PVP2Exception {
+
+ public InvalidAssertionConsumerServiceException(int idx) {
+ super("pvp2.00", new Object[]{idx});
+ this.statusCodeValue = StatusCode.REQUESTER_URI;
+ }
+
+ /**
+ *
+ */
+ public InvalidAssertionConsumerServiceException(String wrongURL) {
+ super("pvp2.23", new Object[]{wrongURL});
+ this.statusCodeValue = StatusCode.REQUESTER_URI;
+
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7861790149343943091L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java
new file mode 100644
index 00000000..d0b6feb9
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+public class InvalidAssertionEncryptionException extends PVP2Exception {
+
+ private static final long serialVersionUID = 6513388841485355549L;
+
+ public InvalidAssertionEncryptionException() {
+ super("pvp2.16", new Object[]{});
+ this.statusCodeValue = StatusCode.RESPONDER_URI;
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java
new file mode 100644
index 00000000..5abd6dbe
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+public class RequestDeniedException extends PVP2Exception {
+
+ public RequestDeniedException() {
+ super("pvp2.14", null);
+ this.statusCodeValue = StatusCode.REQUEST_DENIED_URI;
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4415896615794730553L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java
new file mode 100644
index 00000000..f7145458
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+public class ResponderErrorException extends PVP2Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -425416760138285446L;
+
+ public ResponderErrorException(String messageId, Object[] parameters,
+ Throwable wrapped) {
+ super(messageId, parameters, wrapped);
+ this.statusCodeValue = StatusCode.RESPONDER_URI;
+ }
+
+ public ResponderErrorException(String messageId, Object[] parameters) {
+ super(messageId, parameters);
+ this.statusCodeValue = StatusCode.RESPONDER_URI;
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java
new file mode 100644
index 00000000..364fdbf0
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+public class SAMLRequestNotSignedException extends PVP2Exception {
+
+ public SAMLRequestNotSignedException() {
+ super("pvp2.07", null);
+ this.statusCodeValue = StatusCode.REQUESTER_URI;
+ }
+
+ public SAMLRequestNotSignedException(Throwable e) {
+ super("pvp2.07", null, e);
+ this.statusCodeValue = StatusCode.REQUESTER_URI;
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java
new file mode 100644
index 00000000..b370a7be
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+
+public class SAMLRequestNotSupported extends PVP2Exception {
+
+ public SAMLRequestNotSupported() {
+ super("pvp2.09", null);
+ this.statusCodeValue = StatusCode.REQUEST_UNSUPPORTED_URI;
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1244883178458802767L;
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java
new file mode 100644
index 00000000..5dea922c
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.exception;
+
+import org.opensaml.saml2.core.StatusCode;
+
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+
+public class UnprovideableAttributeException extends PVP2Exception {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3972197758163647157L;
+
+ public UnprovideableAttributeException(String attributeName) {
+ super("pvp2.10", new Object[] {attributeName});
+ this.statusCodeValue = StatusCode.UNKNOWN_ATTR_PROFILE_URI;
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java
new file mode 100644
index 00000000..93ffa789
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java
@@ -0,0 +1,537 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.impl;
+
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.core.Status;
+import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.core.StatusMessage;
+import org.opensaml.saml2.core.impl.AuthnRequestImpl;
+import org.opensaml.saml2.metadata.AssertionConsumerService;
+import org.opensaml.saml2.metadata.AttributeConsumingService;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.ws.security.SecurityPolicyException;
+import org.opensaml.xml.security.x509.X509Credential;
+import org.opensaml.xml.signature.SignableXMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import at.gv.egiz.components.eventlog.api.EventConstants;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.IModulInfo;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger;
+import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException;
+import at.gv.egiz.eaaf.core.exceptions.NoPassivAuthenticationException;
+import at.gv.egiz.eaaf.core.exceptions.SLOException;
+import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractAuthProtocolModulController;
+import at.gv.egiz.eaaf.modules.pvp2.PVPEventConstants;
+import at.gv.egiz.eaaf.modules.pvp2.api.IPVP2BasicConfiguration;
+import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPVPRequestException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.NameIDFormatNotSupportedException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionConsumerServiceException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding;
+import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding;
+import at.gv.egiz.eaaf.modules.pvp2.impl.binding.SoapBinding;
+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.utils.AbstractCredentialProvider;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EAAFURICompare;
+import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.AuthnRequestValidator;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SAMLVerificationEngine;
+
+public abstract class AbstractPVP2XProtocol extends AbstractAuthProtocolModulController implements IModulInfo {
+ private static final Logger log = LoggerFactory.getLogger(AbstractPVP2XProtocol.class);
+
+ @Autowired(required=true) protected IPVP2BasicConfiguration pvpBasicConfiguration;
+ @Autowired(required=true) protected IPVPMetadataProvider metadataProvider;
+ @Autowired(required=true) protected SAMLVerificationEngine samlVerificationEngine;
+
+ private AbstractCredentialProvider pvpIDPCredentials;
+
+ /**
+ * Sets a specific credential provider for PVP S-Profile IDP component.
+ * @param pvpIDPCredentials credential provider
+ */
+ public void setPvpIDPCredentials(AbstractCredentialProvider pvpIDPCredentials) {
+ this.pvpIDPCredentials = pvpIDPCredentials;
+
+ }
+
+ public boolean generateErrorMessage(Throwable e,
+ HttpServletRequest request, HttpServletResponse response,
+ IRequest protocolRequest) throws Throwable {
+
+ if(protocolRequest == null) {
+ throw e;
+ }
+
+ if(!(protocolRequest instanceof PVPSProfilePendingRequest) ) {
+ throw e;
+ }
+ PVPSProfilePendingRequest pvpRequest = (PVPSProfilePendingRequest)protocolRequest;
+
+ Response samlResponse =
+ SAML2Utils.createSAMLObject(Response.class);
+ Status status = SAML2Utils.createSAMLObject(Status.class);
+ StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class);
+ StatusMessage statusMessage = SAML2Utils.createSAMLObject(StatusMessage.class);
+
+ String moaError = null;
+
+ if(e instanceof NoPassivAuthenticationException) {
+ statusCode.setValue(StatusCode.NO_PASSIVE_URI);
+ statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage()));
+
+ } else if (e instanceof NameIDFormatNotSupportedException) {
+ statusCode.setValue(StatusCode.INVALID_NAMEID_POLICY_URI);
+ statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage()));
+
+ } else if (e instanceof SLOException) {
+ //SLOExecpetions only occurs if session information is lost
+ return false;
+
+ } else if(e instanceof PVP2Exception) {
+ PVP2Exception ex = (PVP2Exception) e;
+ statusCode.setValue(ex.getStatusCodeValue());
+ String statusMessageValue = ex.getStatusMessageValue();
+ if(statusMessageValue != null) {
+ statusMessage.setMessage(StringEscapeUtils.escapeXml(statusMessageValue));
+ }
+ moaError = statusMessager.mapInternalErrorToExternalError(ex.getErrorId());
+
+ } else {
+ statusCode.setValue(StatusCode.RESPONDER_URI);
+ statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage()));
+ moaError = statusMessager.getResponseErrorCode(e);
+ }
+
+
+ if (StringUtils.isNotEmpty(moaError)) {
+ StatusCode moaStatusCode = SAML2Utils.createSAMLObject(StatusCode.class);
+ moaStatusCode.setValue(moaError);
+ statusCode.setStatusCode(moaStatusCode);
+ }
+
+ status.setStatusCode(statusCode);
+ if(statusMessage.getMessage() != null) {
+ status.setStatusMessage(statusMessage);
+ }
+ samlResponse.setStatus(status);
+ String remoteSessionID = SAML2Utils.getSecureIdentifier();
+ samlResponse.setID(remoteSessionID);
+
+ samlResponse.setIssueInstant(new DateTime());
+ Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class);
+ nissuer.setValue(pvpBasicConfiguration.getIDPEntityId(pvpRequest.getAuthURL()));
+ nissuer.setFormat(NameID.ENTITY);
+ samlResponse.setIssuer(nissuer);
+
+ IEncoder encoder = null;
+
+ if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
+ encoder = applicationContext.getBean("PVPRedirectBinding", RedirectBinding.class);
+
+ } else if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) {
+ encoder = applicationContext.getBean("PVPPOSTBinding", PostBinding.class);
+
+ } else if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) {
+ encoder = applicationContext.getBean("PVPSOAPBinding", SoapBinding.class);
+ }
+
+ if(encoder == null) {
+ // default to redirect binding
+ encoder = new RedirectBinding();
+ }
+
+ String relayState = null;
+ if (pvpRequest.getRequest() != null)
+ relayState = pvpRequest.getRequest().getRelayState();
+
+ X509Credential signCred = pvpIDPCredentials.getIDPAssertionSigningCredential();
+
+ encoder.encodeRespone(request, response, samlResponse, pvpRequest.getConsumerURL(),
+ relayState, signCred, protocolRequest);
+ return true;
+ }
+
+ public boolean validate(HttpServletRequest request,
+ HttpServletResponse response, IRequest pending) {
+
+ return true;
+ }
+
+ protected void pvpMetadataRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException {
+ //create pendingRequest object
+ PVPSProfilePendingRequest pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class);
+ pendingReq.initialize(req, authConfig);
+ pendingReq.setModule(getName());
+
+ revisionsLogger.logEvent(
+ pendingReq.getUniqueSessionIdentifier(),
+ pendingReq.getUniqueTransactionIdentifier(),
+ EventConstants.TRANSACTION_IP,
+ req.getRemoteAddr());
+
+ MetadataAction metadataAction = applicationContext.getBean(MetadataAction.class);
+ metadataAction.processRequest(pendingReq,
+ req, resp, null);
+
+ }
+
+ protected void PVPIDPPostRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException {
+ PVPSProfilePendingRequest pendingReq = null;
+
+ try {
+ //create pendingRequest object
+ pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class);
+ pendingReq.initialize(req, authConfig);
+ pendingReq.setModule(getName());
+
+ revisionsLogger.logEvent(EventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier());
+ revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier());
+ revisionsLogger.logEvent(
+ pendingReq.getUniqueSessionIdentifier(),
+ pendingReq.getUniqueTransactionIdentifier(),
+ EventConstants.TRANSACTION_IP,
+ req.getRemoteAddr());
+
+ //get POST-Binding decoder implementation
+ InboundMessage msg = (InboundMessage) new PostBinding().decode(
+ req, resp, metadataProvider, false,
+ new EAAFURICompare(pvpBasicConfiguration.getIDPSSOPostService(pendingReq.getAuthURL())));
+ pendingReq.setRequest(msg);
+
+ //preProcess Message
+ preProcess(req, resp, pendingReq);
+
+ } catch (SecurityPolicyException e) {
+ String samlRequest = req.getParameter("SAMLRequest");
+ log.warn("Receive INVALID protocol request: " + samlRequest, e);
+
+ //write revision log entries
+ if (pendingReq != null)
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier());
+
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, e.getMessage());
+
+ } catch (SecurityException e) {
+ String samlRequest = req.getParameter("SAMLRequest");
+ log.warn("Receive INVALID protocol request: " + samlRequest, e);
+
+ //write revision log entries
+ if (pendingReq != null)
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier());
+
+ throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}, e.getMessage());
+
+ } catch (EAAFException e) {
+
+ //write revision log entries
+ if (pendingReq != null)
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier());
+
+ throw e;
+
+ } catch (Throwable e) {
+ String samlRequest = req.getParameter("SAMLRequest");
+ log.warn("Receive INVALID protocol request: " + samlRequest, e);
+
+ //write revision log entries
+ if (pendingReq != null)
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier());
+
+ throw new EAAFException("pvp2.24", new Object[] {e.getMessage()}, e.getMessage(), e);
+ }
+ }
+
+ protected void PVPIDPRedirecttRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException {
+ PVPSProfilePendingRequest pendingReq = null;
+ try {
+ //create pendingRequest object
+ pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class);
+ pendingReq.initialize(req, authConfig);
+ pendingReq.setModule(getName());
+
+ revisionsLogger.logEvent(EventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier());
+ revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier());
+ revisionsLogger.logEvent(
+ pendingReq.getUniqueSessionIdentifier(),
+ pendingReq.getUniqueTransactionIdentifier(),
+ EventConstants.TRANSACTION_IP,
+ req.getRemoteAddr());
+
+ //get POST-Binding decoder implementation
+ InboundMessage msg = (InboundMessage) new RedirectBinding().decode(
+ req, resp, metadataProvider, false,
+ new EAAFURICompare(pvpBasicConfiguration.getIDPSSORedirectService(pendingReq.getAuthURL())));
+ pendingReq.setRequest(msg);
+
+ //preProcess Message
+ preProcess(req, resp, pendingReq);
+
+ } catch (SecurityPolicyException e) {
+ String samlRequest = req.getParameter("SAMLRequest");
+ log.warn("Receive INVALID protocol request: " + samlRequest, e);
+
+ //write revision log entries
+ if (pendingReq != null)
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier());
+
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, e.getMessage());
+
+ } catch (SecurityException e) {
+ String samlRequest = req.getParameter("SAMLRequest");
+ log.warn("Receive INVALID protocol request: " + samlRequest, e);
+
+ //write revision log entries
+ if (pendingReq != null)
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier());
+
+ throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}, e.getMessage());
+
+ } catch (EAAFException e) {
+ String samlRequest = req.getParameter("SAMLRequest");
+ log.info("Receive INVALID protocol request: " + samlRequest);
+
+ //write revision log entries
+ if (pendingReq != null)
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier());
+
+ throw e;
+
+ } catch (Throwable e) {
+ String samlRequest = req.getParameter("SAMLRequest");
+ log.warn("Receive INVALID protocol request: " + samlRequest, e);
+
+ //write revision log entries
+ if (pendingReq != null)
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier());
+
+ throw new EAAFException("pvp2.24", new Object[] {e.getMessage()}, e.getMessage(), e);
+ }
+ }
+
+
+
+ /**
+ *
+ *
+ * @param request
+ * @param response
+ * @param msg
+ * @return true if preprocess can handle this request type, otherwise false
+ * @throws Throwable
+ */
+ abstract protected boolean childPreProcess(HttpServletRequest request,
+ HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable;
+
+ protected void preProcess(HttpServletRequest request,
+ HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable {
+
+ InboundMessage msg = pendingReq.getRequest();
+
+ if (StringUtils.isEmpty(msg.getEntityID())) {
+ throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}, "EntityId is null or empty");
+
+ }
+
+ if(!msg.isVerified()) {
+ samlVerificationEngine.verify(msg,
+ TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider));
+ msg.setVerified(true);
+
+ }
+
+
+ if (msg instanceof PVPSProfileRequest &&
+ ((PVPSProfileRequest)msg).getSamlRequest() instanceof AuthnRequest)
+ preProcessAuthRequest(request, response, pendingReq);
+
+ else if (childPreProcess(request, response, pendingReq))
+ log.debug("Find protocol handler in child implementation");
+
+ else {
+ log.error("Receive unsupported PVP21 message");
+ throw new InvalidPVPRequestException("Unsupported PVP21 message", new Object[] {});
+ }
+
+ revisionsLogger.logEvent(pendingReq, IRevisionLogger.AUTHPROTOCOL_TYPE, getAuthProtocolIdentifier());
+
+ //switch to session authentication
+ performAuthentication(request, response, pendingReq);
+ }
+
+
+ /**
+ * PreProcess Authn request
+ * @param request
+ * @param response
+ * @param pendingReq
+ * @throws Throwable
+ */
+ private void preProcessAuthRequest(HttpServletRequest request,
+ HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable {
+
+ PVPSProfileRequest moaRequest = ((PVPSProfileRequest)pendingReq.getRequest());
+ SignableXMLObject samlReq = moaRequest.getSamlRequest();
+
+ if(!(samlReq instanceof AuthnRequest)) {
+ throw new InvalidPVPRequestException("Unsupported request", new Object[] {});
+ }
+
+ EntityDescriptor metadata = moaRequest.getEntityMetadata(metadataProvider);
+ if(metadata == null) {
+ throw new NoMetadataInformationException();
+ }
+ SPSSODescriptor spSSODescriptor = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS);
+
+ AuthnRequest authnRequest = (AuthnRequest)samlReq;
+
+ if (authnRequest.getIssueInstant() == null) {
+ log.warn("Unsupported request: No IssueInstant Attribute found.");
+ throw new AuthnRequestValidatorException("Unsupported request: No IssueInstant Attribute found.", new Object[] {},
+ "Unsupported request: No IssueInstant Attribute found", pendingReq);
+
+ }
+
+ if (authnRequest.getIssueInstant().minusMinutes(EAAFConstants.ALLOWED_TIME_JITTER).isAfterNow()) {
+ log.warn("Unsupported request: No IssueInstant DateTime is not valid anymore.");
+ throw new AuthnRequestValidatorException("Unsupported request: No IssueInstant DateTime is not valid anymore.", new Object[] {},
+ "Unsupported request: No IssueInstant DateTime is not valid anymore.", pendingReq);
+
+ }
+
+ //parse AssertionConsumerService
+ AssertionConsumerService consumerService = null;
+ if (StringUtils.isNotEmpty(authnRequest.getAssertionConsumerServiceURL()) &&
+ StringUtils.isNotEmpty(authnRequest.getProtocolBinding())) {
+ //use AssertionConsumerServiceURL from request
+
+ //check requested AssertionConsumingService URL against metadata
+ List<AssertionConsumerService> metadataAssertionServiceList = spSSODescriptor.getAssertionConsumerServices();
+ for (AssertionConsumerService service : metadataAssertionServiceList) {
+ if (authnRequest.getProtocolBinding().equals(service.getBinding())
+ && authnRequest.getAssertionConsumerServiceURL().equals(service.getLocation())) {
+ consumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class);
+ consumerService.setBinding(authnRequest.getProtocolBinding());
+ consumerService.setLocation(authnRequest.getAssertionConsumerServiceURL());
+ log.debug("Requested AssertionConsumerServiceURL is valid.");
+ }
+ }
+
+ if (consumerService == null) {
+ throw new InvalidAssertionConsumerServiceException(authnRequest.getAssertionConsumerServiceURL());
+
+ }
+
+
+ } else {
+ //use AssertionConsumerServiceIndex and select consumerService from metadata
+ Integer aIdx = authnRequest.getAssertionConsumerServiceIndex();
+ int assertionidx = 0;
+
+ if(aIdx != null) {
+ assertionidx = aIdx.intValue();
+
+ } else {
+ assertionidx = SAML2Utils.getDefaultAssertionConsumerServiceIndex(spSSODescriptor);
+
+ }
+ consumerService = spSSODescriptor.getAssertionConsumerServices().get(assertionidx);
+
+ if (consumerService == null) {
+ throw new InvalidAssertionConsumerServiceException(aIdx);
+
+ }
+ }
+
+
+ //select AttributeConsumingService from request
+ AttributeConsumingService attributeConsumer = null;
+ Integer aIdx = authnRequest.getAttributeConsumingServiceIndex();
+ int attributeIdx = 0;
+
+ if(aIdx != null) {
+ attributeIdx = aIdx.intValue();
+ }
+
+ if (spSSODescriptor.getAttributeConsumingServices() != null &&
+ spSSODescriptor.getAttributeConsumingServices().size() > 0) {
+ attributeConsumer = spSSODescriptor.getAttributeConsumingServices().get(attributeIdx);
+ }
+
+ //validate AuthnRequest
+ AuthnRequestImpl authReq = (AuthnRequestImpl) samlReq;
+ AuthnRequestValidator.validate(authReq);
+
+// String useMandate = request.getParameter(PARAM_USEMANDATE);
+// if(useMandate != null) {
+// if(useMandate.equals("true") && attributeConsumer != null) {
+// if(!CheckMandateAttributes.canHandleMandate(attributeConsumer)) {
+// throw new MandateAttributesNotHandleAbleException();
+// }
+// }
+// }
+
+ String oaURL = moaRequest.getEntityMetadata(metadataProvider).getEntityID();
+ oaURL = StringEscapeUtils.escapeHtml(oaURL);
+ ISPConfiguration oa = authConfig.getServiceProviderConfiguration(oaURL);
+
+ log.info("Dispatch PVP2 AuthnRequest: OAURL=" + oaURL + " Binding=" + consumerService.getBinding());
+
+ pendingReq.setSPEntityId(oaURL);
+ pendingReq.setOnlineApplicationConfiguration(oa);
+ pendingReq.setBinding(consumerService.getBinding());
+ pendingReq.setRequest(moaRequest);
+ pendingReq.setConsumerURL(consumerService.getLocation());
+
+ //parse AuthRequest
+ pendingReq.setPassiv(authReq.isPassive());
+ pendingReq.setForce(authReq.isForceAuthn());
+
+ //AuthnRequest needs authentication
+ pendingReq.setNeedAuthentication(true);
+
+ //set protocol action, which should be executed after authentication
+ pendingReq.setAction(AuthenticationAction.class.getName());
+
+ //write revisionslog entry
+ revisionsLogger.logEvent(pendingReq, PVPEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST);
+
+ }
+
+ @PostConstruct
+ private void verifyInitialization() {
+ if (pvpIDPCredentials == null) {
+ log.error("No SAML2 credentialProvider injected!");
+ throw new RuntimeException("No SAML2 credentialProvider injected!");
+
+ }
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java
new file mode 100644
index 00000000..adcff465
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.impl;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.joda.time.DateTime;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.core.Assertion;
+import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.metadata.AssertionConsumerService;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.opensaml.xml.security.SecurityException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.IAction;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.impl.data.SLOInformationImpl;
+import at.gv.egiz.eaaf.modules.pvp2.api.IPVP2BasicConfiguration;
+import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.BindingNotSupportedException;
+import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException;
+import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.AuthResponseBuilder;
+import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.PVP2AssertionBuilder;
+import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding;
+import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileRequest;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+
+@Service("PVPAuthenticationRequestAction")
+public class AuthenticationAction implements IAction {
+ private static final Logger log = LoggerFactory.getLogger(AuthenticationAction.class);
+
+ private static final String CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION = "protocols.pvp2.assertion.encryption.active";
+
+ @Autowired(required=true) private IPVPMetadataProvider metadataProvider;
+ @Autowired(required=true) ApplicationContext springContext;
+ @Autowired(required=true) IConfiguration authConfig;
+ @Autowired(required=true) PVP2AssertionBuilder assertionBuilder;
+ @Autowired(required=true) IPVP2BasicConfiguration pvpBasicConfiguration;
+
+ private AbstractCredentialProvider pvpIDPCredentials;
+
+ /**
+ * Sets a specific credential provider for PVP S-Profile IDP component.
+ * @param pvpIDPCredentials credential provider
+ */
+ public void setPvpIDPCredentials(AbstractCredentialProvider pvpIDPCredentials) {
+ this.pvpIDPCredentials = pvpIDPCredentials;
+
+ }
+
+ public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq,
+ HttpServletResponse httpResp, IAuthData authData) throws ResponderErrorException {
+ PVPSProfilePendingRequest pvpRequest = (PVPSProfilePendingRequest) req;
+ try {
+ //get basic information
+ PVPSProfileRequest moaRequest = (PVPSProfileRequest) pvpRequest.getRequest();
+ AuthnRequest authnRequest = (AuthnRequest) moaRequest.getSamlRequest();
+ EntityDescriptor peerEntity = moaRequest.getEntityMetadata(metadataProvider);
+
+ AssertionConsumerService consumerService =
+ SAML2Utils.createSAMLObject(AssertionConsumerService.class);
+ consumerService.setBinding(pvpRequest.getBinding());
+ consumerService.setLocation(pvpRequest.getConsumerURL());
+
+ DateTime date = new DateTime();
+ SLOInformationImpl sloInformation = new SLOInformationImpl();
+ String issuerEntityID = pvpBasicConfiguration.getIDPEntityId(pvpRequest.getAuthURL());
+
+ //build Assertion
+ Assertion assertion = assertionBuilder.buildAssertion(issuerEntityID, pvpRequest, authnRequest, authData,
+ peerEntity, date, consumerService, sloInformation);
+
+ Response authResponse = AuthResponseBuilder.buildResponse(
+ metadataProvider, issuerEntityID, authnRequest,
+ date, assertion, authConfig.getBasicMOAIDConfigurationBoolean(
+ CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION, true));
+
+ IEncoder binding = null;
+
+ if (consumerService.getBinding().equals(
+ SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
+ binding = springContext.getBean("PVPRedirectBinding", RedirectBinding.class);
+
+ } else if (consumerService.getBinding().equals(
+ SAMLConstants.SAML2_POST_BINDING_URI)) {
+ binding = springContext.getBean("PVPPOSTBinding", PostBinding.class);
+
+ }
+
+ if (binding == null) {
+ throw new BindingNotSupportedException(consumerService.getBinding());
+ }
+
+ binding.encodeRespone(httpReq, httpResp, authResponse,
+ consumerService.getLocation(), moaRequest.getRelayState(),
+ pvpIDPCredentials.getIDPAssertionSigningCredential(), req);
+
+ //set protocol type
+ sloInformation.setProtocolType(req.requestedModule());
+ sloInformation.setSpEntityID(req.getServiceProviderConfiguration().getUniqueIdentifier());
+ return sloInformation;
+
+ } catch (MessageEncodingException e) {
+ log.error("Message Encoding exception", e);
+ throw new ResponderErrorException("pvp2.01", null, e);
+
+ } catch (SecurityException e) {
+ log.error("Security exception", e);
+ throw new ResponderErrorException("pvp2.01", null, e);
+
+ } catch (EAAFException e) {
+ log.error("Response generation error", e);
+ throw new ResponderErrorException("pvp2.01", null, e);
+
+ }
+
+ }
+
+ public boolean needAuthentication(IRequest req, HttpServletRequest httpReq,
+ HttpServletResponse httpResp) {
+ return true;
+ }
+
+ public String getDefaultActionName() {
+ return "PVPAuthenticationRequestAction";
+
+ }
+
+ @PostConstruct
+ private void verifyInitialization() {
+ if (pvpIDPCredentials == null) {
+ log.error("No SAML2 credentialProvider injected!");
+ throw new RuntimeException("No SAML2 credentialProvider injected!");
+
+ }
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java
new file mode 100644
index 00000000..fa871597
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.impl;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Service;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.IAction;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface;
+import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger;
+import at.gv.egiz.eaaf.modules.pvp2.PVPEventConstants;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataBuilderConfiguration;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataConfigurationFactory;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2MetadataException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPMetadataBuilder;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider;
+
+@Service("pvpMetadataService")
+public class MetadataAction implements IAction {
+
+ private static final Logger log = LoggerFactory.getLogger(MetadataAction.class);
+
+ @Autowired private IRevisionLogger revisionsLogger;
+ @Autowired private PVPMetadataBuilder metadatabuilder;
+ @Autowired private IPVPMetadataConfigurationFactory configFactory;
+
+ private AbstractCredentialProvider pvpIDPCredentials;
+
+ /**
+ * Sets a specific credential provider for PVP S-Profile IDP component.
+ * @param pvpIDPCredentials credential provider
+ */
+ public void setPvpIDPCredentials(AbstractCredentialProvider pvpIDPCredentials) {
+ this.pvpIDPCredentials = pvpIDPCredentials;
+
+ }
+
+ public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq,
+ HttpServletResponse httpResp, IAuthData authData) throws PVP2MetadataException {
+ try {
+ revisionsLogger.logEvent(req, PVPEventConstants.AUTHPROTOCOL_PVP_METADATA);
+
+ //build metadata
+ IPVPMetadataBuilderConfiguration metadataConfig =
+ configFactory.generateMetadataBuilderConfiguration(
+ req.getAuthURLWithOutSlash(),
+ pvpIDPCredentials);
+
+ ;
+
+ String metadataXML = metadatabuilder.buildPVPMetadata(metadataConfig);
+ log.debug("METADATA: " + metadataXML);
+
+ byte[] content = metadataXML.getBytes("UTF-8");
+ httpResp.setStatus(HttpServletResponse.SC_OK);
+ httpResp.setContentLength(content.length);
+ httpResp.setContentType(MediaType.APPLICATION_XML_VALUE);
+ httpResp.getOutputStream().write(content);
+ return null;
+
+ } catch (Exception e) {
+ log.error("Failed to generate metadata", e);
+ throw new PVP2MetadataException("pvp2.13", null);
+ }
+ }
+
+ public boolean needAuthentication(IRequest req, HttpServletRequest httpReq,
+ HttpServletResponse httpResp) {
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.moduls.IAction#getDefaultActionName()
+ */
+ @Override
+ public String getDefaultActionName() {
+ return "IDP - PVP Metadata action";
+ }
+
+ @PostConstruct
+ private void verifyInitialization() {
+ if (pvpIDPCredentials == null) {
+ log.error("No SAML2 credentialProvider injected!");
+ throw new RuntimeException("No SAML2 credentialProvider injected!");
+
+ }
+ }
+
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PVPSProfilePendingRequest.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PVPSProfilePendingRequest.java
new file mode 100644
index 00000000..06c64b84
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PVPSProfilePendingRequest.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.impl;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl;
+import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage;
+
+@Component("PVPSProfilePendingRequest")
+@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
+public class PVPSProfilePendingRequest extends RequestImpl {
+ private static final long serialVersionUID = 4889919265919638188L;
+
+ InboundMessage request;
+ String binding;
+ String consumerURL;
+
+ public InboundMessage getRequest() {
+ return request;
+ }
+
+ public void setRequest(InboundMessage request) {
+ this.request = request;
+ }
+
+ public String getBinding() {
+ return binding;
+ }
+
+ public void setBinding(String binding) {
+ this.binding = binding;
+ }
+
+ public String getConsumerURL() {
+ return consumerURL;
+ }
+
+ public void setConsumerURL(String consumerURL) {
+ this.consumerURL = consumerURL;
+
+ }
+
+// /* (non-Javadoc)
+// * @see at.gv.egovernment.moa.id.moduls.RequestImpl#getRequestedAttributes()
+// */
+// @Override
+// public Collection<String> getRequestedAttributes(MetadataProvider metadataProvider) {
+//
+// Map<String, String> reqAttr = new HashMap<String, String>();
+// for (String el : PVP2XProtocol.DEFAULTREQUESTEDATTRFORINTERFEDERATION)
+// reqAttr.put(el, "");
+//
+// try {
+// SPSSODescriptor spSSODescriptor = getRequest().getEntityMetadata(metadataProvider).getSPSSODescriptor(SAMLConstants.SAML20P_NS);
+// if (spSSODescriptor.getAttributeConsumingServices() != null &&
+// spSSODescriptor.getAttributeConsumingServices().size() > 0) {
+//
+// Integer aIdx = null;
+// if (getRequest() instanceof MOARequest &&
+// ((MOARequest)getRequest()).getSamlRequest() instanceof AuthnRequestImpl) {
+// AuthnRequestImpl authnRequest = (AuthnRequestImpl)((MOARequest)getRequest()).getSamlRequest();
+// aIdx = authnRequest.getAttributeConsumingServiceIndex();
+//
+// } else {
+// Logger.error("MOARequest is NOT of type AuthnRequest");
+// }
+//
+// int idx = 0;
+//
+// AttributeConsumingService attributeConsumingService = null;
+//
+// if (aIdx != null) {
+// idx = aIdx.intValue();
+// attributeConsumingService = spSSODescriptor
+// .getAttributeConsumingServices().get(idx);
+//
+// } else {
+// List<AttributeConsumingService> attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices();
+// for (AttributeConsumingService el : attrConsumingServiceList) {
+// if (el.isDefault())
+// attributeConsumingService = el;
+// }
+// }
+//
+// for ( RequestedAttribute attr : attributeConsumingService.getRequestAttributes())
+// reqAttr.put(attr.getName(), "");
+// }
+//
+// //return attributQueryBuilder.buildSAML2AttributeList(this.getOnlineApplicationConfiguration(), reqAttr.keySet().iterator());
+// return reqAttr.keySet();
+//
+// } catch (NoMetadataInformationException e) {
+// Logger.warn("NO metadata found for Entity " + getRequest().getEntityID());
+// return null;
+//
+// }
+//
+// }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java
new file mode 100644
index 00000000..34a28f72
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.joda.time.DateTime;
+import org.opensaml.Configuration;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.core.Assertion;
+import org.opensaml.saml2.core.EncryptedAssertion;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.saml2.core.RequestAbstractType;
+import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.encryption.Encrypter;
+import org.opensaml.saml2.encryption.Encrypter.KeyPlacement;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.security.MetadataCredentialResolver;
+import org.opensaml.security.MetadataCriteria;
+import org.opensaml.xml.encryption.EncryptionException;
+import org.opensaml.xml.encryption.EncryptionParameters;
+import org.opensaml.xml.encryption.KeyEncryptionParameters;
+import org.opensaml.xml.security.CriteriaSet;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.credential.UsageType;
+import org.opensaml.xml.security.criteria.EntityIDCriteria;
+import org.opensaml.xml.security.criteria.UsageCriteria;
+import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorFactory;
+import org.opensaml.xml.security.x509.X509Credential;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.modules.pvp2.PVPConstants;
+import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+
+/**
+ * @author tlenz
+ *
+ */
+public class AuthResponseBuilder {
+
+ private static final Logger log = LoggerFactory.getLogger(AuthResponseBuilder.class);
+
+ public static Response buildResponse(MetadataProvider metadataProvider, String issuerEntityID, RequestAbstractType req, DateTime date, Assertion assertion, boolean enableEncryption) throws InvalidAssertionEncryptionException {
+ Response authResponse = SAML2Utils.createSAMLObject(Response.class);
+
+ Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class);
+
+ nissuer.setValue(issuerEntityID);
+ nissuer.setFormat(NameID.ENTITY);
+ authResponse.setIssuer(nissuer);
+ authResponse.setInResponseTo(req.getID());
+
+ //set responseID
+ String remoteSessionID = SAML2Utils.getSecureIdentifier();
+ authResponse.setID(remoteSessionID);
+
+
+ //SAML2 response required IssueInstant
+ authResponse.setIssueInstant(date);
+
+ authResponse.setStatus(SAML2Utils.getSuccessStatus());
+
+ //check, if metadata includes an encryption key
+ MetadataCredentialResolver mdCredResolver =
+ new MetadataCredentialResolver(metadataProvider);
+
+ CriteriaSet criteriaSet = new CriteriaSet();
+ criteriaSet.add( new EntityIDCriteria(req.getIssuer().getValue()) );
+ criteriaSet.add( new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) );
+ criteriaSet.add( new UsageCriteria(UsageType.ENCRYPTION) );
+
+ X509Credential encryptionCredentials = null;
+ try {
+ encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet);
+
+ } catch (SecurityException e2) {
+ log.warn("Can not extract the Assertion Encryption-Key from metadata", e2);
+ throw new InvalidAssertionEncryptionException();
+
+ }
+
+ if (encryptionCredentials != null && enableEncryption) {
+ //encrypt SAML2 assertion
+
+ try {
+
+ EncryptionParameters dataEncParams = new EncryptionParameters();
+ dataEncParams.setAlgorithm(PVPConstants.DEFAULT_SYM_ENCRYPTION_METHODE);
+
+ List<KeyEncryptionParameters> keyEncParamList = new ArrayList<KeyEncryptionParameters>();
+ KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters();
+
+ keyEncParam.setEncryptionCredential(encryptionCredentials);
+ keyEncParam.setAlgorithm(PVPConstants.DEFAULT_ASYM_ENCRYPTION_METHODE);
+ KeyInfoGeneratorFactory kigf = Configuration.getGlobalSecurityConfiguration()
+ .getKeyInfoGeneratorManager().getDefaultManager()
+ .getFactory(encryptionCredentials);
+ keyEncParam.setKeyInfoGenerator(kigf.newInstance());
+ keyEncParamList.add(keyEncParam);
+
+ Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList);
+ //samlEncrypter.setKeyPlacement(KeyPlacement.INLINE);
+ samlEncrypter.setKeyPlacement(KeyPlacement.PEER);
+
+ EncryptedAssertion encryptAssertion = null;
+
+ encryptAssertion = samlEncrypter.encrypt(assertion);
+
+ authResponse.getEncryptedAssertions().add(encryptAssertion);
+
+ } catch (EncryptionException e1) {
+ log.warn("Can not encrypt the PVP2 assertion", e1);
+ throw new InvalidAssertionEncryptionException();
+
+ }
+
+ } else {
+ authResponse.getAssertions().add(assertion);
+
+ }
+
+ return authResponse;
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java
new file mode 100644
index 00000000..7369da15
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java
@@ -0,0 +1,448 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder;
+
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.core.Assertion;
+import org.opensaml.saml2.core.Attribute;
+import org.opensaml.saml2.core.AttributeQuery;
+import org.opensaml.saml2.core.AttributeStatement;
+import org.opensaml.saml2.core.Audience;
+import org.opensaml.saml2.core.AudienceRestriction;
+import org.opensaml.saml2.core.AuthnContext;
+import org.opensaml.saml2.core.AuthnContextClassRef;
+import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.AuthnStatement;
+import org.opensaml.saml2.core.Conditions;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.saml2.core.RequestedAuthnContext;
+import org.opensaml.saml2.core.Subject;
+import org.opensaml.saml2.core.SubjectConfirmation;
+import org.opensaml.saml2.core.SubjectConfirmationData;
+import org.opensaml.saml2.core.impl.AuthnRequestImpl;
+import org.opensaml.saml2.metadata.AssertionConsumerService;
+import org.opensaml.saml2.metadata.AttributeConsumingService;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.NameIDFormat;
+import org.opensaml.saml2.metadata.RequestedAttribute;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Base64Utils;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.data.ILoALevelMapper;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface;
+import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl;
+import at.gv.egiz.eaaf.core.impl.utils.Random;
+import at.gv.egiz.eaaf.modules.pvp2.PVPConstants;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception;
+import at.gv.egiz.eaaf.modules.pvp2.exception.QAANotSupportedException;
+import at.gv.egiz.eaaf.modules.pvp2.idp.api.builder.ISubjectNameIdGenerator;
+import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException;
+import at.gv.egiz.eaaf.modules.pvp2.idp.exception.UnprovideableAttributeException;
+import at.gv.egiz.eaaf.modules.pvp2.idp.impl.PVPSProfilePendingRequest;
+import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPAttributeBuilder;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.QAALevelVerifier;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+
+@Service("PVP2AssertionBuilder")
+public class PVP2AssertionBuilder implements PVPConstants {
+
+ private static final Logger log = LoggerFactory.getLogger(PVP2AssertionBuilder.class);
+ @Autowired private ILoALevelMapper loaLevelMapper;
+ @Autowired private ISubjectNameIdGenerator subjectNameIdGenerator;
+
+
+ /**
+ * Build a PVP assertion as response for a SAML2 AttributeQuery request
+ *
+ * @param issuerEntityID EnitiyID, which should be used for this IDP response
+ * @param attrQuery AttributeQuery request from Service-Provider
+ * @param attrList List of PVP response attributes
+ * @param now Current time
+ * @param validTo ValidTo time of the assertion
+ * @param qaaLevel QAA level of the authentication
+ * @param sessionIndex SAML2 SessionIndex, which should be included *
+ * @return PVP 2.1 Assertion
+ * @throws PVP2Exception
+ */
+ public Assertion buildAssertion(String issuerEntityID, AttributeQuery attrQuery,
+ List<Attribute> attrList, DateTime now, DateTime validTo, String qaaLevel, String sessionIndex) throws PVP2Exception {
+
+ AuthnContextClassRef authnContextClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class);
+ authnContextClassRef.setAuthnContextClassRef(qaaLevel);
+
+ NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class);
+ subjectNameID.setFormat(attrQuery.getSubject().getNameID().getFormat());
+ subjectNameID.setValue(attrQuery.getSubject().getNameID().getValue());
+
+ SubjectConfirmationData subjectConfirmationData = null;
+
+ return buildGenericAssertion(issuerEntityID, attrQuery.getIssuer().getValue(), now,
+ authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex,
+ validTo);
+ }
+
+
+ /**
+ * Build a PVP 2.1 assertion as response of a SAML2 AuthnRequest
+ *
+ * @param issuerEntityID EnitiyID, which should be used for this IDP response
+ * @param pendingReq Current processed pendingRequest DAO
+ * @param authnRequest Current processed PVP AuthnRequest
+ * @param authData AuthenticationData of the user, which is already authenticated
+ * @param peerEntity SAML2 EntityDescriptor of the service-provider, which receives the response
+ * @param date TimeStamp
+ * @param assertionConsumerService SAML2 endpoint of the service-provider, which should be used
+ * @param sloInformation Single LogOut information DAO
+ * @return
+ * @throws PVP2Exception
+ */
+ public Assertion buildAssertion(String issuerEntityID, PVPSProfilePendingRequest pendingReq, AuthnRequest authnRequest,
+ IAuthData authData, EntityDescriptor peerEntity, DateTime date,
+ AssertionConsumerService assertionConsumerService, SLOInformationInterface sloInformation)
+ throws PVP2Exception {
+
+ RequestedAuthnContext reqAuthnContext = authnRequest
+ .getRequestedAuthnContext();
+
+ AuthnContextClassRef authnContextClassRef = SAML2Utils
+ .createSAMLObject(AuthnContextClassRef.class);
+
+ ISPConfiguration oaParam = pendingReq.getServiceProviderConfiguration();
+
+ if (reqAuthnContext == null) {
+ authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel());
+
+ } else {
+
+ boolean eIDAS_qaa_found = false;
+
+ List<AuthnContextClassRef> reqAuthnContextClassRefIt = reqAuthnContext
+ .getAuthnContextClassRefs();
+
+ if (reqAuthnContextClassRefIt.size() == 0) {
+ QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(), EAAFConstants.EIDAS_QAA_HIGH);
+
+ eIDAS_qaa_found = true;
+ authnContextClassRef.setAuthnContextClassRef(EAAFConstants.EIDAS_QAA_HIGH);
+
+ } else {
+ for (AuthnContextClassRef authnClassRef : reqAuthnContextClassRefIt) {
+ String qaa_uri = authnClassRef.getAuthnContextClassRef();
+
+ if (!qaa_uri.trim().startsWith(EAAFConstants.EIDAS_QAA_PREFIX)) {
+ if (loaLevelMapper != null) {
+ log.debug("Find no eIDAS LoA. Start mapping process ... " );
+ qaa_uri = loaLevelMapper.mapToeIDASLoA(qaa_uri.trim());
+
+ } else
+ log.debug("AuthnRequest contains no eIDAS LoA. NO LoA mapper FOUND, ignore "
+ + "'" + qaa_uri.trim() + "'");
+
+ }
+
+ if (qaa_uri.trim().equals(EAAFConstants.EIDAS_QAA_HIGH)
+ || qaa_uri.trim().equals(EAAFConstants.EIDAS_QAA_SUBSTANTIAL)
+ || qaa_uri.trim().equals(EAAFConstants.EIDAS_QAA_LOW)) {
+
+ if (authData.isForeigner()) {
+ QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(), oaParam.getMinimumLevelOfAssurence());
+
+ eIDAS_qaa_found = true;
+ authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel());
+
+ } else {
+
+ QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(),
+ qaa_uri.trim());
+
+ eIDAS_qaa_found = true;
+ authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel());
+
+ }
+ break;
+ }
+ }
+ }
+
+ if (!eIDAS_qaa_found)
+ throw new QAANotSupportedException(EAAFConstants.EIDAS_QAA_HIGH);
+
+ }
+
+
+
+ SPSSODescriptor spSSODescriptor = peerEntity
+ .getSPSSODescriptor(SAMLConstants.SAML20P_NS);
+
+ //add Attributes to Assertion
+ List<Attribute> attrList = new ArrayList<Attribute>();
+ if (spSSODescriptor.getAttributeConsumingServices() != null &&
+ spSSODescriptor.getAttributeConsumingServices().size() > 0) {
+
+ Integer aIdx = authnRequest.getAttributeConsumingServiceIndex();
+ int idx = 0;
+
+ AttributeConsumingService attributeConsumingService = null;
+ if (aIdx != null) {
+ idx = aIdx.intValue();
+ attributeConsumingService = spSSODescriptor
+ .getAttributeConsumingServices().get(idx);
+
+ } else {
+ List<AttributeConsumingService> attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices();
+ for (AttributeConsumingService el : attrConsumingServiceList) {
+ if (el.isDefault())
+ attributeConsumingService = el;
+ }
+ }
+
+ /*
+ * TODO: maybe use first AttributeConsumingService if no is selected
+ * in request or on service is marked as default
+ *
+ */
+ if (attributeConsumingService == null ) {
+ List<AttributeConsumingService> attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices();
+ if (attrConsumingServiceList != null && !attrConsumingServiceList.isEmpty())
+ attributeConsumingService = attrConsumingServiceList.get(0);
+
+ }
+
+
+ if (attributeConsumingService != null) {
+ Iterator<RequestedAttribute> it = attributeConsumingService
+ .getRequestAttributes().iterator();
+ while (it.hasNext()) {
+ RequestedAttribute reqAttribut = it.next();
+ try {
+ Attribute attr = PVPAttributeBuilder.buildAttribute(
+ reqAttribut.getName(), oaParam, authData);
+ if (attr == null) {
+ if (reqAttribut.isRequired()) {
+ throw new UnprovideableAttributeException(
+ reqAttribut.getName());
+ }
+ } else {
+ attrList.add(attr);
+ }
+
+ } catch (UnavailableAttributeException e) {
+ log.info(
+ "Attribute generation for "
+ + reqAttribut.getFriendlyName() + " not possible.");
+ if (reqAttribut.isRequired()) {
+ throw new UnprovideableAttributeException(
+ reqAttribut.getName());
+ }
+
+
+ } catch (PVP2Exception e) {
+ log.info(
+ "Attribute generation failed! for "
+ + reqAttribut.getFriendlyName());
+ if (reqAttribut.isRequired()) {
+ throw new UnprovideableAttributeException(
+ reqAttribut.getName());
+ }
+
+ } catch (Exception e) {
+ log.warn(
+ "General Attribute generation failed! for "
+ + reqAttribut.getFriendlyName(), e);
+ if (reqAttribut.isRequired()) {
+ throw new UnprovideableAttributeException(
+ reqAttribut.getName());
+ }
+
+ }
+ }
+ }
+ }
+
+ //generate subjectNameId
+ NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class);
+ Pair<String, String> subjectNameIdPair = subjectNameIdGenerator.generateSubjectNameId(authData, oaParam);
+ subjectNameID.setValue(subjectNameIdPair.getFirst());
+ subjectNameID.setNameQualifier(subjectNameIdPair.getSecond());
+
+ //get NameIDFormat from request
+ String nameIDFormat = NameID.TRANSIENT;
+ AuthnRequest authnReq = (AuthnRequestImpl) authnRequest;
+ if (authnReq.getNameIDPolicy() != null &&
+ StringUtils.isNotEmpty(authnReq.getNameIDPolicy().getFormat())) {
+ nameIDFormat = authnReq.getNameIDPolicy().getFormat();
+
+ } else {
+ //get NameIDFormat from metadata
+ List<NameIDFormat> metadataNameIDFormats = spSSODescriptor.getNameIDFormats();
+
+ if (metadataNameIDFormats != null) {
+
+ for (NameIDFormat el : metadataNameIDFormats) {
+ if (NameID.PERSISTENT.equals(el.getFormat())) {
+ nameIDFormat = NameID.PERSISTENT;
+ break;
+
+ } else if (NameID.TRANSIENT.equals(el.getFormat()) ||
+ NameID.UNSPECIFIED.equals(el.getFormat()))
+ break;
+
+ }
+ }
+ }
+
+ if (NameID.TRANSIENT.equals(nameIDFormat) || NameID.UNSPECIFIED.equals(nameIDFormat)) {
+ String random = Random.nextHexRandom32();
+ String nameID = subjectNameID.getValue();
+
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest((nameID + random).getBytes("ISO-8859-1"));
+ subjectNameID.setValue(Base64Utils.encodeToString(hash));
+ subjectNameID.setNameQualifier(null);
+ subjectNameID.setFormat(NameID.TRANSIENT);
+
+ } catch (Exception e) {
+ log.warn("PVP2 subjectNameID error", e);
+ throw new ResponderErrorException("pvp2.13", null, e);
+ }
+
+ } else
+ subjectNameID.setFormat(nameIDFormat);
+
+
+ String sessionIndex = null;
+
+ //if request is a reauthentication and NameIDFormat match reuse old session information
+ if (StringUtils.isNotEmpty(authData.getNameID()) &&
+ StringUtils.isNotEmpty(authData.getNameIDFormat()) &&
+ nameIDFormat.equals(authData.getNameIDFormat())) {
+ subjectNameID.setValue(authData.getNameID());
+ sessionIndex = authData.getSessionIndex();
+
+ }
+
+ //
+ if (StringUtils.isEmpty(sessionIndex))
+ sessionIndex = SAML2Utils.getSecureIdentifier();
+
+ SubjectConfirmationData subjectConfirmationData = SAML2Utils
+ .createSAMLObject(SubjectConfirmationData.class);
+ subjectConfirmationData.setInResponseTo(authnRequest.getID());
+ subjectConfirmationData.setNotOnOrAfter(new DateTime(authData.getSsoSessionValidTo().getTime()));
+// subjectConfirmationData.setNotBefore(date);
+
+ //set 'recipient' attribute in subjectConformationData
+ subjectConfirmationData.setRecipient(assertionConsumerService.getLocation());
+
+ //set IP address of the user machine as 'Address' attribute in subjectConformationData
+ String usersIPAddress = pendingReq.getGenericData(
+ RequestImpl.DATAID_REQUESTER_IP_ADDRESS, String.class);
+ if (StringUtils.isNotEmpty(usersIPAddress))
+ subjectConfirmationData.setAddress(usersIPAddress);
+
+ //set SLO information
+ sloInformation.setUserNameIdentifier(subjectNameID.getValue());
+ sloInformation.setNameIDFormat(subjectNameID.getFormat());
+ sloInformation.setSessionIndex(sessionIndex);
+
+ return buildGenericAssertion(issuerEntityID, peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, subjectConfirmationData.getNotOnOrAfter());
+ }
+
+ /**
+ *
+ * @param issuer IDP EntityID
+ * @param entityID Service Provider EntityID
+ * @param date
+ * @param authnContextClassRef
+ * @param attrList
+ * @param subjectNameID
+ * @param subjectConfirmationData
+ * @param sessionIndex
+ * @param isValidTo
+ * @return
+ * @throws ConfigurationException
+ */
+
+ public Assertion buildGenericAssertion(String issuer, String entityID, DateTime date,
+ AuthnContextClassRef authnContextClassRef, List<Attribute> attrList,
+ NameID subjectNameID, SubjectConfirmationData subjectConfirmationData,
+ String sessionIndex, DateTime isValidTo) throws ResponderErrorException {
+ Assertion assertion = SAML2Utils.createSAMLObject(Assertion.class);
+
+ AuthnContext authnContext = SAML2Utils
+ .createSAMLObject(AuthnContext.class);
+ authnContext.setAuthnContextClassRef(authnContextClassRef);
+
+ AuthnStatement authnStatement = SAML2Utils
+ .createSAMLObject(AuthnStatement.class);
+
+ authnStatement.setAuthnInstant(date);
+ authnStatement.setSessionIndex(sessionIndex);
+ authnStatement.setAuthnContext(authnContext);
+
+ assertion.getAuthnStatements().add(authnStatement);
+
+ AttributeStatement attributeStatement = SAML2Utils
+ .createSAMLObject(AttributeStatement.class);
+ attributeStatement.getAttributes().addAll(attrList);
+ if (attributeStatement.getAttributes().size() > 0) {
+ assertion.getAttributeStatements().add(attributeStatement);
+ }
+
+ Subject subject = SAML2Utils.createSAMLObject(Subject.class);
+ subject.setNameID(subjectNameID);
+
+ SubjectConfirmation subjectConfirmation = SAML2Utils
+ .createSAMLObject(SubjectConfirmation.class);
+ subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER);
+ subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData);
+
+ subject.getSubjectConfirmations().add(subjectConfirmation);
+
+ Conditions conditions = SAML2Utils.createSAMLObject(Conditions.class);
+ AudienceRestriction audienceRestriction = SAML2Utils
+ .createSAMLObject(AudienceRestriction.class);
+ Audience audience = SAML2Utils.createSAMLObject(Audience.class);
+
+ audience.setAudienceURI(entityID);
+ audienceRestriction.getAudiences().add(audience);
+ conditions.setNotBefore(date);
+ conditions.setNotOnOrAfter(isValidTo);
+
+ conditions.getAudienceRestrictions().add(audienceRestriction);
+
+ assertion.setConditions(conditions);
+
+ Issuer issuerObj = SAML2Utils.createSAMLObject(Issuer.class);
+
+ if (issuer.endsWith("/"))
+ issuer = issuer.substring(0, issuer.length()-1);
+ issuerObj.setValue(issuer);
+ issuerObj.setFormat(NameID.ENTITY);
+
+ assertion.setIssuer(issuerObj);
+ assertion.setSubject(subject);
+ assertion.setID(SAML2Utils.getSecureIdentifier());
+ assertion.setIssueInstant(date);
+
+ return assertion;
+ }
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider
new file mode 100644
index 00000000..cda12a62
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider
@@ -0,0 +1 @@
+at.gv.egiz.eaaf.modules.pvp2.idp.PVP2SProfileIDPSpringResourceProvider \ No newline at end of file
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml
new file mode 100644
index 00000000..a54482e9
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml
@@ -0,0 +1,19 @@
+<?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="PVP2AssertionBuilder"
+ class="at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.PVP2AssertionBuilder" />
+
+ <bean id="PVPSProfilePendingRequest"
+ class="at.gv.egiz.eaaf.modules.pvp2.idp.impl.PVPSProfilePendingRequest"
+ scope="prototype"/>
+
+</beans> \ No newline at end of file