aboutsummaryrefslogtreecommitdiff
path: root/id
diff options
context:
space:
mode:
authorAlexander Marsalek <amarsalek@iaik.tugraz.at>2014-06-10 11:08:32 +0200
committerAlexander Marsalek <amarsalek@iaik.tugraz.at>2014-06-10 11:08:32 +0200
commitc553525294ffe87bc05a5b1b100f86ddf0aa2d84 (patch)
tree714bfe6587fafc3e27122371d1324aa9497c9b36 /id
parentc1ee833c415bcce3d7173f0beec0c1ffcd6c6529 (diff)
parent8dcf7e74a19986c234888b8b93eda5cbddf8ac76 (diff)
downloadmoa-id-spss-c553525294ffe87bc05a5b1b100f86ddf0aa2d84.tar.gz
moa-id-spss-c553525294ffe87bc05a5b1b100f86ddf0aa2d84.tar.bz2
moa-id-spss-c553525294ffe87bc05a5b1b100f86ddf0aa2d84.zip
Merge branch 'moa-2.1-Snapshot' into dokumentservice
Diffstat (limited to 'id')
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/Constants.java9
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticatedUser.java28
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticationManager.java84
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/IActiveUserStorage.java35
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/MemoryActiveUserStorageImpl.java71
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java238
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/Authenticate.java (renamed from id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/Authenticate.java)55
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java (renamed from id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/BuildMetadata.java)21
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBackChannelServlet.java159
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java270
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java291
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/config/ConfigurationProvider.java8
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/PVP2Exception.java55
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/SLOException.java53
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/filter/AuthenticationFilter.java47
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/helper/FormDataHelper.java2
-rw-r--r--id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/IndexAction.java95
-rw-r--r--id/ConfigWebTool/src/main/resources/applicationResources_de.properties3
-rw-r--r--id/ConfigWebTool/src/main/resources/applicationResources_en.properties3
-rw-r--r--id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml26
-rw-r--r--id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/Constants.java6
-rw-r--r--id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java10
-rw-r--r--id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/DemoApplication.java12
-rw-r--r--id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java336
-rw-r--r--id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/SingleLogOut.java239
-rw-r--r--id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/utils/ApplicationBean.java13
-rw-r--r--id/oa/src/main/webapp/WEB-INF/web.xml24
-rw-r--r--id/server/auth/pom.xml4
-rw-r--r--id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml17
-rw-r--r--id/server/auth/src/main/webapp/WEB-INF/web.xml13
-rw-r--r--id/server/data/deploy/conf/moa-id/htmlTemplates/slo_template.html438
-rw-r--r--id/server/doc/conf/moa-id/htmlTemplates/slo_template.html438
-rw-r--r--id/server/idserverlib/pom.xml9
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java4
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java22
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java14
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/IDPSingleLogOutServlet.java122
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/LogOutServlet.java2
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/RedirectServlet.java22
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/AuthenticationData.java17
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/IAuthData.java2
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java118
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java6
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java173
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java75
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/opemsaml/MOAStringRedirectDeflateEncoder.java71
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java34
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java59
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java376
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java2
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java2
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java33
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java31
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java2
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java247
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java18
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java36
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java8
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java12
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java3
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/storage/AuthenticationSessionStoreage.java90
-rw-r--r--id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties7
-rw-r--r--id/server/idserverlib/src/main/resources/resources/templates/slo_template.html438
63 files changed, 4598 insertions, 560 deletions
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/Constants.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/Constants.java
index df1faa7c0..61880b0cb 100644
--- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/Constants.java
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/Constants.java
@@ -35,6 +35,9 @@ public class Constants {
public static final String SERVLET_PVP2ASSERTION = "pvp2login.action";
public static final String SERVLET_ACCOUNTVERIFICATION = "mailAddressVerification.action";
+ public static final String SERVLET_LOGOUT = "logout.action";
+ public static final String SERVLET_SLO_FRONT = "servlet/sloFrontChannel";
+ public static final String SERVLET_SLO_BACK = "servlet/sloBackChannel";
public static final String STRUTS_SUCCESS = "success";
public static final String STRUTS_ERROR = "error";
@@ -58,6 +61,9 @@ public class Constants {
public static final String SESSION_SENDASSERTIONTEMPLATE = "sendAssertionTemplate";
public static final String SESSION_SLTRANSFORMATION = "slTransformation";
+ public static final String SESSION_SLOERROR = "sloerrormessage";
+ public static final String SESSION_SLOSUCCESS = "slosuccessmessage";
+
public static final String SESSION_I18n = "WW_TRANS_I18N_LOCALE";
@@ -69,6 +75,8 @@ public class Constants {
public static final String REQUEST_FORMCUSTOM_MODULE = "module";
public static final String REQUEST_FORMCUSTOM_VALUE = "value";
+ public static final String REQUEST_USERSLO = "userLogOut";
+
public static final String BKU_ONLINE = "bkuonline";
public static final String BKU_LOCAL = "bkulocal";
public static final String BKU_HANDY = "bkuhandy";
@@ -97,6 +105,7 @@ public class Constants {
public static final Map<String, String> BUSINESSSERVICENAMES;
+
static {
Hashtable<String, String> tmp = new Hashtable<String, String>();
tmp.put(IDENIFICATIONTYPE_FN, "Firmenbuchnummer");
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticatedUser.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticatedUser.java
index 330ed7036..036acf1f6 100644
--- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticatedUser.java
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticatedUser.java
@@ -47,6 +47,9 @@ public class AuthenticatedUser {
private String businessServiceType;
private String businessServiceNumber;
+ private String nameID = null;
+ private String nameIDFormat = null;
+
private AuthenticatedUser() {
}
@@ -68,7 +71,8 @@ public class AuthenticatedUser {
return user;
}
- public static AuthenticatedUser generateUserRequestUser(UserDatabaseFrom form) {
+ public static AuthenticatedUser generateUserRequestUser(UserDatabaseFrom form,
+ String nameID, String nameIDFormat) {
AuthenticatedUser user = new AuthenticatedUser();
user.familyName = form.getFamilyName();
@@ -82,11 +86,14 @@ public class AuthenticatedUser {
user.isPVP2Login = form.isPVPGenerated();
user.lastLogin = new Date();
+ user.nameID = nameID;
+ user.nameIDFormat = nameIDFormat;
+
return user;
}
public AuthenticatedUser(UserDatabase userdb, boolean isAuthenticated, boolean isMandateUser,
- boolean isPVP2Login) {
+ boolean isPVP2Login, String nameID, String nameIDFormat) {
this.familyName = userdb.getFamilyname();
this.givenName = userdb.getGivenname();
@@ -99,6 +106,9 @@ public class AuthenticatedUser {
this.isPVP2Login = isPVP2Login;
this.lastLogin = new Date();
+ this.nameID = nameID;
+ this.nameIDFormat = nameIDFormat;
+
if (!this.isAdmin) generateUserSpecificConfigurationOptions(userdb);
}
@@ -226,6 +236,20 @@ public class AuthenticatedUser {
public void setLastLogin(Date lastLogin) {
this.lastLogin = lastLogin;
}
+
+ /**
+ * @return the nameID
+ */
+ public String getNameID() {
+ return nameID;
+ }
+
+ /**
+ * @return the nameIDFormat
+ */
+ public String getNameIDFormat() {
+ return nameIDFormat;
+ }
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticationManager.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticationManager.java
new file mode 100644
index 000000000..6d3afffc9
--- /dev/null
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/AuthenticationManager.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.configuration.auth;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * @author tlenz
+ *
+ */
+public class AuthenticationManager {
+
+ private static final Logger log = LoggerFactory
+ .getLogger(AuthenticationManager.class);
+
+ private static AuthenticationManager instance = null;
+ private static IActiveUserStorage activeUsers = null;
+
+ public static AuthenticationManager getInstance() {
+ if (instance == null)
+ instance = new AuthenticationManager();
+
+ return instance;
+ }
+
+ private AuthenticationManager() {
+ activeUsers = new MemoryActiveUserStorageImpl();
+
+ }
+
+ public AuthenticatedUser getActiveUser(String nameID) {
+ return activeUsers.getUser(nameID);
+ }
+
+ public void setActiveUser(AuthenticatedUser authUser) {
+ log.debug("LogIn user with nameID:" + authUser.getNameID());
+ activeUsers.setUser(authUser.getNameID(), authUser);
+
+ }
+
+ public boolean isActiveUser(String nameID) {
+ AuthenticatedUser user = activeUsers.getUser(nameID);
+ if (user != null && user.isAuthenticated())
+ return true;
+ else
+ return false;
+ }
+
+ public boolean isActiveUser(AuthenticatedUser authUser) {
+ if (authUser != null)
+ return isActiveUser(authUser.getNameID());
+ else
+ return false;
+ }
+
+ public void removeActiveUser(AuthenticatedUser authUser) {
+ log.debug("LogOut active user " + authUser.getGivenName() + " " + authUser.getFamilyName()
+ + " dbID: " + authUser.getUserID() + " nameID:" + authUser.getNameID());
+ activeUsers.removeUser(authUser.getNameID());
+
+ }
+}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/IActiveUserStorage.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/IActiveUserStorage.java
new file mode 100644
index 000000000..c52fee140
--- /dev/null
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/IActiveUserStorage.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.configuration.auth;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IActiveUserStorage {
+
+ public AuthenticatedUser getUser(String nameID);
+ public void setUser(String nameID, AuthenticatedUser authUser);
+ public void removeUser(String nameID);
+
+}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/MemoryActiveUserStorageImpl.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/MemoryActiveUserStorageImpl.java
new file mode 100644
index 000000000..145da2c35
--- /dev/null
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/MemoryActiveUserStorageImpl.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.configuration.auth;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author tlenz
+ *
+ */
+public class MemoryActiveUserStorageImpl implements IActiveUserStorage {
+
+ private Map<String, AuthenticatedUser> store = null;
+
+ /**
+ *
+ */
+ public MemoryActiveUserStorageImpl() {
+ store = new HashMap<String, AuthenticatedUser>();
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.configuration.auth.IActiveUserStorage#getUser(java.lang.String)
+ */
+ @Override
+ public AuthenticatedUser getUser(String nameID) {
+ return store.get(nameID);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.configuration.auth.IActiveUserStorage#setUser(java.lang.String, at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser)
+ */
+ @Override
+ public void setUser(String nameID, AuthenticatedUser authUser) {
+ store.put(nameID, authUser);
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.configuration.auth.IActiveUserStorage#removeUser(java.lang.String)
+ */
+ @Override
+ public void removeUser(String nameID) {
+ if (store.containsKey(nameID))
+ store.remove(nameID);
+
+ }
+
+}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java
new file mode 100644
index 000000000..3d66a4b19
--- /dev/null
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/PVP2Utils.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.configuration.auth.pvp2;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.SignableSAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.binding.encoding.HTTPPostEncoder;
+import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder;
+import org.opensaml.saml2.core.RequestAbstractType;
+import org.opensaml.saml2.core.StatusResponseType;
+import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.SingleSignOnService;
+import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder;
+import org.opensaml.security.MetadataCredentialResolver;
+import org.opensaml.security.MetadataCredentialResolverFactory;
+import org.opensaml.security.MetadataCriteria;
+import org.opensaml.security.SAMLSignatureProfileValidator;
+import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
+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.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.security.trust.TrustedCredentialTrustEngine;
+import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter;
+import org.opensaml.xml.security.x509.X509Credential;
+import org.opensaml.xml.signature.AbstractSignableXMLObject;
+import org.opensaml.xml.signature.SignableXMLObject;
+import org.opensaml.xml.signature.Signature;
+import org.opensaml.xml.signature.SignatureConstants;
+import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine;
+import org.opensaml.xml.validation.ValidationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider;
+import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException;
+import at.gv.egovernment.moa.id.configuration.exception.PVP2Exception;
+import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils;
+
+/**
+ * @author tlenz
+ *
+ */
+public class PVP2Utils {
+
+ private static final Logger log = LoggerFactory
+ .getLogger(PVP2Utils.class);
+
+ public static void postBindingEncoder(HttpServletRequest req, HttpServletResponse resp,
+ SignableSAMLObject pvp2Req, X509Credential authcredential, String targetLocation, String relayState) throws PVP2Exception {
+ try {
+ VelocityEngine engine = new VelocityEngine();
+ engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8");
+ engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
+ engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8");
+ engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
+ engine.setProperty("classpath.resource.loader.class",
+ "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+ engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+ "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
+ engine.init();
+
+ HTTPPostEncoder encoder = new HTTPPostEncoder(engine,
+ "templates/pvp_postbinding_template.html");
+ 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(authcredential);
+ context.setPeerEntityEndpoint(service);
+ context.setOutboundSAMLMessage(pvp2Req);
+ context.setOutboundMessageTransport(responseAdapter);
+ context.setRelayState(relayState);
+
+ encoder.encode(context);
+
+ } catch (MessageEncodingException e) {
+ log.warn("Encode PVP 2.1 message FAILED.", e);
+ throw new PVP2Exception("Encode PVP 2.1 message FAILED.", e);
+
+ }
+ }
+
+
+ /**
+ * @param request
+ * @param response
+ * @param sloReq
+ * @param authcredential
+ * @param location
+ * @param object
+ * @throws PVP2Exception
+ */
+ public static void redirectBindingEncoder(HttpServletRequest request,
+ HttpServletResponse response, SignableSAMLObject pvp2Req,
+ X509Credential authcredential, String location, String relayState) throws PVP2Exception {
+ try {
+ HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
+ HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
+ response
+ , 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(location);
+ context.setOutboundSAMLMessageSigningCredential(authcredential);
+ context.setPeerEntityEndpoint(service);
+ context.setOutboundSAMLMessage(pvp2Req);
+ context.setOutboundMessageTransport(responseAdapter);
+ context.setRelayState(relayState);
+
+ encoder.encode(context);
+ } catch (MessageEncodingException e) {
+ log.warn("Encode PVP 2.1 message FAILED.", e);
+ throw new PVP2Exception("Encode PVP 2.1 message FAILED.", e);
+
+ }
+ }
+
+ public static ExplicitKeySignatureTrustEngine getTrustEngine(ConfigurationProvider configuration) {
+ //Verify Signature
+ List<KeyInfoProvider> keyInfoProvider = new ArrayList<KeyInfoProvider>();
+ keyInfoProvider.add(new DSAKeyValueProvider());
+ keyInfoProvider.add(new RSAKeyValueProvider());
+ keyInfoProvider.add(new InlineX509DataProvider());
+
+ KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver(
+ keyInfoProvider);
+
+ MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory();
+ MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(configuration.getMetaDataProvier());
+
+ return new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver);
+
+ }
+
+ public static void validateSignature(SignableXMLObject msg, ConfigurationProvider configuration) throws SecurityException, ValidationException {
+ //Validate Signature
+ SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
+ profileValidator.validate(msg.getSignature());
+
+ CriteriaSet criteriaSet = new CriteriaSet();
+ criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS));
+ criteriaSet.add(new EntityIDCriteria(configuration.getPVP2IDPMetadataEntityName()));
+ criteriaSet.add(new UsageCriteria(UsageType.SIGNING));
+
+ ExplicitKeySignatureTrustEngine trustEngine = getTrustEngine(configuration);
+ trustEngine.validate(msg.getSignature(), criteriaSet);
+ }
+
+ public static X509Credential signMessage(AbstractSignableXMLObject msg, ConfigurationProvider config) throws PVP2Exception {
+ //sign authentication request
+ KeyStore keyStore;
+ try {
+ keyStore = config.getPVP2KeyStore();
+ X509Credential authcredential = new KeyStoreX509CredentialAdapter(
+ keyStore,
+ config.getPVP2KeystoreAuthRequestKeyAlias(),
+ config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray());
+
+ Signature signer = SAML2Utils.createSAMLObject(Signature.class);
+ signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
+ signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
+ signer.setSigningCredential(authcredential);
+ msg.setSignature(signer);
+
+ return authcredential;
+
+ } catch (NoSuchAlgorithmException e) {
+ log.warn("Sign PVP 2.1 message FAILED.", e);
+ throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e);
+
+ } catch (CertificateException e) {
+ log.warn("Sign PVP 2.1 message FAILED.", e);
+ throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e);
+
+ } catch (KeyStoreException e) {
+ log.warn("Sign PVP 2.1 message FAILED.", e);
+ throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e);
+
+ } catch (ConfigurationException e) {
+ log.warn("Sign PVP 2.1 message FAILED.", e);
+ throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e);
+
+ } catch (IOException e) {
+ log.warn("Sign PVP 2.1 message FAILED.", e);
+ throw new PVP2Exception("Sign PVP 2.1 message FAILED.", e);
+ }
+ }
+}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/Authenticate.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/Authenticate.java
index abcfd67e9..56f6d8827 100644
--- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/Authenticate.java
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/Authenticate.java
@@ -20,7 +20,7 @@
* The "NOTICE" text file is part of the distribution. Any derivative works
* that you distribute must include a readable copy of the "NOTICE" text file.
*******************************************************************************/
-package at.gv.egovernment.moa.id.configuration.auth.pvp2;
+package at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets;
import java.io.IOException;
import java.security.KeyStore;
@@ -64,6 +64,7 @@ import org.opensaml.xml.io.Marshaller;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter;
import org.opensaml.xml.security.x509.X509Credential;
+import org.opensaml.xml.signature.AbstractSignableXMLObject;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureConstants;
import org.slf4j.Logger;
@@ -71,6 +72,7 @@ import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import at.gv.egovernment.moa.id.configuration.Constants;
+import at.gv.egovernment.moa.id.configuration.auth.pvp2.PVP2Utils;
import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider;
import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException;
import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils;
@@ -190,48 +192,17 @@ public class Authenticate extends HttpServlet {
authReq.setRequestedAuthnContext(reqAuthContext);
- KeyStore keyStore = config.getPVP2KeyStore();
-
- X509Credential authcredential = new KeyStoreX509CredentialAdapter(
- keyStore,
- config.getPVP2KeystoreAuthRequestKeyAlias(),
- config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray());
-
- Signature signer = SAML2Utils.createSAMLObject(Signature.class);
- signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
- signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
- signer.setSigningCredential(authcredential);
-
- authReq.setSignature(signer);
-
- VelocityEngine engine = new VelocityEngine();
- engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8");
- engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
- engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8");
- engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
- engine.setProperty("classpath.resource.loader.class",
- "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
- engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
- "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
- engine.init();
-
- HTTPPostEncoder encoder = new HTTPPostEncoder(engine,
- "templates/pvp_postbinding_template.html");
- HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
- response, 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(redirectEndpoint.getLocation());;
+ //sign Message
+ X509Credential authcredential = PVP2Utils.signMessage((AbstractSignableXMLObject) authReq, config);
+
+ //encode message
+ PVP2Utils.postBindingEncoder(request,
+ response,
+ authReq,
+ authcredential,
+ redirectEndpoint.getLocation(),
+ null);
- context.setOutboundSAMLMessageSigningCredential(authcredential);
- context.setPeerEntityEndpoint(service);
- context.setOutboundSAMLMessage(authReq);
- context.setOutboundMessageTransport(responseAdapter);
-
- encoder.encode(context);
-
} catch (Exception e) {
log.warn("Authentication Request can not be generated", e);
throw new ServletException("Authentication Request can not be generated.", e);
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/BuildMetadata.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java
index 9a0f73a1f..f121babc6 100644
--- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/BuildMetadata.java
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/BuildMetadata.java
@@ -20,7 +20,7 @@
* The "NOTICE" text file is part of the distribution. Any derivative works
* that you distribute must include a readable copy of the "NOTICE" text file.
*******************************************************************************/
-package at.gv.egovernment.moa.id.configuration.auth.pvp2;
+package at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets;
import java.io.IOException;
import java.io.StringWriter;
@@ -59,6 +59,7 @@ import org.opensaml.saml2.metadata.LocalizedString;
import org.opensaml.saml2.metadata.NameIDFormat;
import org.opensaml.saml2.metadata.SPSSODescriptor;
import org.opensaml.saml2.metadata.ServiceName;
+import org.opensaml.saml2.metadata.SingleLogoutService;
import org.opensaml.xml.io.Marshaller;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.security.SecurityException;
@@ -75,6 +76,7 @@ import org.opensaml.xml.signature.Signer;
import org.w3c.dom.Document;
import at.gv.egovernment.moa.id.configuration.Constants;
+import at.gv.egovernment.moa.id.configuration.auth.pvp2.AttributeListBuilder;
import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider;
import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException;
import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils;
@@ -228,6 +230,23 @@ public class BuildMetadata extends HttpServlet {
spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService);
+
+ //add SLO services
+ SingleLogoutService postBindingService = SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ postBindingService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
+ postBindingService.setLocation(serviceURL + Constants.SERVLET_SLO_FRONT);
+ spSSODescriptor.getSingleLogoutServices().add(postBindingService);
+
+ SingleLogoutService redirectBindingService = SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ redirectBindingService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ redirectBindingService.setLocation(serviceURL + Constants.SERVLET_SLO_FRONT);
+ spSSODescriptor.getSingleLogoutServices().add(redirectBindingService);
+
+// SingleLogoutService soapBindingService = SAML2Utils.createSAMLObject(SingleLogoutService.class);
+// soapBindingService.setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI);
+// soapBindingService.setLocation(serviceURL + Constants.SERVLET_SLO_BACK);
+// spSSODescriptor.getSingleLogoutServices().add(soapBindingService);
+
spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);
spEntityDescriptor.getRoleDescriptors().add(spSSODescriptor);
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBackChannelServlet.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBackChannelServlet.java
new file mode 100644
index 000000000..4b23089c4
--- /dev/null
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBackChannelServlet.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.saml2.binding.encoding.HTTPSOAP11Encoder;
+import org.opensaml.saml2.core.LogoutRequest;
+import org.opensaml.saml2.core.LogoutResponse;
+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.x509.KeyStoreX509CredentialAdapter;
+import org.opensaml.xml.security.x509.X509Credential;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException;
+
+/**
+ * @author tlenz
+ *
+ */
+public class SLOBackChannelServlet extends SLOBasicServlet {
+
+ private static final long serialVersionUID = 1481623547633064922L;
+ private static final Logger log = LoggerFactory
+ .getLogger(SLOBackChannelServlet.class);
+
+ /**
+ * @throws ConfigurationException
+ */
+ public SLOBackChannelServlet() throws ConfigurationException {
+ super();
+ }
+
+
+ protected void doPost(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+
+ try {
+ HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder(new BasicParserPool());
+ BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext =
+ new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ messageContext
+ .setInboundMessageTransport(new HttpServletRequestAdapter(
+ request));
+
+ soapDecoder.decode(messageContext);
+
+ Envelope inboundMessage = (Envelope) messageContext
+ .getInboundMessage();
+
+ if (inboundMessage.getBody() != null) {
+ List<XMLObject> xmlElemList = inboundMessage.getBody().getUnknownXMLObjects();
+
+ LogoutResponse sloResp;
+ if (!xmlElemList.isEmpty() && xmlElemList.get(0) instanceof LogoutRequest) {
+ LogoutRequest sloReq = (LogoutRequest) xmlElemList.get(0);
+ sloResp = processLogOutRequest(sloReq, request);
+
+ KeyStore keyStore = getConfig().getPVP2KeyStore();
+ X509Credential authcredential = new KeyStoreX509CredentialAdapter(
+ keyStore,
+ getConfig().getPVP2KeystoreAuthRequestKeyAlias(),
+ getConfig().getPVP2KeystoreAuthRequestKeyPassword().toCharArray());
+
+ HTTPSOAP11Encoder encoder = new HTTPSOAP11Encoder();
+ HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
+ response, true);
+ BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ context.setOutboundSAMLMessageSigningCredential(authcredential);
+ context.setOutboundSAMLMessage(sloResp);
+ context.setOutboundMessageTransport(responseAdapter);
+
+ encoder.encode(context);
+
+ } else {
+ log.warn("Received request ist not of type LogOutRequest");
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+
+ }
+ }
+
+ } catch (MessageDecodingException e) {
+ log.error("SLO message processing FAILED." , e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+
+ } catch (SecurityException e) {
+ log.error("SLO message processing FAILED." , e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+
+ } catch (NoSuchAlgorithmException e) {
+ log.error("SLO message processing FAILED." , e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+
+ } catch (CertificateException e) {
+ log.error("SLO message processing FAILED." , e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+
+ } catch (KeyStoreException e) {
+ log.error("SLO message processing FAILED." , e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+
+ } catch (ConfigurationException e) {
+ log.error("SLO message processing FAILED." , e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+
+ } catch (MessageEncodingException e) {
+ log.error("SLO message processing FAILED." , e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+
+ }
+ }
+
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+
+ }
+
+}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java
new file mode 100644
index 000000000..38c858918
--- /dev/null
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOBasicServlet.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets;
+
+import java.security.NoSuchAlgorithmException;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.joda.time.DateTime;
+import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.LogoutRequest;
+import org.opensaml.saml2.core.LogoutResponse;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.saml2.core.NameIDType;
+import org.opensaml.saml2.core.Status;
+import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.SingleLogoutService;
+import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
+import org.opensaml.saml2.metadata.provider.MetadataProviderException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egovernment.moa.id.configuration.Constants;
+import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser;
+import at.gv.egovernment.moa.id.configuration.auth.AuthenticationManager;
+import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider;
+import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException;
+import at.gv.egovernment.moa.id.configuration.exception.PVP2Exception;
+import at.gv.egovernment.moa.id.configuration.exception.SLOException;
+import at.gv.egovernment.moa.id.configuration.helper.LanguageHelper;
+import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils;
+import at.gv.egovernment.moa.util.MiscUtil;
+
+/**
+ * @author tlenz
+ *
+ */
+public class SLOBasicServlet extends HttpServlet {
+ private static final long serialVersionUID = -4547240664871845098L;
+ private static final Logger log = LoggerFactory
+ .getLogger(SLOBasicServlet.class);
+
+ private ConfigurationProvider config;
+
+ public SLOBasicServlet() throws ConfigurationException {
+ config = ConfigurationProvider.getInstance();
+ config.initializePVP2Login();
+ }
+
+ protected LogoutRequest createLogOutRequest(String nameID, String nameIDFormat, HttpServletRequest request) throws SLOException {
+ try {
+ LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class);
+ SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator();
+ sloReq.setID(gen.generateIdentifier());
+ sloReq.setIssueInstant(new DateTime());
+ NameID name = SAML2Utils.createSAMLObject(NameID.class);
+ Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
+
+ String serviceURL = config.getPublicUrlPreFix(request);
+ if (!serviceURL.endsWith("/"))
+ serviceURL = serviceURL + "/";
+ name.setValue(serviceURL);
+ issuer.setValue(serviceURL);
+ issuer.setFormat(NameIDType.ENTITY);
+ sloReq.setIssuer(issuer);
+
+ NameID userNameID = SAML2Utils.createSAMLObject(NameID.class);
+ sloReq.setNameID(userNameID);
+ userNameID.setFormat(nameIDFormat);
+ userNameID.setValue(nameID);
+
+ return sloReq;
+
+ } catch (NoSuchAlgorithmException e) {
+ log.warn("Single LogOut request createn FAILED. ", e);
+ throw new SLOException();
+
+ }
+
+ }
+
+ protected LogoutResponse processLogOutRequest(LogoutRequest sloReq, HttpServletRequest request) throws NoSuchAlgorithmException {
+ //check response destination
+ String serviceURL = config.getPublicUrlPreFix(request);
+ if (!serviceURL.endsWith("/"))
+ serviceURL = serviceURL + "/";
+
+ String responseDestination = sloReq.getDestination();
+ if (MiscUtil.isEmpty(responseDestination) ||
+ !responseDestination.startsWith(serviceURL)) {
+ log.warn("PVPResponse destination does not match requested destination");
+ return createSLOResponse(sloReq, StatusCode.REQUESTER_URI, request);
+ }
+
+ AuthenticationManager authManager = AuthenticationManager.getInstance();
+ if (authManager.isActiveUser(sloReq.getNameID().getValue())) {
+ AuthenticatedUser authUser = authManager.getActiveUser(sloReq.getNameID().getValue());
+ log.info("User " + authUser.getGivenName() + " " + authUser.getFamilyName() + " with nameID:"
+ + authUser.getNameID() + " get logged out by Single LogOut request.");
+ authManager.removeActiveUser(authUser);
+ HttpSession session = request.getSession(false);
+ if (session != null)
+ session.invalidate();
+
+ return createSLOResponse(sloReq, StatusCode.SUCCESS_URI, request);
+
+ } else {
+ log.debug("Single LogOut not possible! User with nameID:" + sloReq.getNameID().getValue() + " is not found.");
+ return createSLOResponse(sloReq, StatusCode.PARTIAL_LOGOUT_URI, request);
+
+ }
+
+ }
+
+ private LogoutResponse createSLOResponse(LogoutRequest sloReq, String statusCodeURI, HttpServletRequest request) throws NoSuchAlgorithmException {
+ LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class);
+ SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator();
+ sloResp.setID(gen.generateIdentifier());
+ sloResp.setInResponseTo(sloReq.getID());
+ sloResp.setIssueInstant(new DateTime());
+ NameID name = SAML2Utils.createSAMLObject(NameID.class);
+ Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
+
+ String serviceURL = config.getPublicUrlPreFix(request);
+ if (!serviceURL.endsWith("/"))
+ serviceURL = serviceURL + "/";
+ name.setValue(serviceURL);
+ issuer.setValue(serviceURL);
+ issuer.setFormat(NameIDType.ENTITY);
+ sloResp.setIssuer(issuer);
+
+ Status status = SAML2Utils.createSAMLObject(Status.class);
+ sloResp.setStatus(status);
+ StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class);
+ statusCode.setValue(statusCodeURI);
+ status.setStatusCode(statusCode );
+
+ return sloResp;
+ }
+
+ protected void validateLogOutResponse(LogoutResponse sloResp, String reqID, HttpServletRequest request, HttpServletResponse response) throws PVP2Exception {
+ //ckeck InResponseTo matchs requestID
+ if (MiscUtil.isEmpty(reqID)) {
+ log.info("NO Sigle LogOut request ID");
+ throw new PVP2Exception("NO Sigle LogOut request ID");
+ }
+
+ if (!reqID.equals(sloResp.getInResponseTo())) {
+ log.warn("SLORequestID does not match SLO Response ID!");
+ throw new PVP2Exception("SLORequestID does not match SLO Response ID!");
+
+ }
+
+ //check response destination
+ String serviceURL = config.getPublicUrlPreFix(request);
+ if (!serviceURL.endsWith("/"))
+ serviceURL = serviceURL + "/";
+
+ String responseDestination = sloResp.getDestination();
+ if (MiscUtil.isEmpty(responseDestination) ||
+ !responseDestination.startsWith(serviceURL)) {
+ log.warn("PVPResponse destination does not match requested destination");
+ throw new PVP2Exception("SLO response destination does not match requested destination");
+ }
+
+ request.getSession().invalidate();
+
+ if (sloResp.getStatus().getStatusCode().getValue().equals(StatusCode.PARTIAL_LOGOUT_URI)) {
+ log.warn("Single LogOut process is not completed.");
+ request.getSession().setAttribute(Constants.SESSION_SLOERROR,
+ LanguageHelper.getErrorString("webpages.slo.error", request));
+
+
+ } else if (sloResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {
+ log.info("Single LogOut process complete.");
+ request.getSession().setAttribute(Constants.SESSION_SLOSUCCESS,
+ LanguageHelper.getErrorString("webpages.slo.success", request));
+
+
+ } else {
+ log.warn("Single LogOut response sends an unsupported statustype " + sloResp.getStatus().getStatusCode().getValue());
+ request.getSession().setAttribute(Constants.SESSION_SLOERROR,
+ LanguageHelper.getErrorString("webpages.slo.error", request));
+
+ }
+ String redirectURL = serviceURL + Constants.SERVLET_LOGOUT;
+ redirectURL = response.encodeRedirectURL(redirectURL);
+ response.setContentType("text/html");
+ response.setStatus(302);
+ response.addHeader("Location", redirectURL);
+
+ }
+
+ protected SingleLogoutService findIDPFrontChannelSLOService() throws
+ ConfigurationException, SLOException {
+
+ String entityname = config.getPVP2IDPMetadataEntityName();
+ if (MiscUtil.isEmpty(entityname)) {
+ log.info("No IDP EntityName configurated");
+ throw new ConfigurationException("No IDP EntityName configurated");
+ }
+
+ //get IDP metadata from metadataprovider
+ HTTPMetadataProvider idpmetadata = config.getMetaDataProvier();
+ try {
+ EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname);
+ if (idpEntity == null) {
+ log.info("IDP EntityName is not found in IDP Metadata");
+ throw new ConfigurationException("IDP EntityName is not found in IDP Metadata");
+
+ }
+
+ //select authentication-service url from metadata
+ SingleLogoutService redirectEndpoint = null;
+ for (SingleLogoutService sss :
+ idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) {
+
+ //Get the service address for the binding you wish to use
+ if (sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI))
+ redirectEndpoint = sss;
+
+ else if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI) &&
+ redirectEndpoint == null)
+ redirectEndpoint = sss;
+ }
+
+ if (redirectEndpoint == null) {
+ log.warn("Single LogOut FAILED: IDP implements no frontchannel SLO service.");
+ throw new SLOException("Single LogOut FAILED: IDP implements no frontchannel SLO service.");
+ }
+
+ return redirectEndpoint;
+ } catch (MetadataProviderException e) {
+ log.info("IDP EntityName is not found in IDP Metadata", e);
+ throw new ConfigurationException("IDP EntityName is not found in IDP Metadata");
+
+ }
+ }
+
+ protected ConfigurationProvider getConfig() {
+ return config;
+ }
+
+}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java
new file mode 100644
index 000000000..67921c689
--- /dev/null
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/auth/pvp2/servlets/SLOFrontChannelServlet.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets;
+
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.SignableSAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.binding.decoding.HTTPPostDecoder;
+import org.opensaml.saml2.binding.decoding.HTTPRedirectDeflateDecoder;
+import org.opensaml.saml2.binding.security.SAML2AuthnRequestsSignedRule;
+import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule;
+import org.opensaml.saml2.core.LogoutRequest;
+import org.opensaml.saml2.core.LogoutResponse;
+import org.opensaml.saml2.core.RequestAbstractType;
+import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.core.StatusResponseType;
+import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.SingleLogoutService;
+import org.opensaml.ws.message.decoder.MessageDecodingException;
+import org.opensaml.ws.security.SecurityPolicyException;
+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.xml.XMLObject;
+import org.opensaml.xml.parse.BasicParserPool;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.x509.X509Credential;
+import org.opensaml.xml.signature.AbstractSignableXMLObject;
+import org.opensaml.xml.signature.SignableXMLObject;
+import org.opensaml.xml.validation.ValidationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egovernment.moa.id.configuration.Constants;
+import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser;
+import at.gv.egovernment.moa.id.configuration.auth.AuthenticationManager;
+import at.gv.egovernment.moa.id.configuration.auth.pvp2.PVP2Utils;
+import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException;
+import at.gv.egovernment.moa.id.configuration.exception.PVP2Exception;
+import at.gv.egovernment.moa.id.configuration.exception.SLOException;
+import at.gv.egovernment.moa.id.configuration.helper.LanguageHelper;
+import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory;
+import at.gv.egovernment.moa.util.MiscUtil;
+
+/**
+ * @author tlenz
+ *
+ */
+public class SLOFrontChannelServlet extends SLOBasicServlet {
+
+ private static final long serialVersionUID = -6280199681356977759L;
+ private static final Logger log = LoggerFactory
+ .getLogger(SLOFrontChannelServlet.class);
+
+ /**
+ * @throws ConfigurationException
+ */
+ public SLOFrontChannelServlet() throws ConfigurationException {
+ super();
+ }
+
+ /**
+ * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ try {
+ if (MiscUtil.isNotEmpty(request.getParameter(Constants.REQUEST_USERSLO))) {
+ //process user initiated single logout process
+ Object authUserObj = request.getSession().getAttribute(Constants.SESSION_AUTH);
+ AuthenticatedUser authUser = (AuthenticatedUser) authUserObj;
+
+ String nameIDFormat = authUser.getNameIDFormat();
+ String nameID = authUser.getNameID();
+
+ //remove user
+ AuthenticationManager authManager = AuthenticationManager.getInstance();
+ authManager.removeActiveUser(authUser);
+
+ if (MiscUtil.isEmpty(nameID) || MiscUtil.isEmpty(nameIDFormat)) {
+ log.warn("No user information found. Single Log-Out not possible");
+ buildErrorMessage(request, response);
+
+ } else
+ log.info("Fount user information for user nameID: " + nameID
+ + " , nameIDFormat: " + nameIDFormat
+ + ". Build Single Log-Out request ...");
+
+ //build SLO request to IDP
+ LogoutRequest sloReq = createLogOutRequest(nameID, nameIDFormat, request);
+
+ request.getSession().setAttribute(Constants.SESSION_PVP2REQUESTID, sloReq.getID());
+
+ //send message
+ sendMessage(request, response, sloReq, null);
+
+ } else {
+ //process PVP 2.1 single logout process
+ HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder(
+ new BasicParserPool());
+ BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(request));
+ messageContext.setMetadataProvider(getConfig().getMetaDataProvier());
+
+ SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule(
+ PVP2Utils.getTrustEngine(getConfig()));
+ SAML2AuthnRequestsSignedRule signedRole = new SAML2AuthnRequestsSignedRule();
+ BasicSecurityPolicy policy = new BasicSecurityPolicy();
+ policy.getPolicyRules().add(signatureRule);
+ policy.getPolicyRules().add(signedRole);
+ SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver(
+ policy);
+ messageContext.setSecurityPolicyResolver(resolver);
+ messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+ decode.decode(messageContext);
+
+ signatureRule.evaluate(messageContext);
+
+
+ processMessage(request, response,
+ messageContext.getInboundMessage(), messageContext.getRelayState());
+
+ }
+
+ } catch (SLOException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (ConfigurationException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (PVP2Exception e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (SecurityPolicyException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (MessageDecodingException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (SecurityException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ }
+ }
+
+ /**
+ * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ protected void doPost(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ try {
+ HTTPPostDecoder decode = new HTTPPostDecoder(new BasicParserPool());
+ BasicSAMLMessageContext<Response, ?, ?> messageContext = new BasicSAMLMessageContext<Response, SAMLObject, SAMLObject>();
+ messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(request));
+ decode.decode(messageContext);
+
+ PVP2Utils.validateSignature((SignableXMLObject) messageContext.getInboundMessage(), getConfig());
+
+ processMessage(request, response,
+ messageContext.getInboundMessage(), messageContext.getRelayState());
+
+
+ } catch (MessageDecodingException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (SecurityException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (ValidationException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (ConfigurationException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (PVP2Exception e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Single LogOut processing error.", e);
+ buildErrorMessage(request, response);
+
+ }
+ }
+
+ private void buildErrorMessage(HttpServletRequest request, HttpServletResponse response) {
+
+ request.getSession().setAttribute(Constants.SESSION_SLOERROR,
+ LanguageHelper.getErrorString("webpages.slo.error", request));
+
+ //check response destination
+ String serviceURL = getConfig().getPublicUrlPreFix(request);
+ if (!serviceURL.endsWith("/"))
+ serviceURL = serviceURL + "/";
+
+ String redirectURL = serviceURL + Constants.SERVLET_LOGOUT;
+ redirectURL = response.encodeRedirectURL(redirectURL);
+ response.setContentType("text/html");
+ response.setStatus(302);
+ response.addHeader("Location", redirectURL);
+ }
+
+ private void processMessage(HttpServletRequest request, HttpServletResponse response,
+ XMLObject xmlObject, String relayState) throws ConfigurationException, PVP2Exception, NoSuchAlgorithmException {
+ if (xmlObject instanceof LogoutRequest) {
+ LogoutResponse sloResp =
+ processLogOutRequest((LogoutRequest) xmlObject, request);
+ sendMessage(request, response, sloResp, relayState);
+
+ } else if (xmlObject instanceof LogoutResponse) {
+ LogoutResponse sloResp = (LogoutResponse) xmlObject;
+
+ String reqID = (String) request.getSession().getAttribute(Constants.SESSION_PVP2REQUESTID);
+ request.getSession().setAttribute(Constants.SESSION_PVP2REQUESTID, null);
+ validateLogOutResponse(sloResp, reqID, request, response);
+
+ }
+ }
+
+ private void sendMessage(HttpServletRequest request, HttpServletResponse response,
+ RequestAbstractType sloReq, String relayState) throws ConfigurationException, PVP2Exception {
+ SingleLogoutService sloService = findIDPFrontChannelSLOService();
+ sloReq.setDestination(sloService.getLocation());
+ sendMessage(request, response, sloReq, sloService, relayState);
+ }
+
+ private void sendMessage(HttpServletRequest request, HttpServletResponse response,
+ StatusResponseType sloReq, String relayState) throws ConfigurationException, PVP2Exception {
+ SingleLogoutService sloService = findIDPFrontChannelSLOService();
+ sloReq.setDestination(sloService.getLocation());
+ sendMessage(request, response, sloReq, sloService, relayState);
+ }
+
+ private void sendMessage(HttpServletRequest request, HttpServletResponse response,
+ SignableSAMLObject sloReq, SingleLogoutService sloService, String relayState) throws ConfigurationException, PVP2Exception {
+ X509Credential authcredential = PVP2Utils.signMessage((AbstractSignableXMLObject) sloReq, getConfig());
+ if (sloService.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI))
+ PVP2Utils.postBindingEncoder(request, response, sloReq, authcredential, sloService.getLocation(), relayState);
+
+ else if (sloService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI))
+ PVP2Utils.redirectBindingEncoder(request, response, sloReq, authcredential, sloService.getLocation(), relayState);
+ }
+
+}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/config/ConfigurationProvider.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/config/ConfigurationProvider.java
index a2aa2a8a4..e176e5141 100644
--- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/config/ConfigurationProvider.java
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/config/ConfigurationProvider.java
@@ -53,12 +53,10 @@ import at.gv.egovernment.moa.id.commons.db.dao.config.ChainingModeType;
import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
import at.gv.egovernment.moa.id.commons.ex.MOAHttpProtocolSocketFactoryException;
import at.gv.egovernment.moa.id.commons.utils.MOAHttpProtocolSocketFactory;
-import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.configuration.Constants;
import at.gv.egovernment.moa.id.configuration.auth.pvp2.MetaDataVerificationFilter;
import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException;
import at.gv.egovernment.moa.id.configuration.utils.UserRequestCleaner;
-import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration;
import at.gv.egovernment.moa.util.FileUtils;
import at.gv.egovernment.moa.util.MiscUtil;
@@ -85,8 +83,12 @@ public class ConfigurationProvider {
private boolean pvp2logininitialzied = false;
public static ConfigurationProvider getInstance() throws ConfigurationException {
+
if (instance == null) {
- instance = new ConfigurationProvider();
+ synchronized (ConfigurationProvider.class) {
+ instance = new ConfigurationProvider();
+ }
+
}
return instance;
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/PVP2Exception.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/PVP2Exception.java
new file mode 100644
index 000000000..c941c4bbe
--- /dev/null
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/PVP2Exception.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.configuration.exception;
+
+/**
+ * @author tlenz
+ *
+ */
+public class PVP2Exception extends Exception {
+
+ private static final long serialVersionUID = -3887330440491843927L;
+
+ /**
+ * @param string
+ */
+ public PVP2Exception(String string) {
+ super(string);
+ }
+
+ /**
+ *
+ */
+ public PVP2Exception() {
+ super();
+ }
+
+ /**
+ * @param string
+ * @param e
+ */
+ public PVP2Exception(String string, Throwable e) {
+ super(string, e);
+ }
+
+}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/SLOException.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/SLOException.java
new file mode 100644
index 000000000..5d34397f4
--- /dev/null
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/exception/SLOException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.configuration.exception;
+
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @author tlenz
+ *
+ */
+public class SLOException extends PVP2Exception {
+ /**
+ * @param string
+ */
+ public SLOException(String string) {
+ super(string);
+ }
+
+ public SLOException() {
+ super();
+ }
+
+ /**
+ * @param string
+ * @param e
+ */
+ public SLOException(String string, Throwable e) {
+ super(string, e);
+ }
+
+ private static final long serialVersionUID = 6443077827626969931L;
+
+}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/filter/AuthenticationFilter.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/filter/AuthenticationFilter.java
index 190773bf0..9ca1d08cc 100644
--- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/filter/AuthenticationFilter.java
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/filter/AuthenticationFilter.java
@@ -43,6 +43,7 @@ import javax.servlet.http.HttpSession;
import at.gv.egovernment.moa.id.configuration.Constants;
import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser;
+import at.gv.egovernment.moa.id.configuration.auth.AuthenticationManager;
import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider;
import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException;
import at.gv.egovernment.moa.util.MiscUtil;
@@ -136,12 +137,26 @@ public class AuthenticationFilter implements Filter{
HttpSession session = httpServletRequest.getSession();
- Object authuser = session.getAttribute(Constants.SESSION_AUTH);
+ Object authuserobj = session.getAttribute(Constants.SESSION_AUTH);
+ AuthenticatedUser authuser = (AuthenticatedUser) authuserobj;
String requestURL = WebAppUtil.getRequestURLWithParameters(httpServletRequest, true);
log.trace("Request URL: " + requestURL);
+ AuthenticationManager authManager = AuthenticationManager.getInstance();
+ if (!authManager.isActiveUser(authuser)) {
+ //user is not active anymore. Invalidate session and reauthenticate user
+ String authID = (String) session.getAttribute(Constants.SESSION_PVP2REQUESTID);
+ session.invalidate();
+ authuser = null;
+
+ //TODO: set infotext
+
+ session = httpServletRequest.getSession(true);
+ session.setAttribute(Constants.SESSION_PVP2REQUESTID, authID);
+ }
+
if (authuser == null && !this.isExcluded(requestURL)) {
if (config.isLoginDeaktivated()) {
@@ -151,6 +166,8 @@ public class AuthenticationFilter implements Filter{
if (authuser == null) {
authuser = AuthenticatedUser.generateDefaultUser();
+ authManager.setActiveUser(authuser);
+
//authuser = new AuthenticatedUser(1, "Max", "TestUser", true, false);
httpServletRequest.getSession().setAttribute(Constants.SESSION_AUTH, authuser);
}
@@ -188,23 +205,23 @@ public class AuthenticationFilter implements Filter{
return;
}
-
}
- }
- try {
- filterchain.doFilter(req, resp);
- } catch (Exception e) {
+ } else {
+ try {
+ filterchain.doFilter(req, resp);
+
+ } catch (Exception e) {
-// String redirectURL = "./index.action";
-// HttpServletResponse httpResp = (HttpServletResponse) resp;
-// redirectURL = httpResp.encodeRedirectURL(redirectURL);
-// resp.setContentType("text/html");
-// ((HttpServletResponse) resp).setStatus(302);
-// httpResp.addHeader("Location", redirectURL);
-// log.warn("A Filter Error occurs -> Redirect to Login-Form");
- }
-
+ //String redirectURL = "./index.action";
+ //HttpServletResponse httpResp = (HttpServletResponse) resp;
+ //redirectURL = httpResp.encodeRedirectURL(redirectURL);
+ //resp.setContentType("text/html");
+ //((HttpServletResponse) resp).setStatus(302);
+ //httpResp.addHeader("Location", redirectURL);
+ //log.warn("A Filter Error occurs -> Redirect to Login-Form");
+ }
+ }
}
public void init(FilterConfig filterConfig) throws ServletException {
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/helper/FormDataHelper.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/helper/FormDataHelper.java
index 24ee653f3..cd6c699b9 100644
--- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/helper/FormDataHelper.java
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/helper/FormDataHelper.java
@@ -88,7 +88,7 @@ public class FormDataHelper {
userlist.add(new AuthenticatedUser(dbuser,
dbuser.isIsActive(),
ismandate,
- false));
+ false, null, null));
}
return userlist;
}
diff --git a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/IndexAction.java b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/IndexAction.java
index e019b70bb..980bb1e59 100644
--- a/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/IndexAction.java
+++ b/id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/IndexAction.java
@@ -85,6 +85,8 @@ import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
import at.gv.egovernment.moa.id.commons.validation.ValidationHelper;
import at.gv.egovernment.moa.id.configuration.Constants;
import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser;
+import at.gv.egovernment.moa.id.configuration.auth.AuthenticationManager;
+import at.gv.egovernment.moa.id.configuration.auth.pvp2.PVP2Utils;
import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider;
import at.gv.egovernment.moa.id.configuration.data.UserDatabaseFrom;
import at.gv.egovernment.moa.id.configuration.exception.BasicActionException;
@@ -216,8 +218,14 @@ public class IndexAction extends BasicAction {
AuthenticatedUser authuser = new AuthenticatedUser(dbuser,
true,
ismandateuser,
- false);
+ false,
+ dbuser.getHjid()+"dbID",
+ "username/password");
+ //store user as authenticated user
+ AuthenticationManager authManager = AuthenticationManager.getInstance();
+ authManager.setActiveUser(authUser);
+
Date date = DateTimeHelper.parseDateTime(dbuser.getLastLogin());
if (date != null)
authuser.setLastLogin(date);;
@@ -308,31 +316,10 @@ public class IndexAction extends BasicAction {
addActionError(LanguageHelper.getErrorString("error.login", request));
return Constants.STRUTS_ERROR;
}
-
- //Validate Signature
- SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
- profileValidator.validate(sign);
-
- //Verify Signature
- List<KeyInfoProvider> keyInfoProvider = new ArrayList<KeyInfoProvider>();
- keyInfoProvider.add(new DSAKeyValueProvider());
- keyInfoProvider.add(new RSAKeyValueProvider());
- keyInfoProvider.add(new InlineX509DataProvider());
- KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver(
- keyInfoProvider);
-
- MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory();
- MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(configuration.getMetaDataProvier());
-
- CriteriaSet criteriaSet = new CriteriaSet();
- criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS));
- criteriaSet.add(new EntityIDCriteria(configuration.getPVP2IDPMetadataEntityName()));
- criteriaSet.add(new UsageCriteria(UsageType.SIGNING));
-
- ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver);
- trustEngine.validate(sign, criteriaSet);
-
+ //validate signature
+ PVP2Utils.validateSignature(samlResponse, configuration);
+
log.info("PVP2 Assertion is valid");
if (samlResponse.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {
@@ -444,7 +431,14 @@ public class IndexAction extends BasicAction {
}
}
- authUser = AuthenticatedUser.generateUserRequestUser(user);
+ //create AuthUser data element
+ authUser = AuthenticatedUser.generateUserRequestUser(user,
+ nameID.getValue(),
+ nameID.getFormat());
+
+ //store user as authenticated user
+ AuthenticationManager authManager = AuthenticationManager.getInstance();
+ authManager.setActiveUser(authUser);
//set Random value
formID = Random.nextRandom();
@@ -468,7 +462,14 @@ public class IndexAction extends BasicAction {
authUser = new AuthenticatedUser(dbuser,
false,
dbuser.isIsMandateUser(),
- true);
+ true,
+ nameID.getValue(),
+ nameID.getFormat());
+
+ //store user as authenticated user
+ AuthenticationManager authManager = AuthenticationManager.getInstance();
+ authManager.setActiveUser(authUser);
+
session.setAttribute(Constants.SESSION_FORM, user);
session.setAttribute(Constants.SESSION_AUTH, authUser);
@@ -488,7 +489,13 @@ public class IndexAction extends BasicAction {
authUser = new AuthenticatedUser(dbuser, true,
ismandateuser,
- true);
+ true,
+ nameID.getValue(),
+ nameID.getFormat());
+
+ //store user as authenticated user
+ AuthenticationManager authManager = AuthenticationManager.getInstance();
+ authManager.setActiveUser(authUser);
Date date = DateTimeHelper.parseDateTime(dbuser.getLastLogin());
if (date != null)
@@ -507,7 +514,7 @@ public class IndexAction extends BasicAction {
finally {
ConfigurationDBUtils.closeSession();
}
-
+
HttpSession newsession = generateNewJSession(request);
newsession.setAttribute(Constants.SESSION_AUTH, authUser);
return Constants.STRUTS_SUCCESS;
@@ -785,33 +792,19 @@ public class IndexAction extends BasicAction {
}
public String logout() {
-
- try {
- populateBasicInformations();
+ HttpSession session = request.getSession(false);
+
+ if (session != null) {
+ if (MiscUtil.isNotEmpty((String)session.getAttribute(Constants.SESSION_SLOSUCCESS)))
+ addActionMessage((String)session.getAttribute(Constants.SESSION_SLOSUCCESS));
- } catch (BasicActionException e) {
- return Constants.STRUTS_ERROR;
+ if (MiscUtil.isNotEmpty((String)session.getAttribute(Constants.SESSION_SLOERROR)))
+ addActionError((String)session.getAttribute(Constants.SESSION_SLOERROR));
- }
-
- if (session != null)
session.invalidate();
-
- try {
- ConfigurationProvider config = ConfigurationProvider.getInstance();
- String ssologout = config.getSSOLogOutURL();
- if (MiscUtil.isNotEmpty(ssologout) && authUser != null && authUser.isPVP2Login()) {
- ssologouturl = ssologout + config.getPublicUrlPreFix(request) + "/index.action";
- return Constants.STRUTS_SSOLOGOUT;
+ }
- }
-
- } catch (ConfigurationException e) {
- log.warn("Configuration can not be loaded.", e);
-
- }
-
return Constants.STRUTS_SUCCESS;
}
diff --git a/id/ConfigWebTool/src/main/resources/applicationResources_de.properties b/id/ConfigWebTool/src/main/resources/applicationResources_de.properties
index 1f0819edf..f379a7a34 100644
--- a/id/ConfigWebTool/src/main/resources/applicationResources_de.properties
+++ b/id/ConfigWebTool/src/main/resources/applicationResources_de.properties
@@ -35,8 +35,11 @@ error.oa.oauth.clientSecret=Client-Secret darf nicht leer sein
error.oa.oauth.keyname=Key-Name darf nicht leer sein
error.oa.oauth.keystore=Keystore darf nicht leer sein und muss eine richtige URL sein.
+
mail.userrequest.subject=Accountanforderung MOA-ID 2.x Konfigurationstool
+webpages.slo.error=Der Abmeldevorgang bei allen Online-Applikationen war nicht erfolgreich. Bitte schlie \u00dfen Sie aus Sicherheitsgr\u00FCnden ihren Browser.
+webpages.slo.success=Sie wurden erfolgreich bei allen Online-Applikationen abgemeldet.
webpages.error.header=Es ist ein Fehler aufgetreten
webpages.index.header=Willkommen bei der MOA-ID 2.x Konfigurationsapplikation
diff --git a/id/ConfigWebTool/src/main/resources/applicationResources_en.properties b/id/ConfigWebTool/src/main/resources/applicationResources_en.properties
index 7733be5d0..398df94a5 100644
--- a/id/ConfigWebTool/src/main/resources/applicationResources_en.properties
+++ b/id/ConfigWebTool/src/main/resources/applicationResources_en.properties
@@ -38,6 +38,9 @@ error.oa.oauth.keystore=Keystore cannot be blank and has to be provided in the f
mail.userrequest.subject=Requesting accounts - MOA-ID 2.x Config Tool
+webpages.slo.error=LogOut process finished with an error. For security reasons, please close your browser.
+webpages.slo.success=LogOut process finished successful
+
webpages.error.header=The error occured
webpages.index.header=Welcome to MOA-ID 2.x Configuration
webpages.index.desciption.head=In order to use this service you should log in
diff --git a/id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml b/id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml
index 3919d3ff3..a6fe50269 100644
--- a/id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml
+++ b/id/ConfigWebTool/src/main/webapp/WEB-INF/web.xml
@@ -64,15 +64,27 @@
<servlet>
<servlet-name>pvp2login</servlet-name>
<display-name>pvp2login</display-name>
- <servlet-class>at.gv.egovernment.moa.id.configuration.auth.pvp2.Authenticate</servlet-class>
+ <servlet-class>at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.Authenticate</servlet-class>
</servlet>
<servlet>
<servlet-name>buildmetadata</servlet-name>
<display-name>buildmetadata</display-name>
- <servlet-class>at.gv.egovernment.moa.id.configuration.auth.pvp2.BuildMetadata</servlet-class>
+ <servlet-class>at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.BuildMetadata</servlet-class>
</servlet>
+ <servlet>
+ <servlet-name>slofrontchannel</servlet-name>
+ <display-name>Single LogOut FrontChannel Service</display-name>
+ <servlet-class>at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.SLOFrontChannelServlet</servlet-class>
+ </servlet>
+
+ <servlet>
+ <servlet-name>slobackchannel</servlet-name>
+ <display-name>Single LogOut BackChannel Service</display-name>
+ <servlet-class>at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.SLOBackChannelServlet</servlet-class>
+ </servlet>
+
<servlet-mapping>
<servlet-name>buildmetadata</servlet-name>
<url-pattern>/servlet/metadata</url-pattern>
@@ -83,6 +95,16 @@
<url-pattern>/servlet/pvp2login</url-pattern>
</servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>slofrontchannel</servlet-name>
+ <url-pattern>/servlet/sloFrontChannel</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>slobackchannel</servlet-name>
+ <url-pattern>/servlet/sloBackChannel</url-pattern>
+ </servlet-mapping>
+
<!-- <filter-mapping>
<filter-name>sitemash</filter-name>
<url-pattern>/*</url-pattern>
diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/Constants.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/Constants.java
index af1dd84be..d6d2b32da 100644
--- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/Constants.java
+++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/Constants.java
@@ -28,4 +28,10 @@ public class Constants {
public static final String SERVLET_PVP2ASSERTION = "demoapplication";
public static final String SESSION_PVP2REQUESTID = "pvp2requestid";
+
+ public static final String SERVLET_PVPSINGLELOGOUT = "singlelogout";
+
+ public static final String SESSION_NAMEID = "pvp2nameID";
+
+ public static final String SESSION_NAMEIDFORMAT = "pvp2nameIDFormat";
}
diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java
index 4c9bc6d76..65a4ab2a7 100644
--- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java
+++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/BuildMetadata.java
@@ -56,6 +56,7 @@ import org.opensaml.saml2.metadata.LocalizedString;
import org.opensaml.saml2.metadata.NameIDFormat;
import org.opensaml.saml2.metadata.SPSSODescriptor;
import org.opensaml.saml2.metadata.ServiceName;
+import org.opensaml.saml2.metadata.SingleLogoutService;
import org.opensaml.saml2.metadata.impl.EncryptionMethodBuilder;
import org.opensaml.xml.encryption.EncryptionConstants;
import org.opensaml.xml.encryption.OAEPparams;
@@ -238,10 +239,15 @@ public class BuildMetadata extends HttpServlet {
postassertionConsumerService.setIndex(0);
postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
- postassertionConsumerService.setLocation(serviceURL + Constants.SERVLET_PVP2ASSERTION);
-
+ postassertionConsumerService.setLocation(serviceURL + Constants.SERVLET_PVP2ASSERTION);
spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService);
+ //set Single Log-Out service
+ SingleLogoutService sloService = SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ sloService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ sloService.setLocation(serviceURL + Constants.SERVLET_PVPSINGLELOGOUT);
+ spSSODescriptor.getSingleLogoutServices().add(sloService);
+
spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);
spEntityDescriptor.getRoleDescriptors().add(spSSODescriptor);
diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/DemoApplication.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/DemoApplication.java
index dcd478864..cde9451a4 100644
--- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/DemoApplication.java
+++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/DemoApplication.java
@@ -73,6 +73,7 @@ import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine;
import at.gv.egovernment.moa.id.demoOA.Configuration;
+import at.gv.egovernment.moa.id.demoOA.Constants;
import at.gv.egovernment.moa.id.demoOA.PVPConstants;
import at.gv.egovernment.moa.id.demoOA.utils.ApplicationBean;
import at.gv.egovernment.moa.id.demoOA.utils.SAML2Utils;
@@ -223,14 +224,19 @@ public class DemoApplication extends HttpServlet {
birthday = attributes.get(x).getAttributeValues().get(0).getDOM().getTextContent();
}
}
- }
+ }
+ request.getSession().setAttribute(Constants.SESSION_NAMEIDFORMAT,
+ saml2assertion.getSubject().getNameID().getFormat());
+ request.getSession().setAttribute(Constants.SESSION_NAMEID,
+ saml2assertion.getSubject().getNameID().getValue());
+
}
-
+
bean.setDateOfBirth(birthday);
bean.setFamilyName(familyName);
bean.setGivenName(givenName);
bean.setLogin(true);
-
+
setAnser(request, response, bean);
return;
diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java
new file mode 100644
index 000000000..666ecaeee
--- /dev/null
+++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/Index.java
@@ -0,0 +1,336 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ *******************************************************************************/
+package at.gv.egovernment.moa.id.demoOA.servlet.pvp2;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.joda.time.DateTime;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.binding.decoding.HTTPPostDecoder;
+import org.opensaml.saml2.binding.decoding.HTTPRedirectDeflateDecoder;
+import org.opensaml.saml2.binding.encoding.HTTPPostEncoder;
+import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder;
+import org.opensaml.saml2.binding.security.SAML2AuthnRequestsSignedRule;
+import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.LogoutRequest;
+import org.opensaml.saml2.core.LogoutResponse;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.saml2.core.NameIDType;
+import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.core.Status;
+import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.core.StatusResponseType;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.SingleLogoutService;
+import org.opensaml.saml2.metadata.SingleSignOnService;
+import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder;
+import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
+import org.opensaml.security.MetadataCredentialResolver;
+import org.opensaml.security.MetadataCredentialResolverFactory;
+import org.opensaml.security.MetadataCriteria;
+import org.opensaml.security.SAMLSignatureProfileValidator;
+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.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.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.security.x509.KeyStoreX509CredentialAdapter;
+import org.opensaml.xml.security.x509.X509Credential;
+import org.opensaml.xml.signature.SignableXMLObject;
+import org.opensaml.xml.signature.Signature;
+import org.opensaml.xml.signature.SignatureConstants;
+import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egovernment.moa.id.demoOA.Configuration;
+import at.gv.egovernment.moa.id.demoOA.exception.ConfigurationException;
+import at.gv.egovernment.moa.id.demoOA.utils.ApplicationBean;
+import at.gv.egovernment.moa.id.demoOA.utils.SAML2Utils;
+import at.gv.egovernment.moa.util.DOMUtils;
+import at.iaik.commons.util.MiscUtil;
+
+
+public class Index extends HttpServlet {
+
+ private static final long serialVersionUID = -2129228304760706063L;
+ private static final Logger log = LoggerFactory
+ .getLogger(Index.class);
+
+
+ private void process(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+
+
+ ApplicationBean bean = new ApplicationBean();
+
+
+ String method = request.getMethod();
+ HttpSession session = request.getSession();
+ if (session == null) {
+ log.info("NO HTTP Session");
+ bean.setErrorMessage("NO HTTP session");
+ setAnser(request, response, bean);
+ return;
+ }
+
+ if (method.equals("GET")) {
+ try {
+ Configuration config = Configuration.getInstance();
+
+ //Decode with HttpPost Binding
+ HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder(
+ new BasicParserPool());
+ BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ messageContext
+ .setInboundMessageTransport(new HttpServletRequestAdapter(request));
+
+ decode.decode(messageContext);
+
+ messageContext.setMetadataProvider(config.getMetaDataProvier());
+ CriteriaSet criteriaSet = new CriteriaSet();
+ criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS));
+ criteriaSet.add(new EntityIDCriteria(config.getPVP2IDPMetadataEntityName()));
+ criteriaSet.add(new UsageCriteria(UsageType.SIGNING));
+
+ MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory.getFactory();
+ MetadataCredentialResolver credentialResolver = credentialResolverFactory.getInstance(config.getMetaDataProvier());
+
+ //Verify Signature
+ List<KeyInfoProvider> keyInfoProvider = new ArrayList<KeyInfoProvider>();
+ keyInfoProvider.add(new DSAKeyValueProvider());
+ keyInfoProvider.add(new RSAKeyValueProvider());
+ keyInfoProvider.add(new InlineX509DataProvider());
+
+ KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver(
+ keyInfoProvider);
+
+
+ ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credentialResolver, keyInfoResolver);
+
+
+ SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule(
+ trustEngine);
+ SAML2AuthnRequestsSignedRule signedRole = new SAML2AuthnRequestsSignedRule();
+ BasicSecurityPolicy policy = new BasicSecurityPolicy();
+ policy.getPolicyRules().add(signatureRule);
+ policy.getPolicyRules().add(signedRole);
+ SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver(
+ policy);
+ messageContext.setSecurityPolicyResolver(resolver);
+
+ messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+ signatureRule.evaluate(messageContext);
+
+ SignableXMLObject samlResponse = (SignableXMLObject) messageContext.getInboundMessage();
+
+
+
+ log.info("PVP2 statusrequest or statusresponse is valid");
+
+
+ if (samlResponse instanceof LogoutResponse) {
+
+ LogoutResponse sloResp = (LogoutResponse) samlResponse;
+
+ //set assertion
+ org.w3c.dom.Document doc = SAML2Utils.asDOMDocument(samlResponse);
+ String assertion = DOMUtils.serializeNode(doc);
+ bean.setAssertion(assertion);
+
+ if (sloResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {
+
+ bean.setSuccessMessage("Der Single Log-Out Vorgang konnte erfolgreich durchgeführt werden.");
+
+ setAnser(request, response, bean);
+ return;
+
+ } else {
+ bean.setErrorMessage("Der Single Log-Out Vorgang war nicht erfolgreich.<br>Bitte schließen Sie aus sicherheitsgründen den Browser!");
+ setAnser(request, response, bean);
+ return;
+
+ }
+
+ } else if (samlResponse instanceof LogoutRequest) {
+ //invalidate user session
+ request.getSession().invalidate();
+
+ //build LogOutResponse
+ LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class);
+ SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator();
+ sloResp.setID(gen.generateIdentifier());
+ sloResp.setIssueInstant(new DateTime());
+ NameID name = SAML2Utils.createSAMLObject(NameID.class);
+ Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
+
+ String serviceURL = config.getPublicUrlPreFix(request);
+ if (!serviceURL.endsWith("/"))
+ serviceURL = serviceURL + "/";
+ name.setValue(serviceURL);
+ issuer.setValue(serviceURL);
+ issuer.setFormat(NameIDType.ENTITY);
+ sloResp.setIssuer(issuer);
+
+ Status status = SAML2Utils.createSAMLObject(Status.class);
+ sloResp.setStatus(status);
+ StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class);
+ statusCode.setValue(StatusCode.SUCCESS_URI);
+ status.setStatusCode(statusCode );
+
+ String entityname = config.getPVP2IDPMetadataEntityName();
+ if (MiscUtil.isEmpty(entityname)) {
+ log.info("No IDP EntityName configurated");
+ throw new ConfigurationException("No IDP EntityName configurated");
+ }
+
+ //get IDP metadata from metadataprovider
+ HTTPMetadataProvider idpmetadata = config.getMetaDataProvier();
+ EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname);
+ if (idpEntity == null) {
+ log.info("IDP EntityName is not found in IDP Metadata");
+ throw new ConfigurationException("IDP EntityName is not found in IDP Metadata");
+ }
+
+ //select authentication-service url from metadata
+ SingleLogoutService redirectEndpoint = null;
+ for (SingleLogoutService sss :
+ idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) {
+
+ //Get the service address for the binding you wish to use
+ if (sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
+ redirectEndpoint = sss;
+ }
+ }
+ sloResp.setDestination(redirectEndpoint.getLocation());
+
+ //sign authentication request
+ KeyStore keyStore = config.getPVP2KeyStore();
+ X509Credential authcredential = new KeyStoreX509CredentialAdapter(
+ keyStore,
+ config.getPVP2KeystoreAuthRequestKeyAlias(),
+ config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray());
+
+ Signature signer = SAML2Utils.createSAMLObject(Signature.class);
+ signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
+ signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
+ signer.setSigningCredential(authcredential);
+ sloResp.setSignature(signer);
+
+ HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
+ HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
+ response, 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(redirectEndpoint.getLocation());;
+
+ context.setOutboundSAMLMessageSigningCredential(authcredential);
+ context.setPeerEntityEndpoint(service);
+ context.setOutboundSAMLMessage(sloResp);
+ context.setOutboundMessageTransport(responseAdapter);
+ context.setRelayState(messageContext.getRelayState());
+
+ encoder.encode(context);
+
+ } else {
+ bean.setErrorMessage("Kein gültiger LogOut Request oder LogOut Response");
+ setAnser(request, response, bean);
+ return;
+
+ }
+
+
+ } catch (Exception e) {
+ log.warn("Internal error", e);
+ bean.setErrorMessage("Internal Error: " + e.getMessage());
+ setAnser(request, response, bean);
+ return;
+ }
+
+ } else {
+ bean.setErrorMessage("Die Demoapplikation unterstützt nur SAML2 POST-Binding.");
+ setAnser(request, response, bean);
+ return;
+
+ }
+ }
+
+ private void setAnser(HttpServletRequest request, HttpServletResponse response, ApplicationBean answersBean) throws ServletException, IOException {
+ // store bean in session
+ request.setAttribute("answers", answersBean);
+
+ // you now can forward to some view, for example some results.jsp
+ request.getRequestDispatcher("demoapp.jsp").forward(request, response);
+
+ }
+
+ /**
+ * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+
+ process(request, response);
+ }
+
+
+ /**
+ * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ protected void doPost(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ process(request, response);
+ }
+}
diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/SingleLogOut.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/SingleLogOut.java
new file mode 100644
index 000000000..11cc020ff
--- /dev/null
+++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/servlet/pvp2/SingleLogOut.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ *******************************************************************************/
+package at.gv.egovernment.moa.id.demoOA.servlet.pvp2;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.joda.time.DateTime;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.binding.encoding.HTTPPostEncoder;
+import org.opensaml.saml2.core.AuthnContextClassRef;
+import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration;
+import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.LogoutRequest;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.saml2.core.NameIDPolicy;
+import org.opensaml.saml2.core.NameIDType;
+import org.opensaml.saml2.core.RequestedAuthnContext;
+import org.opensaml.saml2.core.Subject;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.SingleLogoutService;
+import org.opensaml.saml2.metadata.SingleSignOnService;
+import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder;
+import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
+import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
+import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter;
+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.egovernment.moa.id.demoOA.Configuration;
+import at.gv.egovernment.moa.id.demoOA.Constants;
+import at.gv.egovernment.moa.id.demoOA.exception.ConfigurationException;
+import at.gv.egovernment.moa.id.demoOA.utils.SAML2Utils;
+import at.iaik.commons.util.MiscUtil;
+
+
+/**
+ * Servlet implementation class Authenticate
+ */
+public class SingleLogOut extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger log = LoggerFactory
+ .getLogger(SingleLogOut.class);
+
+ /**
+ * @see HttpServlet#HttpServlet()
+ */
+ public SingleLogOut() {
+ super();
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ try {
+ builder = factory.newDocumentBuilder();
+
+ } catch (ParserConfigurationException e) {
+ log.warn("PVP2 AuthenticationServlet can not be initialized.", e);
+ }
+ }
+
+ DocumentBuilder builder;
+
+
+ //generate AuthenticationRequest
+ protected void process(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ try {
+
+ Configuration config = Configuration.getInstance();
+ config.initializePVP2Login();
+
+ String nameIDFormat = (String) request.getSession().getAttribute(Constants.SESSION_NAMEIDFORMAT);
+ String nameID = (String) request.getSession().getAttribute(Constants.SESSION_NAMEID);
+
+ if (MiscUtil.isEmpty(nameID) || MiscUtil.isEmpty(nameIDFormat)) {
+ log.warn("No user information found. Single Log-Out not possible");
+ throw new ServletException("No user information found. Single Log-Out not possible");
+
+ } else
+ log.info("Fount user information for user nameID: " + nameID
+ + " , nameIDFormat: " + nameIDFormat
+ + ". Build Single Log-Out request ...");
+
+ //invalidate local session
+ request.getSession().invalidate();
+
+ //build Single LogOut request
+ LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class);
+ SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator();
+ sloReq.setID(gen.generateIdentifier());
+ sloReq.setIssueInstant(new DateTime());
+ NameID name = SAML2Utils.createSAMLObject(NameID.class);
+ Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
+
+ String serviceURL = config.getPublicUrlPreFix(request);
+ if (!serviceURL.endsWith("/"))
+ serviceURL = serviceURL + "/";
+ name.setValue(serviceURL);
+ issuer.setValue(serviceURL);
+ issuer.setFormat(NameIDType.ENTITY);
+ sloReq.setIssuer(issuer);
+
+ NameID userNameID = SAML2Utils.createSAMLObject(NameID.class);
+ sloReq.setNameID(userNameID);
+ userNameID.setFormat(nameIDFormat);
+ userNameID.setValue(nameID);
+
+ String entityname = config.getPVP2IDPMetadataEntityName();
+ if (MiscUtil.isEmpty(entityname)) {
+ log.info("No IDP EntityName configurated");
+ throw new ConfigurationException("No IDP EntityName configurated");
+ }
+
+ //get IDP metadata from metadataprovider
+ HTTPMetadataProvider idpmetadata = config.getMetaDataProvier();
+ EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname);
+ if (idpEntity == null) {
+ log.info("IDP EntityName is not found in IDP Metadata");
+ throw new ConfigurationException("IDP EntityName is not found in IDP Metadata");
+ }
+
+ //select authentication-service url from metadata
+ SingleLogoutService redirectEndpoint = null;
+ for (SingleLogoutService sss :
+ idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) {
+
+ //Get the service address for the binding you wish to use
+ if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) {
+ redirectEndpoint = sss;
+ }
+ }
+ sloReq.setDestination(redirectEndpoint.getLocation());
+
+ //sign authentication request
+ KeyStore keyStore = config.getPVP2KeyStore();
+ X509Credential authcredential = new KeyStoreX509CredentialAdapter(
+ keyStore,
+ config.getPVP2KeystoreAuthRequestKeyAlias(),
+ config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray());
+
+ Signature signer = SAML2Utils.createSAMLObject(Signature.class);
+ signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
+ signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
+ signer.setSigningCredential(authcredential);
+ sloReq.setSignature(signer);
+
+ //generate Http-POST Binding message
+ VelocityEngine engine = new VelocityEngine();
+ engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8");
+ engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
+ engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8");
+ engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
+ engine.setProperty("classpath.resource.loader.class",
+ "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+ engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+ "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
+ engine.init();
+
+ HTTPPostEncoder encoder = new HTTPPostEncoder(engine,
+ "templates/pvp_postbinding_template.html");
+ HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
+ response, 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(redirectEndpoint.getLocation());;
+
+ context.setOutboundSAMLMessageSigningCredential(authcredential);
+ context.setPeerEntityEndpoint(service);
+ context.setOutboundSAMLMessage(sloReq);
+ context.setOutboundMessageTransport(responseAdapter);
+
+ encoder.encode(context);
+
+ } catch (Exception e) {
+ log.warn("Authentication Request can not be generated", e);
+ throw new ServletException("Authentication Request can not be generated.", e);
+ }
+ }
+
+ /**
+ * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+
+ process(request, response);
+ }
+
+ /**
+ * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ protected void doPost(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ process(request, response);
+ }
+
+}
diff --git a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/utils/ApplicationBean.java b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/utils/ApplicationBean.java
index 832993604..05c253b6e 100644
--- a/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/utils/ApplicationBean.java
+++ b/id/oa/src/main/java/at/gv/egovernment/moa/id/demoOA/utils/ApplicationBean.java
@@ -36,6 +36,7 @@ public class ApplicationBean implements Serializable {
private boolean isLogin = false;
private String errorMessage;
+ private String successMessage;
/**
* @return the familyName
@@ -109,6 +110,18 @@ public class ApplicationBean implements Serializable {
public void setLogin(boolean isLogin) {
this.isLogin = isLogin;
}
+ /**
+ * @return the successMessage
+ */
+ public String getSuccessMessage() {
+ return successMessage;
+ }
+ /**
+ * @param successMessage the successMessage to set
+ */
+ public void setSuccessMessage(String successMessage) {
+ this.successMessage = successMessage;
+ }
diff --git a/id/oa/src/main/webapp/WEB-INF/web.xml b/id/oa/src/main/webapp/WEB-INF/web.xml
index 85a1bbaeb..d40f156cd 100644
--- a/id/oa/src/main/webapp/WEB-INF/web.xml
+++ b/id/oa/src/main/webapp/WEB-INF/web.xml
@@ -8,7 +8,7 @@
<servlet>
<servlet-name>pvp2login</servlet-name>
- <display-name>pvp2login</display-name>
+ <display-name>PVP 2.1 Authentication request builder</display-name>
<servlet-class>at.gv.egovernment.moa.id.demoOA.servlet.pvp2.Authenticate</servlet-class>
</servlet>
@@ -17,6 +17,17 @@
<url-pattern>/servlet/pvp2login</url-pattern>
</servlet-mapping>
+ <servlet>
+ <servlet-name>pvp2slo</servlet-name>
+ <display-name>PVP 2.1 Single Log-Out request builder</display-name>
+ <servlet-class>at.gv.egovernment.moa.id.demoOA.servlet.pvp2.SingleLogOut</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>pvp2slo</servlet-name>
+ <url-pattern>/servlet/startpvp2slo</url-pattern>
+ </servlet-mapping>
+
<servlet>
<servlet-name>pvp2metadata</servlet-name>
<display-name>Metadata</display-name>
@@ -39,5 +50,16 @@
<url-pattern>/demoapplication</url-pattern>
</servlet-mapping>
+ <servlet>
+ <servlet-name>index</servlet-name>
+ <display-name>Mainpage</display-name>
+ <servlet-class>at.gv.egovernment.moa.id.demoOA.servlet.pvp2.Index</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>index</servlet-name>
+ <url-pattern>/singlelogout</url-pattern>
+ </servlet-mapping>
+
</web-app>
diff --git a/id/server/auth/pom.xml b/id/server/auth/pom.xml
index f18f0e1b0..20c45b096 100644
--- a/id/server/auth/pom.xml
+++ b/id/server/auth/pom.xml
@@ -88,7 +88,9 @@
</build>
<dependencies>
- <!-- we need Axis 1.1 here, 1.0 is included in SPSS -->
+
+
+ <!-- we need Axis 1.1 here, 1.0 is included in SPSS -->
<dependency>
<groupId>axis</groupId>
<artifactId>axis</artifactId>
diff --git a/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml b/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml
index 6da7396a1..23737452a 100644
--- a/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml
+++ b/id/server/auth/src/main/webapp/WEB-INF/urlrewrite.xml
@@ -41,20 +41,29 @@
</rule>
<rule match-type="regex">
<from>^/pvp2/redirect$</from>
- <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=Redirect&amp;%{query-string}</to>
+ <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=Redirect&amp;endpointtype=idp&amp;%{query-string}</to>
</rule>
<rule match-type="regex">
<from>^/pvp2/post$</from>
- <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=Post&amp;%{query-string}</to>
+ <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=Post&amp;endpointtype=idp&amp;%{query-string}</to>
</rule>
<rule match-type="regex">
<from>^/pvp2/Soap$</from>
- <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=Soap</to>
+ <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=Soap&amp;endpointtype=idp</to>
</rule>
<rule match-type="regex">
<from>^/pvp2/attributequery$</from>
- <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=AttributeQuery</to>
+ <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=AttributeQuery&amp;endpointtype=idp</to>
</rule>
+ <rule match-type="regex">
+ <from>^/pvp2/sp/redirect$</from>
+ <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=Redirect&amp;endpointtype=sp&amp;%{query-string}</to>
+ </rule>
+ <rule match-type="regex">
+ <from>^/pvp2/sp/post$</from>
+ <to type="forward">/dispatcher?mod=id_pvp2x&amp;action=Post&amp;endpointtype=sp&amp;%{query-string}</to>
+ </rule>
+
<rule match-type="regex">
<from>^/stork2/StartAuthentication$</from>
diff --git a/id/server/auth/src/main/webapp/WEB-INF/web.xml b/id/server/auth/src/main/webapp/WEB-INF/web.xml
index 0ef8a568c..d60d73fd2 100644
--- a/id/server/auth/src/main/webapp/WEB-INF/web.xml
+++ b/id/server/auth/src/main/webapp/WEB-INF/web.xml
@@ -35,8 +35,15 @@
<display-name>LogOut</display-name>
<description>SSO LogOut</description>
<servlet-class>at.gv.egovernment.moa.id.auth.servlet.LogOutServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
</servlet>
+
+ <servlet>
+ <servlet-name>IDPSLO</servlet-name>
+ <display-name>IDP-SLO</display-name>
+ <description>IDP Single LogOut Service</description>
+ <servlet-class>at.gv.egovernment.moa.id.auth.servlet.IDPSingleLogOutServlet</servlet-class>
+ </servlet>
+
<servlet>
<servlet-name>VerifyIdentityLink</servlet-name>
<display-name>VerifyIdentityLink</display-name>
@@ -171,6 +178,10 @@
<url-pattern>/LogOut</url-pattern>
</servlet-mapping>
<servlet-mapping>
+ <servlet-name>IDPSLO</servlet-name>
+ <url-pattern>/idpSingleLogout</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
<servlet-name>VerifyIdentityLink</servlet-name>
<url-pattern>/VerifyIdentityLink</url-pattern>
</servlet-mapping>
diff --git a/id/server/data/deploy/conf/moa-id/htmlTemplates/slo_template.html b/id/server/data/deploy/conf/moa-id/htmlTemplates/slo_template.html
new file mode 100644
index 000000000..a652855c4
--- /dev/null
+++ b/id/server/data/deploy/conf/moa-id/htmlTemplates/slo_template.html
@@ -0,0 +1,438 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+
+ <!-- MOA-ID 2.x BKUSelection Layout CSS -->
+ <style type="text/css">
+ @media screen and (min-width: 650px) {
+
+ body {
+ margin:0;
+ padding:0;
+ color : #000;
+ background-color : #fff;
+ text-align: center;
+ background-color: #6B7B8B;
+ }
+
+ #page {
+ display: block;
+ border: 2px solid rgb(0,0,0);
+ width: 650px;
+ height: 460px;
+ margin: 0 auto;
+ margin-top: 5%;
+ position: relative;
+ border-radius: 25px;
+ background: rgb(255,255,255);
+ }
+
+ #page1 {
+ text-align: center;
+ }
+
+ #main {
+ /* clear:both; */
+ position:relative;
+ margin: 0 auto;
+ width: 250px;
+ text-align: center;
+ }
+
+ .OA_header {
+ /* background-color: white;*/
+ font-size: 20pt;
+ margin-bottom: 25px;
+ margin-top: 25px;
+ }
+
+ #leftcontent {
+ /*float:left; */
+ width:250px;
+ margin-bottom: 25px;
+ text-align: left;
+ /*border: 1px solid rgb(0,0,0);*/
+ }
+
+ #leftcontent {
+ width: 300px;
+ margin-top: 30px;
+ }
+
+ h2#tabheader{
+ font-size: 1.1em;
+ padding-left: 2%;
+ padding-right: 2%;
+ position: relative;
+ }
+
+ .setAssertionButton_full {
+ background: #efefef;
+ cursor: pointer;
+ margin-top: 15px;
+ width: 100px;
+ height: 30px
+ }
+
+ #leftbutton {
+ width: 30%;
+ float:left;
+ margin-left: 40px;
+ }
+
+ #rightbutton {
+ width: 30%;
+ float:right;
+ margin-right: 45px;
+ text-align: right;
+ }
+
+ button {
+ height: 25px;
+ width: 75px;
+ margin-bottom: 10px;
+ }
+
+ #validation {
+ position: absolute;
+ bottom: 0px;
+ margin-left: 270px;
+ padding-bottom: 10px;
+ }
+
+ }
+
+ @media screen and (max-width: 205px) {
+ #localBKU p {
+ font-size: 0.6em;
+ }
+
+ #localBKU input {
+ font-size: 0.6em;
+ min-width: 60px;
+ /* max-width: 65px; */
+ min-height: 1.0em;
+ /* border-radius: 5px; */
+ }
+
+ }
+
+ @media screen and (max-width: 249px) and (min-width: 206px) {
+ #localBKU p {
+ font-size: 0.7em;
+ }
+
+ #localBKU input {
+ font-size: 0.7em;
+ min-width: 70px;
+ /* max-width: 75px; */
+ min-height: 0.95em;
+ /* border-radius: 6px; */
+ }
+
+ }
+
+ @media screen and (max-width: 299px) and (min-width: 250px) {
+ #localBKU p {
+ font-size: 0.9em;
+ }
+
+ #localBKU input {
+ font-size: 0.8em;
+ min-width: 70px;
+ /* max-width: 75px; */
+ /* border-radius: 6px; */
+ }
+
+ }
+
+ @media screen and (max-width: 399px) and (min-width: 300px) {
+ #localBKU p {
+ font-size: 0.9em;
+ }
+
+ #localBKU input {
+ font-size: 0.8em;
+ min-width: 70px;
+ /* max-width: 75px; */
+ /* border-radius: 6px; */
+ }
+
+ }
+
+ @media screen and (max-width: 649px) and (min-width: 400px) {
+ #localBKU p {
+ font-size: 0.9em;
+ }
+
+ #localBKU input {
+ font-size: 0.8em;
+ min-width: 70px;
+ /* max-width: 80px; */
+ /* border-radius: 6px; */
+ }
+
+ }
+
+
+
+ @media screen and (max-width: 649px) {
+
+ body {
+ margin:0;
+ padding:0;
+ color : #000;
+ text-align: center;
+ font-size: 100%;
+ background-color: #MAIN_BACKGOUNDCOLOR#;
+ }
+
+ #page {
+ visibility: hidden;
+ margin-top: 0%;
+ }
+
+ #page1 {
+ visibility: hidden;
+ }
+
+ #main {
+ visibility: hidden;
+ }
+
+ #validation {
+ visibility: hidden;
+ display: none;
+ }
+
+ .OA_header {
+ margin-bottom: 0px;
+ margin-top: 0px;
+ font-size: 0pt;
+ visibility: hidden;
+ }
+
+ #leftcontent {
+ visibility: visible;
+ margin-bottom: 0px;
+ text-align: left;
+ border:none;
+ vertical-align: middle;
+ min-height: 173px;
+ min-width: 204px;
+
+ }
+
+ input[type=button] {
+/* height: 11%; */
+ width: 70%;
+ }
+ }
+
+ * {
+ margin: 0;
+ padding: 0;
+ font-family: #FONTTYPE#;
+ }
+
+ #selectArea {
+ padding-top: 10px;
+ padding-bottom: 55px;
+ padding-left: 10px;
+ }
+
+ .setAssertionButton {
+ background: #efefef;
+ cursor: pointer;
+ margin-top: 15px;
+ width: 70px;
+ height: 25px;
+ }
+
+ #leftbutton {
+ width: 35%;
+ float:left;
+ margin-left: 15px;
+ }
+
+ #rightbutton {
+ width: 35%;
+ float:right;
+ margin-right: 25px;
+ text-align: right;
+ }
+
+/* input[type=button], .sendButton {
+ background: #BUTTON_BACKGROUNDCOLOR#;
+ color: #BUTTON_COLOR#;
+/* border:1px solid #000; */
+/* cursor: pointer;
+/* box-shadow: 3px 3px 3px #222222; */
+/* }
+
+/* button:hover, button:focus, button:active,
+ .sendButton:hover , .sendButton:focus, .sendButton:active,
+ #mandateCheckBox:hover, #mandateCheckBox:focus, #mandateCheckBox:active {
+ background: #BUTTON_BACKGROUNDCOLOR_FOCUS#;
+ color: #BUTTON_COLOR#;
+/* border:1px solid #000; */
+/* cursor: pointer;
+/* box-shadow: -1px -1px 3px #222222; */
+/* }
+
+*/
+ input {
+ /*border:1px solid #000;*/
+ cursor: pointer;
+ }
+
+ #localBKU input {
+/* color: #BUTTON_COLOR#; */
+ border: 0px;
+ display: inline-block;
+
+ }
+
+ #localBKU input:hover, #localBKU input:focus, #localBKU input:active {
+ text-decoration: underline;
+ }
+
+ #installJava, #BrowserNOK {
+ clear:both;
+ font-size:0.8em;
+ padding:4px;
+ }
+
+ .selectText{
+
+ }
+
+ .selectTextHeader{
+
+ }
+
+ .sendButton {
+ width: 30%;
+ margin-bottom: 1%;
+ }
+
+ #leftcontent a {
+ text-decoration:none;
+ color: #000;
+ /* display:block;*/
+ padding:4px;
+ }
+
+ #leftcontent a:hover, #leftcontent a:focus, #leftcontent a:active {
+ text-decoration:underline;
+ color: #000;
+ }
+
+ .infobutton {
+ background-color: #005a00;
+ color: white;
+ font-family: serif;
+ text-decoration: none;
+ padding-top: 2px;
+ padding-right: 4px;
+ padding-bottom: 2px;
+ padding-left: 4px;
+ font-weight: bold;
+ }
+
+ .hell {
+ background-color : #MAIN_BACKGOUNDCOLOR#;
+ color: #MAIN_COLOR#;
+ }
+
+ .dunkel {
+ background-color: #HEADER_BACKGROUNDCOLOR#;
+ color: #HEADER_COLOR#;
+ }
+
+ .main_header {
+ color: black;
+ font-size: 32pt;
+ position: absolute;
+ right: 10%;
+ top: 40px;
+
+ }
+
+ #alert {
+ margin: 100px 250px;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 14px;
+ font-weight: normal;
+ color: red;
+ }
+
+ .reqframe {
+ /*display: none;*/
+ visibility: hidden;
+
+ }
+
+ </style>
+
+
+ <title>Single LogOut Vorgang ... </title>
+</head>
+
+<body>
+ <noscript>
+ <p>
+ <strong>Note:</strong> Since your browser does not support
+ JavaScript, you must press the Continue button once to proceed.
+ </p>
+ </noscript>
+
+ <div id="page">
+ <div id="page1" class="case selected-case" role="main">
+ <h2 class="OA_header" role="heading">MOA-ID Single LogOut Information</h2>
+ <div id="main">
+ <div id="leftcontent" class="hell" role="application">
+
+ #if($errorMsg)
+ <div class="alert">
+ <p>$errorMsg</p>
+ </div>
+ #end
+
+ #if($successMsg)
+ <div>
+ <p>$successMsg</p>
+ </div>
+ #end
+
+ #if($redirectURLs)
+ <div>
+ <p>
+ Sie werden von allen Online-Applikationen abgemeldet. <br>
+ Dieser Vorgang kann einige Zeit in Anspruch nehmen.
+ </p>
+ </div>
+ #end
+
+ </div>
+ </div>
+ </div>
+ <div id="validation">
+ <a href="http://validator.w3.org/check?uri="> <img
+ style="border: 0; width: 88px; height: 31px"
+ src="$contextpath/img/valid-html5-blue.png" alt="HTML5 ist valide!" />
+ </a> <a href="http://jigsaw.w3.org/css-validator/"> <img
+ style="border: 0; width: 88px; height: 31px"
+ src="http://jigsaw.w3.org/css-validator/images/vcss-blue"
+ alt="CSS ist valide!" />
+ </a>
+ </div>
+ </div>
+
+
+ #foreach( $el in $redirectURLs )
+ <iframe src=$el class="reqframe"></iframe>
+ #end
+
+</body>
+</html> \ No newline at end of file
diff --git a/id/server/doc/conf/moa-id/htmlTemplates/slo_template.html b/id/server/doc/conf/moa-id/htmlTemplates/slo_template.html
new file mode 100644
index 000000000..a652855c4
--- /dev/null
+++ b/id/server/doc/conf/moa-id/htmlTemplates/slo_template.html
@@ -0,0 +1,438 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+
+ <!-- MOA-ID 2.x BKUSelection Layout CSS -->
+ <style type="text/css">
+ @media screen and (min-width: 650px) {
+
+ body {
+ margin:0;
+ padding:0;
+ color : #000;
+ background-color : #fff;
+ text-align: center;
+ background-color: #6B7B8B;
+ }
+
+ #page {
+ display: block;
+ border: 2px solid rgb(0,0,0);
+ width: 650px;
+ height: 460px;
+ margin: 0 auto;
+ margin-top: 5%;
+ position: relative;
+ border-radius: 25px;
+ background: rgb(255,255,255);
+ }
+
+ #page1 {
+ text-align: center;
+ }
+
+ #main {
+ /* clear:both; */
+ position:relative;
+ margin: 0 auto;
+ width: 250px;
+ text-align: center;
+ }
+
+ .OA_header {
+ /* background-color: white;*/
+ font-size: 20pt;
+ margin-bottom: 25px;
+ margin-top: 25px;
+ }
+
+ #leftcontent {
+ /*float:left; */
+ width:250px;
+ margin-bottom: 25px;
+ text-align: left;
+ /*border: 1px solid rgb(0,0,0);*/
+ }
+
+ #leftcontent {
+ width: 300px;
+ margin-top: 30px;
+ }
+
+ h2#tabheader{
+ font-size: 1.1em;
+ padding-left: 2%;
+ padding-right: 2%;
+ position: relative;
+ }
+
+ .setAssertionButton_full {
+ background: #efefef;
+ cursor: pointer;
+ margin-top: 15px;
+ width: 100px;
+ height: 30px
+ }
+
+ #leftbutton {
+ width: 30%;
+ float:left;
+ margin-left: 40px;
+ }
+
+ #rightbutton {
+ width: 30%;
+ float:right;
+ margin-right: 45px;
+ text-align: right;
+ }
+
+ button {
+ height: 25px;
+ width: 75px;
+ margin-bottom: 10px;
+ }
+
+ #validation {
+ position: absolute;
+ bottom: 0px;
+ margin-left: 270px;
+ padding-bottom: 10px;
+ }
+
+ }
+
+ @media screen and (max-width: 205px) {
+ #localBKU p {
+ font-size: 0.6em;
+ }
+
+ #localBKU input {
+ font-size: 0.6em;
+ min-width: 60px;
+ /* max-width: 65px; */
+ min-height: 1.0em;
+ /* border-radius: 5px; */
+ }
+
+ }
+
+ @media screen and (max-width: 249px) and (min-width: 206px) {
+ #localBKU p {
+ font-size: 0.7em;
+ }
+
+ #localBKU input {
+ font-size: 0.7em;
+ min-width: 70px;
+ /* max-width: 75px; */
+ min-height: 0.95em;
+ /* border-radius: 6px; */
+ }
+
+ }
+
+ @media screen and (max-width: 299px) and (min-width: 250px) {
+ #localBKU p {
+ font-size: 0.9em;
+ }
+
+ #localBKU input {
+ font-size: 0.8em;
+ min-width: 70px;
+ /* max-width: 75px; */
+ /* border-radius: 6px; */
+ }
+
+ }
+
+ @media screen and (max-width: 399px) and (min-width: 300px) {
+ #localBKU p {
+ font-size: 0.9em;
+ }
+
+ #localBKU input {
+ font-size: 0.8em;
+ min-width: 70px;
+ /* max-width: 75px; */
+ /* border-radius: 6px; */
+ }
+
+ }
+
+ @media screen and (max-width: 649px) and (min-width: 400px) {
+ #localBKU p {
+ font-size: 0.9em;
+ }
+
+ #localBKU input {
+ font-size: 0.8em;
+ min-width: 70px;
+ /* max-width: 80px; */
+ /* border-radius: 6px; */
+ }
+
+ }
+
+
+
+ @media screen and (max-width: 649px) {
+
+ body {
+ margin:0;
+ padding:0;
+ color : #000;
+ text-align: center;
+ font-size: 100%;
+ background-color: #MAIN_BACKGOUNDCOLOR#;
+ }
+
+ #page {
+ visibility: hidden;
+ margin-top: 0%;
+ }
+
+ #page1 {
+ visibility: hidden;
+ }
+
+ #main {
+ visibility: hidden;
+ }
+
+ #validation {
+ visibility: hidden;
+ display: none;
+ }
+
+ .OA_header {
+ margin-bottom: 0px;
+ margin-top: 0px;
+ font-size: 0pt;
+ visibility: hidden;
+ }
+
+ #leftcontent {
+ visibility: visible;
+ margin-bottom: 0px;
+ text-align: left;
+ border:none;
+ vertical-align: middle;
+ min-height: 173px;
+ min-width: 204px;
+
+ }
+
+ input[type=button] {
+/* height: 11%; */
+ width: 70%;
+ }
+ }
+
+ * {
+ margin: 0;
+ padding: 0;
+ font-family: #FONTTYPE#;
+ }
+
+ #selectArea {
+ padding-top: 10px;
+ padding-bottom: 55px;
+ padding-left: 10px;
+ }
+
+ .setAssertionButton {
+ background: #efefef;
+ cursor: pointer;
+ margin-top: 15px;
+ width: 70px;
+ height: 25px;
+ }
+
+ #leftbutton {
+ width: 35%;
+ float:left;
+ margin-left: 15px;
+ }
+
+ #rightbutton {
+ width: 35%;
+ float:right;
+ margin-right: 25px;
+ text-align: right;
+ }
+
+/* input[type=button], .sendButton {
+ background: #BUTTON_BACKGROUNDCOLOR#;
+ color: #BUTTON_COLOR#;
+/* border:1px solid #000; */
+/* cursor: pointer;
+/* box-shadow: 3px 3px 3px #222222; */
+/* }
+
+/* button:hover, button:focus, button:active,
+ .sendButton:hover , .sendButton:focus, .sendButton:active,
+ #mandateCheckBox:hover, #mandateCheckBox:focus, #mandateCheckBox:active {
+ background: #BUTTON_BACKGROUNDCOLOR_FOCUS#;
+ color: #BUTTON_COLOR#;
+/* border:1px solid #000; */
+/* cursor: pointer;
+/* box-shadow: -1px -1px 3px #222222; */
+/* }
+
+*/
+ input {
+ /*border:1px solid #000;*/
+ cursor: pointer;
+ }
+
+ #localBKU input {
+/* color: #BUTTON_COLOR#; */
+ border: 0px;
+ display: inline-block;
+
+ }
+
+ #localBKU input:hover, #localBKU input:focus, #localBKU input:active {
+ text-decoration: underline;
+ }
+
+ #installJava, #BrowserNOK {
+ clear:both;
+ font-size:0.8em;
+ padding:4px;
+ }
+
+ .selectText{
+
+ }
+
+ .selectTextHeader{
+
+ }
+
+ .sendButton {
+ width: 30%;
+ margin-bottom: 1%;
+ }
+
+ #leftcontent a {
+ text-decoration:none;
+ color: #000;
+ /* display:block;*/
+ padding:4px;
+ }
+
+ #leftcontent a:hover, #leftcontent a:focus, #leftcontent a:active {
+ text-decoration:underline;
+ color: #000;
+ }
+
+ .infobutton {
+ background-color: #005a00;
+ color: white;
+ font-family: serif;
+ text-decoration: none;
+ padding-top: 2px;
+ padding-right: 4px;
+ padding-bottom: 2px;
+ padding-left: 4px;
+ font-weight: bold;
+ }
+
+ .hell {
+ background-color : #MAIN_BACKGOUNDCOLOR#;
+ color: #MAIN_COLOR#;
+ }
+
+ .dunkel {
+ background-color: #HEADER_BACKGROUNDCOLOR#;
+ color: #HEADER_COLOR#;
+ }
+
+ .main_header {
+ color: black;
+ font-size: 32pt;
+ position: absolute;
+ right: 10%;
+ top: 40px;
+
+ }
+
+ #alert {
+ margin: 100px 250px;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 14px;
+ font-weight: normal;
+ color: red;
+ }
+
+ .reqframe {
+ /*display: none;*/
+ visibility: hidden;
+
+ }
+
+ </style>
+
+
+ <title>Single LogOut Vorgang ... </title>
+</head>
+
+<body>
+ <noscript>
+ <p>
+ <strong>Note:</strong> Since your browser does not support
+ JavaScript, you must press the Continue button once to proceed.
+ </p>
+ </noscript>
+
+ <div id="page">
+ <div id="page1" class="case selected-case" role="main">
+ <h2 class="OA_header" role="heading">MOA-ID Single LogOut Information</h2>
+ <div id="main">
+ <div id="leftcontent" class="hell" role="application">
+
+ #if($errorMsg)
+ <div class="alert">
+ <p>$errorMsg</p>
+ </div>
+ #end
+
+ #if($successMsg)
+ <div>
+ <p>$successMsg</p>
+ </div>
+ #end
+
+ #if($redirectURLs)
+ <div>
+ <p>
+ Sie werden von allen Online-Applikationen abgemeldet. <br>
+ Dieser Vorgang kann einige Zeit in Anspruch nehmen.
+ </p>
+ </div>
+ #end
+
+ </div>
+ </div>
+ </div>
+ <div id="validation">
+ <a href="http://validator.w3.org/check?uri="> <img
+ style="border: 0; width: 88px; height: 31px"
+ src="$contextpath/img/valid-html5-blue.png" alt="HTML5 ist valide!" />
+ </a> <a href="http://jigsaw.w3.org/css-validator/"> <img
+ style="border: 0; width: 88px; height: 31px"
+ src="http://jigsaw.w3.org/css-validator/images/vcss-blue"
+ alt="CSS ist valide!" />
+ </a>
+ </div>
+ </div>
+
+
+ #foreach( $el in $redirectURLs )
+ <iframe src=$el class="reqframe"></iframe>
+ #end
+
+</body>
+</html> \ No newline at end of file
diff --git a/id/server/idserverlib/pom.xml b/id/server/idserverlib/pom.xml
index 9bca6e0b6..5b2890658 100644
--- a/id/server/idserverlib/pom.xml
+++ b/id/server/idserverlib/pom.xml
@@ -241,12 +241,19 @@
</dependency> -->
<!-- <dependency> <groupId>at.gv.egovernment.moa.id</groupId> <artifactId>mandate-validate</artifactId>
<version>1.1</version> </dependency> -->
- <dependency>
+ <!--
+ <dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
+ -->
+ <dependency>
+ <groupId>eu.stork</groupId>
+ <artifactId>DocumentService</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
<!-- JSON JWT implementation -->
<dependency>
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java
index 6f83da367..e2c0c1f18 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java
@@ -33,6 +33,10 @@ public interface MOAIDAuthConstants {
public static final String PARAM_SSO = "SSO";
public static final String INTERFEDERATION_IDP = "interIDP";
+ public static final String PARAM_SLOSTATUS = "status";
+ public static final String SLOSTATUS_SUCCESS = "success";
+ public static final String SLOSTATUS_ERROR = "error";
+
/** servlet parameter &quot;sourceID&quot; */
public static final String PARAM_SOURCEID = "sourceID";
/** servlet parameter &quot;BKUSelectionTemplate&quot; */
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java
index 632227d79..c0e1dd3ca 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java
@@ -27,6 +27,8 @@ import iaik.x509.X509Certificate;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
import java.util.List;
import javax.naming.ldap.LdapName;
@@ -445,6 +447,9 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants {
authData.setSsoSession(true);
+ if (assertion.getConditions() != null && assertion.getConditions().getNotOnOrAfter() != null)
+ authData.setSsoSessionValidTo(assertion.getConditions().getNotOnOrAfter().toDate());
+
//only for SAML1
if (PVPConstants.STORK_QAA_1_4.equals(authData.getQAALevel()))
authData.setQualifiedCertificate(true);
@@ -454,7 +459,7 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants {
}
private static void buildAuthDataFormMOASession(AuthenticationData authData, AuthenticationSession session,
- IOAAuthParameters oaParam) throws BuildException {
+ IOAAuthParameters oaParam) throws BuildException, ConfigurationException {
String target = oaParam.getTarget();
@@ -465,7 +470,7 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants {
boolean businessService = oaParam.getBusinessService();
authData.setIssuer(session.getAuthURL());
-
+
//baseID or wbpk in case of BusinessService without SSO or BusinessService SSO
authData.setIdentificationValue(identityLink.getIdentificationValue());
authData.setIdentificationType(identityLink.getIdentificationType());
@@ -529,6 +534,19 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants {
authData.setSsoSession(AuthenticationSessionStoreage.isSSOSession(session.getSessionID()));
+ //set max. SSO session time
+ if (authData.isSsoSession()) {
+ long maxSSOSessionTime = AuthConfigurationProvider.getInstance().getTimeOuts().getMOASessionCreated().longValue() * 1000;
+ Date ssoSessionValidTo = new Date(session.getSessionCreated().getTime() + maxSSOSessionTime);
+ authData.setSsoSessionValidTo(ssoSessionValidTo);
+
+ } else {
+ //set valid to 5 min
+ Date ssoSessionValidTo = new Date(new Date().getTime() + 5 * 60 * 1000);
+ authData.setSsoSessionValidTo(ssoSessionValidTo);
+
+ }
+
/* TODO: Support SSO Mandate MODE!
* Insert functionality to translate mandates in case of SSO
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java
index c5ba49b2e..8726c1618 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java
@@ -42,6 +42,7 @@ import java.io.Serializable;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
+import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
@@ -78,6 +79,9 @@ public class AuthenticationSession implements Serializable {
* session ID
*/
private String sessionID;
+
+ private Date sessionCreated = null;
+
/**
* "Gesch&auml;ftsbereich" the online application belongs to; maybe <code>null</code> if the
* online application is a business application
@@ -344,8 +348,9 @@ public class AuthenticationSession implements Serializable {
* @param id
* Session ID
*/
- public AuthenticationSession(String id) {
+ public AuthenticationSession(String id, Date created) {
sessionID = id;
+ sessionCreated = created;
// setTimestampStart();
// infoboxValidators = new ArrayList();
}
@@ -1050,6 +1055,13 @@ public class AuthenticationSession implements Serializable {
this.storkAuthnResponse = storkAuthnResponse;
}
+ /**
+ * @return the sessionCreated
+ */
+ public Date getSessionCreated() {
+ return sessionCreated;
+ }
+
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/IDPSingleLogOutServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/IDPSingleLogOutServlet.java
new file mode 100644
index 000000000..ac4e56023
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/IDPSingleLogOutServlet.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.auth.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.velocity.VelocityContext;
+
+import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
+import at.gv.egovernment.moa.id.moduls.AuthenticationManager;
+import at.gv.egovernment.moa.id.moduls.SSOManager;
+import at.gv.egovernment.moa.id.storage.AssertionStorage;
+import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
+import at.gv.egovernment.moa.id.util.MOAIDMessageProvider;
+import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.MiscUtil;
+
+/**
+ * @author tlenz
+ *
+ */
+public class IDPSingleLogOutServlet extends AuthServlet {
+
+ private static final long serialVersionUID = -1301786072691577221L;
+
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ Logger.debug("receive IDP SingleLogOut Request");
+ SSOManager ssomanager = SSOManager.getInstance();
+ String ssoid = ssomanager.getSSOSessionID(req);
+
+ Object tokkenObj = req.getParameter(PARAM_SLOSTATUS);
+ String tokken = null;
+ String status = null;
+ if (tokkenObj != null && tokkenObj instanceof String) {
+ tokken = (String) tokkenObj;
+ try {
+ status = AssertionStorage.getInstance().get(tokken, String.class);
+ if (MiscUtil.isNotEmpty(status)) {
+ AssertionStorage.getInstance().remove(tokken);
+
+ }
+ VelocityContext context = new VelocityContext();
+ if (SLOSTATUS_SUCCESS.equals(status))
+ context.put("successMsg",
+ MOAIDMessageProvider.getInstance().getMessage("slo.00", null));
+ else
+ context.put("errorMsg",
+ MOAIDMessageProvider.getInstance().getMessage("slo.01", null));
+
+ ssomanager.printSingleLogOutInfo(context, resp);
+
+ } catch (MOAIDException e) {
+ handleErrorNoRedirect(e.getMessage(), e, req, resp);
+
+ } catch (MOADatabaseException e) {
+ handleErrorNoRedirect(e.getMessage(), e, req, resp);
+
+ }
+
+ }
+
+ if (MiscUtil.isNotEmpty(status)) {
+ //print status information
+
+
+ } else if (MiscUtil.isNotEmpty(ssoid)) {
+ if (ssomanager.isValidSSOSession(ssoid, null)) {
+
+ AuthenticationManager authmanager = AuthenticationManager.getInstance();
+ String moaSessionID = AuthenticationSessionStoreage.getMOASessionSSOID(ssoid);
+
+ if (MiscUtil.isNotEmpty(moaSessionID)) {
+ AuthenticationSession authSession;
+ try {
+ authSession = AuthenticationSessionStoreage
+ .getSession(moaSessionID);
+ if(authSession != null) {
+ authmanager.performSingleLogOut(req, resp, authSession, null);
+
+ }
+
+ } catch (MOADatabaseException e) {
+ //TODO: insert error Handling
+
+ } catch (MOAIDException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/LogOutServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/LogOutServlet.java
index 9b300578a..d7de985a4 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/LogOutServlet.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/LogOutServlet.java
@@ -109,7 +109,7 @@ public class LogOutServlet extends AuthServlet {
RequestStorage.removePendingRequest(AuthenticationSessionStoreage.getPendingRequestID(moasessionid));
- authmanager.logout(req, resp, moasessionid);
+ authmanager.performOnlyIDPLogOut(req, resp, moasessionid);
Logger.info("User with SSO Id " + ssoid + " is logged out and get redirect to "+ redirectUrl);
} else {
Logger.info("No active SSO session found. User is maybe logout already and get redirect to "+ redirectUrl);
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/RedirectServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/RedirectServlet.java
index 57755ca9f..6e1811c8b 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/RedirectServlet.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/RedirectServlet.java
@@ -46,6 +46,8 @@ public class RedirectServlet extends AuthServlet{
public static final String REDIRCT_PARAM_URL = "redirecturl";
+ private static final String DEFAULT_REDIRECTTARGET = "_parent";
+
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
@@ -55,16 +57,10 @@ public class RedirectServlet extends AuthServlet{
String target = req.getParameter(PARAM_TARGET);
String artifact = req.getParameter(PARAM_SAMLARTIFACT);
String interIDP = req.getParameter(INTERFEDERATION_IDP);
-
- if (MiscUtil.isEmpty(artifact) && MiscUtil.isEmpty(interIDP)) {
- resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Parameters not valid");
- return;
- }
-
Logger.debug("Check URL against online-applications");
OnlineApplication oa = null;
- String redirectTarget = "_parent";
+ String redirectTarget = DEFAULT_REDIRECTTARGET;
try {
oa = ConfigurationDBRead.getActiveOnlineApplication(url);
if (oa == null) {
@@ -118,10 +114,16 @@ public class RedirectServlet extends AuthServlet{
resp.addHeader("Location", url);
- } else {
- resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Parameters not valid");
- return;
+ } else {
+ Logger.debug("Redirect to " + url);
+ String redirect_form = RedirectFormBuilder.buildLoginForm(url, DEFAULT_REDIRECTTARGET);
+ resp.setContentType("text/html;charset=UTF-8");
+ resp.setStatus(HttpServletResponse.SC_OK);
+ PrintWriter out = new PrintWriter(resp.getOutputStream());
+ out.write(redirect_form);
+ out.flush();
+
}
}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/AuthenticationData.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/AuthenticationData.java
index 33e62d3d0..5685977bc 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/AuthenticationData.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/AuthenticationData.java
@@ -135,6 +135,7 @@ public class AuthenticationData implements IAuthData, Serializable {
private String QAALevel = null;
private boolean ssoSession = false;
+ private Date ssoSessionValidTo = null;
private boolean interfederatedSSOSession = false;
private String interfederatedIDP = null;
@@ -656,7 +657,23 @@ public class AuthenticationData implements IAuthData, Serializable {
public void setInterfederatedIDP(String interfederatedIDP) {
this.interfederatedIDP = interfederatedIDP;
}
+
+ /**
+ * @return the ssoSessionValidTo
+ */
+ public Date getSsoSessionValidTo() {
+ return ssoSessionValidTo;
+ }
+
+ /**
+ * @param ssoSessionValidTo the ssoSessionValidTo to set
+ */
+ public void setSsoSessionValidTo(Date ssoSessionValidTo) {
+ this.ssoSessionValidTo = ssoSessionValidTo;
+ }
+
+
}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/IAuthData.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/IAuthData.java
index 4ea81f134..7e421da0f 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/IAuthData.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/IAuthData.java
@@ -53,6 +53,8 @@ public interface IAuthData {
String getBPK();
String getBPKType();
+ Date getSsoSessionValidTo();
+
String getInterfederatedIDP();
String getIdentificationValue();
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java
index a0f3dd309..d1e04e107 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/SLOInformationContainer.java
@@ -24,13 +24,18 @@ package at.gv.egovernment.moa.id.data;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.metadata.SingleLogoutService;
+import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore;
import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration;
@@ -52,58 +57,93 @@ public class SLOInformationContainer implements Serializable {
public void parseActiveOAs(List<OASessionStore> dbOAs, String removeOAID) {
- activeFrontChannalOAs = new LinkedHashMap<String, SLOInformationImpl>();
- activeBackChannelOAs = new LinkedHashMap<String, SLOInformationImpl>();
+ if (activeBackChannelOAs == null)
+ activeBackChannelOAs = new LinkedHashMap<String, SLOInformationImpl>();
+ if (activeFrontChannalOAs == null)
+ activeFrontChannalOAs = new LinkedHashMap<String, SLOInformationImpl>();
if (dbOAs != null) {
for (OASessionStore oa : dbOAs) {
- //Actually only PVP 2.1 support Single LogOut
- if (PVP2XProtocol.NAME.equals(oa.getProtocolType()) &&
- !oa.getOaurlprefix().equals(removeOAID)) {
+ if (!oa.getOaurlprefix().equals(removeOAID)) {
+
+ //Actually only PVP 2.1 support Single LogOut
+ if (PVP2XProtocol.PATH.equals(oa.getProtocolType())) {
+ SingleLogoutService sloDesc;
+ try {
+ sloDesc = SingleLogOutBuilder.getRequestSLODescriptor(oa.getOaurlprefix());
+
+ if (sloDesc.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI))
+ activeBackChannelOAs.put(oa.getOaurlprefix(),
+ new SLOInformationImpl(
+ oa.getAssertionSessionID(),
+ oa.getUserNameID(),
+ oa.getUserNameIDFormat(),
+ oa.getProtocolType(),
+ sloDesc));
+
+ else
+ activeFrontChannalOAs.put(oa.getOaurlprefix(),
+ new SLOInformationImpl(
+ oa.getAssertionSessionID(),
+ oa.getUserNameID(),
+ oa.getUserNameIDFormat(),
+ oa.getProtocolType(),
+ sloDesc));
+
+ } catch (NOSLOServiceDescriptorException e) {
+ putFailedOA(oa.getOaurlprefix());
+
+ }
+
+ } else
+ putFailedOA(oa.getOaurlprefix());
+ }
+ }
+ }
+ }
+
+ /**
+ * @param dbIDPs
+ * @param value
+ */
+ public void parseActiveIDPs(List<InterfederationSessionStore> dbIDPs,
+ String removeIDP) {
+ if (activeBackChannelOAs == null)
+ activeBackChannelOAs = new LinkedHashMap<String, SLOInformationImpl>();
+ if (activeFrontChannalOAs == null)
+ activeFrontChannalOAs = new LinkedHashMap<String, SLOInformationImpl>();
+
+ if (dbIDPs != null) {
+ for (InterfederationSessionStore el : dbIDPs) {
+ if (!el.getIdpurlprefix().equals(removeIDP)) {
+
SingleLogoutService sloDesc;
try {
- sloDesc = SingleLogOutBuilder.getRequestSLODescriptor(oa.getOaurlprefix());
+ sloDesc = SingleLogOutBuilder.getRequestSLODescriptor(el.getIdpurlprefix());
- if (sloDesc.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI))
- activeBackChannelOAs.put(oa.getOaurlprefix(),
- new SLOInformationImpl(
- oa.getAssertionSessionID(),
- oa.getUserNameID(),
- oa.getUserNameIDFormat(),
- oa.getProtocolType(),
- sloDesc));
-
- else
- activeFrontChannalOAs.put(oa.getOaurlprefix(),
- new SLOInformationImpl(
- oa.getAssertionSessionID(),
- oa.getUserNameID(),
- oa.getUserNameIDFormat(),
- oa.getProtocolType(),
+ activeFrontChannalOAs.put(el.getIdpurlprefix(),
+ new SLOInformationImpl(
+ el.getSessionIndex(),
+ el.getUserNameID(),
+ NameID.TRANSIENT,
+ PVP2XProtocol.PATH,
sloDesc));
} catch (NOSLOServiceDescriptorException e) {
- putFailedOA(oa.getOaurlprefix());
+ putFailedOA(el.getIdpurlprefix());
}
-
- } else
- putFailedOA(oa.getOaurlprefix());
+ }
}
}
}
-
- public String getNextFrontChannelOA() {
- Iterator<String> interator = activeFrontChannalOAs.keySet().iterator();
- if (interator.hasNext())
- return interator.next();
-
- else
- return null;
+
+ public boolean hasFrontChannelOA() {
+ return !activeFrontChannalOAs.isEmpty();
}
- public SLOInformationImpl getFrontChannelOASessionDescripten(String oaID) {
- return activeFrontChannalOAs.get(oaID);
+ public Set<Entry<String, SLOInformationImpl>> getFrontChannelOASessionDescriptions() {
+ return activeFrontChannalOAs.entrySet();
}
public void removeFrontChannelOA(String oaID) {
@@ -147,9 +187,5 @@ public class SLOInformationContainer implements Serializable {
if (sloFailedOAs == null)
sloFailedOAs = new ArrayList<String>();
sloFailedOAs.add(oaID);
- }
-
-
-
-
+ }
}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java
index a3827ab73..0cbe749e0 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java
@@ -143,7 +143,7 @@ public class DispatcherServlet extends AuthServlet{
//remove MOASession
AuthenticationSession moaSession = AuthenticationSessionStoreage.getSessionWithPendingRequestID(pendingRequestID);
- AuthenticationManager.getInstance().logout(req, resp, moaSession.getSessionID());
+ AuthenticationManager.getInstance().performOnlyIDPLogOut(req, resp, moaSession.getSessionID());
return;
}
@@ -468,12 +468,12 @@ public class DispatcherServlet extends AuthServlet{
} catch (AuthenticationException e) {
Logger.warn("SSO Session information can not be stored -> SSO is not enabled!");
- authmanager.logout(req, resp, moasessionID);
+ authmanager.performOnlyIDPLogOut(req, resp, moasessionID);
isSSOSession = false;
}
} else {
- authmanager.logout(req, resp, moasessionID);
+ authmanager.performOnlyIDPLogOut(req, resp, moasessionID);
}
//Advanced statistic logging
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java
index 5a06b3ecd..a7eb51877 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java
@@ -24,13 +24,21 @@ package at.gv.egovernment.moa.id.moduls;
import java.io.IOException;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map.Entry;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
import org.joda.time.DateTime;
import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
import org.opensaml.common.xml.SAMLConstants;
@@ -38,6 +46,8 @@ import org.opensaml.saml2.core.AuthnContextClassRef;
import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration;
import org.opensaml.saml2.core.AuthnRequest;
import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.LogoutRequest;
+import org.opensaml.saml2.core.LogoutResponse;
import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.NameIDPolicy;
import org.opensaml.saml2.core.NameIDType;
@@ -45,12 +55,15 @@ import org.opensaml.saml2.core.RequestedAuthnContext;
import org.opensaml.saml2.core.Subject;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.SingleLogoutService;
import org.opensaml.saml2.metadata.SingleSignOnService;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.opensaml.security.MetadataCredentialResolver;
import org.opensaml.security.MetadataCredentialResolverFactory;
import org.opensaml.security.MetadataCriteria;
import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.opensaml.ws.soap.common.SOAPException;
+import org.opensaml.xml.XMLObject;
import org.opensaml.xml.security.CriteriaSet;
import org.opensaml.xml.security.SecurityException;
import org.opensaml.xml.security.criteria.EntityIDCriteria;
@@ -64,19 +77,32 @@ import at.gv.egovernment.moa.id.auth.exception.BuildException;
import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.auth.parser.StartAuthentificationParameterParser;
import at.gv.egovernment.moa.id.auth.servlet.AuthServlet;
+import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore;
+import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore;
import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
+import at.gv.egovernment.moa.id.config.ConfigurationException;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+import at.gv.egovernment.moa.id.data.SLOInformationContainer;
+import at.gv.egovernment.moa.id.data.SLOInformationImpl;
+import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.ArtifactBinding;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding;
+import at.gv.egovernment.moa.id.protocols.pvp2x.builder.SingleLogOutBuilder;
import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration;
+import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest;
import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider;
+import at.gv.egovernment.moa.id.protocols.pvp2x.utils.MOASAMLSOAPClient;
import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils;
+import at.gv.egovernment.moa.id.storage.AssertionStorage;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
+import at.gv.egovernment.moa.id.util.Random;
+import at.gv.egovernment.moa.id.util.VelocityProvider;
import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.MessageProvider;
import at.gv.egovernment.moa.util.MiscUtil;
import at.gv.egovernment.moa.util.StringUtils;
@@ -138,7 +164,149 @@ public class AuthenticationManager extends AuthServlet {
return false;
}
- public void logout(HttpServletRequest request,
+ public void performSingleLogOut(HttpServletRequest httpReq,
+ HttpServletResponse httpResp, AuthenticationSession session, PVPTargetConfiguration pvpReq) throws MOAIDException {
+ String pvpSLOIssuer = null;
+ String inboundRelayState = null;
+
+ if (pvpReq != null) {
+ MOARequest samlReq = (MOARequest) pvpReq.getRequest();
+ LogoutRequest logOutReq = (LogoutRequest) samlReq.getSamlRequest();
+ pvpSLOIssuer = logOutReq.getIssuer().getValue();
+ inboundRelayState = samlReq.getRelayState();
+ }
+
+ SSOManager ssomanager = SSOManager.getInstance();
+
+ //store active OAs to SLOContaine
+ List<OASessionStore> dbOAs = AuthenticationSessionStoreage.getAllActiveOAFromMOASession(session);
+ List<InterfederationSessionStore> dbIDPs = AuthenticationSessionStoreage.getAllActiveIDPsFromMOASession(session);
+ SLOInformationContainer sloContainer = new SLOInformationContainer();
+ sloContainer.setSloRequest(pvpReq);
+ sloContainer.parseActiveIDPs(dbIDPs, pvpSLOIssuer);
+ sloContainer.parseActiveOAs(dbOAs, pvpSLOIssuer);
+
+ //terminate MOASession
+ try {
+ AuthenticationSessionStoreage.destroySession(session.getSessionID());
+ ssomanager.deleteSSOSessionID(httpReq, httpResp);
+
+ } catch (MOADatabaseException e) {
+ Logger.warn("Delete MOASession FAILED.");
+ sloContainer.putFailedOA(AuthConfigurationProvider.getInstance().getPublicURLPrefix());
+
+ }
+
+ //start service provider back channel logout process
+ Iterator<String> nextOAInterator = sloContainer.getNextBackChannelOA();
+ while (nextOAInterator.hasNext()) {
+ SLOInformationImpl sloDescr = sloContainer.getBackChannelOASessionDescripten(nextOAInterator.next());
+ LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr);
+
+ try {
+ List<XMLObject> soapResp = MOASAMLSOAPClient.send(sloDescr.getServiceURL(), sloReq);
+
+ LogoutResponse sloResp = null;
+ for (XMLObject el : soapResp) {
+ if (el instanceof LogoutResponse)
+ sloResp = (LogoutResponse) el;
+ }
+
+ if (sloResp == null) {
+ Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue()
+ + " FAILED. NO LogOut response received.");
+ sloContainer.putFailedOA(sloReq.getIssuer().getValue());
+
+ }
+
+ SingleLogOutBuilder.checkStatusCode(sloContainer, sloResp);
+
+ } catch (SOAPException e) {
+ Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue()
+ + " FAILED.", e);
+ sloContainer.putFailedOA(sloReq.getIssuer().getValue());
+
+ } catch (SecurityException e) {
+ Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue()
+ + " FAILED.", e);
+ sloContainer.putFailedOA(sloReq.getIssuer().getValue());
+
+ }
+ }
+
+ //start service provider front channel logout process
+ try {
+ if (sloContainer.hasFrontChannelOA()) {
+ String relayState = Random.nextRandom();
+
+ Collection<Entry<String, SLOInformationImpl>> sloDescr = sloContainer.getFrontChannelOASessionDescriptions();
+ List<String> sloReqList = new ArrayList<String>();
+ for (Entry<String, SLOInformationImpl> el : sloDescr) {
+ LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(el.getValue());
+ try {
+ sloReqList.add(SingleLogOutBuilder.getFrontChannelSLOMessageURL(el.getValue().getServiceURL(), el.getValue().getBinding(),
+ sloReq, httpReq, httpResp, relayState));
+
+ } catch (Exception e) {
+ Logger.warn("Failed to build SLO request for OA:" + el.getKey());
+ sloContainer.putFailedOA(el.getKey());
+
+ }
+ }
+
+ AssertionStorage.getInstance().put(relayState, sloContainer);
+
+ VelocityContext context = new VelocityContext();
+ context.put("redirectURLs", sloReqList);
+ ssomanager.printSingleLogOutInfo(context, httpResp);
+
+
+ } else {
+ if (pvpReq != null) {
+ //send SLO response to SLO request issuer
+ SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq);
+ LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, pvpReq, sloContainer.getSloFailedOAs());
+ SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, inboundRelayState);
+
+ } else {
+ //print SLO information directly
+ VelocityContext context = new VelocityContext();
+ if (sloContainer.getSloFailedOAs() == null ||
+ sloContainer.getSloFailedOAs().size() == 0)
+ context.put("successMsg",
+ MessageProvider.getInstance().getMessage("slo.00", null));
+ else
+ context.put("errorMsg",
+ MessageProvider.getInstance().getMessage("slo.01", null));
+ ssomanager.printSingleLogOutInfo(context, httpResp);
+
+ }
+
+ }
+
+ } catch (MOADatabaseException e) {
+ Logger.error("MOA AssertionDatabase ERROR", e);
+ if (pvpReq != null) {
+ SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq);
+ LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq);
+ SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, inboundRelayState);
+
+ }else {
+ //print SLO information directly
+ VelocityContext context = new VelocityContext();
+ context.put("errorMsg",
+ MessageProvider.getInstance().getMessage("slo.01", null));
+ ssomanager.printSingleLogOutInfo(context, httpResp);
+
+ }
+
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public void performOnlyIDPLogOut(HttpServletRequest request,
HttpServletResponse response, String moaSessionID) {
Logger.info("Logout");
@@ -196,7 +364,8 @@ public class AuthenticationManager extends AuthServlet {
throws ServletException, IOException, MOAIDException {
String form = SendAssertionFormBuilder.buildForm(target.requestedModule(),
- target.requestedAction(), target.getRequestID(), oaParam, request.getContextPath());
+ target.requestedAction(), target.getRequestID(), oaParam,
+ AuthConfigurationProvider.getInstance().getPublicURLPrefix());
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = new PrintWriter(response.getOutputStream());
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java
index f4f89a4ba..a46b11c6e 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/SSOManager.java
@@ -22,17 +22,31 @@
*******************************************************************************/
package at.gv.egovernment.moa.id.moduls;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.net.URI;
import java.util.List;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.app.VelocityEngine;
import org.hibernate.Query;
import org.hibernate.Session;
import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.commons.db.MOASessionDBUtils;
import at.gv.egovernment.moa.id.commons.db.dao.session.AuthenticatedSessionStore;
import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore;
@@ -42,11 +56,15 @@ import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.Random;
+import at.gv.egovernment.moa.id.util.VelocityProvider;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.MiscUtil;
public class SSOManager {
+ private static final String HTMLTEMPLATESDIR = "htmlTemplates/";
+ private static final String HTMLTEMPLATEFULL = "slo_template.html";
+
private static final String SSOCOOKIE = "MOA_ID_SSO";
private static final String SSOINTERFEDERATION = "MOA_INTERFEDERATION_SSO";
@@ -267,6 +285,63 @@ public class SSOManager {
}
+ public void printSingleLogOutInfo(VelocityContext context, HttpServletResponse httpResp) throws MOAIDException {
+ try {
+ Logger.trace("Initialize VelocityEngine...");
+ VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine();
+
+ InputStream is = null;
+ try {
+ String rootconfigdir = AuthConfigurationProvider.getInstance().getRootConfigFileDir();
+ String pathLocation = rootconfigdir + HTMLTEMPLATESDIR + HTMLTEMPLATEFULL;
+ File file = new File(new URI(pathLocation));
+ is = new FileInputStream(file);
+ evaluateSLOTemplate(context, httpResp, is);
+
+ } catch (Exception e) {
+ Logger.warn("SLO Template is not found in configuration directory. Load template from project library ... ");
+
+ try {
+ String pathLocation = "resources/templates/" + HTMLTEMPLATEFULL;
+ is = Thread.currentThread()
+ .getContextClassLoader()
+ .getResourceAsStream(pathLocation);
+ evaluateSLOTemplate(context, httpResp, is);
+
+ } catch (Exception e1) {
+ Logger.error("Single LogOut form can not created.", e);
+ throw new MOAIDException("Create Single LogOut information FAILED.", null, e);
+ }
+
+ } finally {
+ if (is != null)
+ is.close();
+
+ }
+
+ } catch (Exception e) {
+ Logger.error("Single LogOut form can not created.", e);
+ throw new MOAIDException("Create Single LogOut information FAILED.", null, e);
+ }
+
+ }
+
+ private void evaluateSLOTemplate(VelocityContext context, HttpServletResponse httpResp, InputStream is) throws ConfigurationException, IOException {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is ));
+
+ //set default elements to velocity context
+ context.put("contextpath", AuthConfigurationProvider.getInstance().getPublicURLPrefix());
+
+ StringWriter writer = new StringWriter();
+ //velocityEngine.evaluate(context, writer, "SLO_Template", reader);
+ Velocity.evaluate(context, writer, "SLO Template", reader);
+
+
+ httpResp.setContentType("text/html;charset=UTF-8");
+ httpResp.getOutputStream().write(writer.toString().getBytes());
+
+ }
+
private String getValueFromCookie(HttpServletRequest httpReq, String cookieName) {
Cookie[] cookies = httpReq.getCookies();
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/opemsaml/MOAStringRedirectDeflateEncoder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/opemsaml/MOAStringRedirectDeflateEncoder.java
new file mode 100644
index 000000000..ece1a805d
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/opemsaml/MOAStringRedirectDeflateEncoder.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.opemsaml;
+
+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 at.gv.egovernment.moa.logging.Logger;
+
+/**
+ * @author tlenz
+ *
+ */
+public class MOAStringRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder {
+
+ private String redirectURL = null;
+
+ public void encode(MessageContext messageContext)
+ throws MessageEncodingException {
+ if (!(messageContext instanceof SAMLMessageContext)) {
+ Logger.error("Invalid message context type, this encoder only support SAMLMessageContext");
+ throw new MessageEncodingException(
+ "Invalid message context type, this encoder only support SAMLMessageContext");
+ }
+
+ 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/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java
index 01f7e18ba..fec8e3b98 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java
@@ -244,7 +244,7 @@ public class MetadataAction implements IAction {
postassertionConsumerService.setIndex(0);
postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
postassertionConsumerService.setLocation(PVPConfiguration
- .getInstance().getIDPSSOPostService());
+ .getInstance().getSPSSOPostService());
postassertionConsumerService.setIsDefault(true);
spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService);
@@ -253,7 +253,7 @@ public class MetadataAction implements IAction {
redirectassertionConsumerService.setIndex(1);
redirectassertionConsumerService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
redirectassertionConsumerService.setLocation(PVPConfiguration
- .getInstance().getIDPSSORedirectService());
+ .getInstance().getSPSSORedirectService());
spSSODescriptor.getAssertionConsumerServices().add(redirectassertionConsumerService);
@@ -265,14 +265,14 @@ public class MetadataAction implements IAction {
// postSLOService
// .setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
// spSSODescriptor.getSingleLogoutServices().add(postSLOService);
-//
-// SingleLogoutService redirectSLOService =
-// SAML2Utils.createSAMLObject(SingleLogoutService.class);
-// redirectSLOService.setLocation(PVPConfiguration
-// .getInstance().getIDPSSOPostService());
-// redirectSLOService
-// .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
-// spSSODescriptor.getSingleLogoutServices().add(redirectSLOService);
+
+ SingleLogoutService redirectSLOService =
+ SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ redirectSLOService.setLocation(PVPConfiguration
+ .getInstance().getSPSSORedirectService());
+ redirectSLOService
+ .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ spSSODescriptor.getSingleLogoutServices().add(redirectSLOService);
spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);
@@ -355,13 +355,13 @@ public class MetadataAction implements IAction {
redirectSingleSignOnService);
//add SLO descriptor
-// SingleLogoutService redirectSLOService =
-// SAML2Utils.createSAMLObject(SingleLogoutService.class);
-// redirectSLOService.setLocation(PVPConfiguration
-// .getInstance().getIDPSSOPostService());
-// redirectSLOService
-// .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
-// idpSSODescriptor.getSingleLogoutServices().add(redirectSLOService);
+ SingleLogoutService redirectSLOService =
+ SAML2Utils.createSAMLObject(SingleLogoutService.class);
+ redirectSLOService.setLocation(PVPConfiguration
+ .getInstance().getIDPSSORedirectService());
+ redirectSLOService
+ .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ idpSSODescriptor.getSingleLogoutServices().add(redirectSLOService);
}
/*if (PVPConfiguration.getInstance().getIDPResolveSOAPService() != null) {
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java
index d9ce6250a..7f8ea91bd 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java
@@ -111,6 +111,11 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants {
public static final String ATTRIBUTEQUERY = "AttributeQuery";
public static final String SINGLELOGOUT = "SingleLogOut";
+ public static final String ENDPOINT_IDP = "idp";
+ public static final String ENDPOINT_SP = "sp";
+
+ public static final String PARAMETER_ENDPOINT = "endpointtype";
+
private static List<IDecoder> decoder = new ArrayList<IDecoder>();
private static HashMap<String, IAction> actions = new HashMap<String, IAction>();
@@ -168,6 +173,23 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants {
return null;
}
+ private boolean isServiceProviderEndPointUsed(HttpServletRequest req) throws InvalidProtocolRequestException {
+ Object obj = req.getParameter(PARAMETER_ENDPOINT);
+ if (obj instanceof String) {
+ String param = (String) obj;
+ if (MiscUtil.isNotEmpty(param)) {
+ if (ENDPOINT_IDP.equals(param))
+ return false;
+
+ else if (ENDPOINT_SP.equals(param))
+ return true;
+ }
+ }
+
+ Logger.error("No valid PVP 2.1 entpoint descriptor");
+ throw new InvalidProtocolRequestException("pvp2.20", new Object[] {});
+ }
+
public PVP2XProtocol() {
super();
}
@@ -193,7 +215,8 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants {
return null;
}
try {
- InboundMessage msg = (InboundMessage) decoder.decode(request, response);
+
+ InboundMessage msg = (InboundMessage) decoder.decode(request, response, isServiceProviderEndPointUsed(request));
if (MiscUtil.isEmpty(msg.getEntityID())) {
throw new InvalidProtocolRequestException("pvp2.20", new Object[] {});
@@ -217,13 +240,14 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants {
else if (msg instanceof MOARequest &&
((MOARequest)msg).getSamlRequest() instanceof LogoutRequest)
- return preProcessLogOut(request, response, (MOARequest) msg);
+ return preProcessLogOut(request, response, msg);
- else if (msg instanceof MOARequest &&
- ((MOARequest)msg).getSamlRequest() instanceof LogoutResponse)
- return preProcessLogOut(request, response, (MOARequest) msg);
+ else if (msg instanceof MOAResponse &&
+ ((MOAResponse)msg).getResponse() instanceof LogoutResponse)
+ return preProcessLogOut(request, response, msg);
- else if (msg instanceof MOAResponse) {
+ else if (msg instanceof MOAResponse &&
+ ((MOAResponse)msg).getResponse() instanceof Response) {
//load service provider AuthRequest from session
IRequest obj = RequestStorage.getPendingRequest(msg.getRelayState());
@@ -420,20 +444,22 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants {
* @throws MOAIDException
*/
private IRequest preProcessLogOut(HttpServletRequest request,
- HttpServletResponse response, MOARequest msg) throws MOAIDException {
+ HttpServletResponse response, InboundMessage inMsg) throws MOAIDException {
PVPTargetConfiguration config = new PVPTargetConfiguration();
- if (((MOARequest)msg).getSamlRequest() instanceof LogoutRequest) {
+ MOARequest msg;
+ if (inMsg instanceof MOARequest &&
+ ((MOARequest)inMsg).getSamlRequest() instanceof LogoutRequest) {
//preProcess single logout request from service provider
-
+
+ msg = (MOARequest) inMsg;
+
EntityDescriptor metadata = msg.getEntityMetadata();
if(metadata == null) {
throw new NoMetadataInformationException();
}
-
-
String oaURL = metadata.getEntityID();
oaURL = StringEscapeUtils.escapeHtml(oaURL);
@@ -443,10 +469,11 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants {
config.setBinding(msg.getRequestBinding());
- } else if (((MOARequest)msg).getSamlRequest() instanceof LogoutResponse) {
+ } else if (inMsg instanceof MOAResponse &&
+ ((MOAResponse)inMsg).getResponse() instanceof LogoutResponse) {
//preProcess single logour response from service provider
- LogoutResponse resp = (LogoutResponse) (((MOARequest)msg).getSamlRequest());
+ LogoutResponse resp = (LogoutResponse) (((MOAResponse)inMsg).getResponse());
Logger.debug("PreProcess SLO Response from " + resp.getIssuer());
@@ -458,14 +485,14 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants {
}
//TODO: check if relayState exists
- msg.getRelayState();
+ inMsg.getRelayState();
} else
throw new MOAIDException("Unsupported request", new Object[] {});
- config.setRequest(msg);
+ config.setRequest(inMsg);
config.setAction(SINGLELOGOUT);
return config;
}
@@ -624,7 +651,7 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants {
*/
private MOAResponse preProcessAuthResponse(MOAResponse msg) {
Logger.debug("Start PVP21 assertion processing... ");
- Response samlResp = msg.getResponse();
+ Response samlResp = (Response) msg.getResponse();
try {
if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java
index c67d10ab7..46e02d048 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java
@@ -22,26 +22,51 @@
*/
package at.gv.egovernment.moa.id.protocols.pvp2x;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang.SerializationUtils;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.core.LogoutRequest;
import org.opensaml.saml2.core.LogoutResponse;
import org.opensaml.saml2.core.RequestAbstractType;
import org.opensaml.saml2.core.Status;
import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.core.StatusResponseType;
import org.opensaml.saml2.metadata.SingleLogoutService;
+import org.opensaml.saml2.metadata.impl.SingleLogoutServiceBuilder;
import org.opensaml.ws.message.encoder.MessageEncodingException;
import org.opensaml.ws.soap.common.SOAPException;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.x509.X509Credential;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.auth.servlet.RedirectServlet;
+import at.gv.egovernment.moa.id.commons.db.MOASessionDBUtils;
+import at.gv.egovernment.moa.id.commons.db.dao.session.AssertionStore;
+import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore;
import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore;
import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
@@ -49,9 +74,11 @@ import at.gv.egovernment.moa.id.data.IAuthData;
import at.gv.egovernment.moa.id.data.SLOInformationContainer;
import at.gv.egovernment.moa.id.data.SLOInformationImpl;
import at.gv.egovernment.moa.id.data.SLOInformationInterface;
+import at.gv.egovernment.moa.id.moduls.AuthenticationManager;
import at.gv.egovernment.moa.id.moduls.IAction;
import at.gv.egovernment.moa.id.moduls.IRequest;
import at.gv.egovernment.moa.id.moduls.SSOManager;
+import at.gv.egovernment.moa.id.opemsaml.MOAStringRedirectDeflateEncoder;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding;
@@ -59,12 +86,17 @@ import at.gv.egovernment.moa.id.protocols.pvp2x.builder.SingleLogOutBuilder;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.SLOException;
import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest;
+import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOAResponse;
+import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider;
import at.gv.egovernment.moa.id.protocols.pvp2x.utils.MOASAMLSOAPClient;
import at.gv.egovernment.moa.id.storage.AssertionStorage;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.Random;
+import at.gv.egovernment.moa.id.util.VelocityProvider;
import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.MessageProvider;
import at.gv.egovernment.moa.util.MiscUtil;
+import at.gv.egovernment.moa.util.URLEncoder;
/**
* @author tlenz
@@ -82,16 +114,16 @@ public class SingleLogOutAction implements IAction {
PVPTargetConfiguration pvpReq = (PVPTargetConfiguration) req;
- if (pvpReq.getRequest() instanceof MOARequest) {
+ if (pvpReq.getRequest() instanceof MOARequest &&
+ ((MOARequest)pvpReq.getRequest()).getSamlRequest() instanceof LogoutRequest) {
+ Logger.debug("Process Single LogOut request");
MOARequest samlReq = (MOARequest) pvpReq.getRequest();
- if (samlReq.getSamlRequest() instanceof LogoutRequest) {
- Logger.debug("Process Single LogOut request");
- LogoutRequest logOutReq = (LogoutRequest) samlReq.getSamlRequest();
+ LogoutRequest logOutReq = (LogoutRequest) samlReq.getSamlRequest();
- AuthenticationSession session =
- AuthenticationSessionStoreage.searchMOASessionWithNameIDandOAID(
- logOutReq.getIssuer().getValue(),
- logOutReq.getNameID().getValue());
+ AuthenticationSession session =
+ AuthenticationSessionStoreage.searchMOASessionWithNameIDandOAID(
+ logOutReq.getIssuer().getValue(),
+ logOutReq.getNameID().getValue());
if (session == null) {
Logger.warn("Can not find active SSO session with nameID "
@@ -104,7 +136,7 @@ public class SingleLogOutAction implements IAction {
Logger.warn("Can not find active Session. Single LogOut not possible!");
SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq);
LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq);
- sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState());
+ SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState());
return null;
} else {
@@ -116,101 +148,150 @@ public class SingleLogOutAction implements IAction {
Logger.warn("Can not find active Session. Single LogOut not possible!");
SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq);
LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq);
- sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState());
+ SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState());
return null;
}
}
}
- //store active OAs to SLOContaine
- List<OASessionStore> dbOAs = AuthenticationSessionStoreage.getAllActiveOAFromMOASession(session);
- SLOInformationContainer sloContainer = new SLOInformationContainer();
- sloContainer.setSloRequest(pvpReq);
- sloContainer.parseActiveOAs(dbOAs, logOutReq.getIssuer().getValue());
-
- //terminate MOASession
- try {
- AuthenticationSessionStoreage.destroySession(session.getSessionID());
-
- } catch (MOADatabaseException e) {
- Logger.warn("Delete MOASession FAILED.");
- sloContainer.putFailedOA(AuthConfigurationProvider.getInstance().getPublicURLPrefix());
-
- }
-
- //start service provider back channel logout process
- Iterator<String> nextOAInterator = sloContainer.getNextBackChannelOA();
- while (nextOAInterator.hasNext()) {
- SLOInformationImpl sloDescr = sloContainer.getBackChannelOASessionDescripten(nextOAInterator.next());
- LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr);
-
- try {
- List<XMLObject> soapResp = MOASAMLSOAPClient.send(sloDescr.getServiceURL(), sloReq);
-
- LogoutResponse sloResp = null;
- for (XMLObject el : soapResp) {
- if (el instanceof LogoutResponse)
- sloResp = (LogoutResponse) el;
- }
-
- if (sloResp == null) {
- Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue()
- + " FAILED. NO LogOut response received.");
- sloContainer.putFailedOA(sloReq.getIssuer().getValue());
+ AuthenticationManager authManager = AuthenticationManager.getInstance();
+ authManager.performSingleLogOut(httpReq, httpResp, session, pvpReq);
- }
-
- checkStatusCode(sloContainer, sloResp);
-
- } catch (SOAPException e) {
- Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue()
- + " FAILED.", e);
- sloContainer.putFailedOA(sloReq.getIssuer().getValue());
-
- } catch (SecurityException e) {
- Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue()
- + " FAILED.", e);
- sloContainer.putFailedOA(sloReq.getIssuer().getValue());
-
- }
- }
-
- //start service provider front channel logout process
- try {
- doFrontChannelLogOut(sloContainer, httpReq, httpResp);
-
- } catch (MOADatabaseException e) {
- Logger.error("MOA AssertionDatabase ERROR", e);
- SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq);
- LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq);
- sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState());
- return null;
-
- }
-
- } else if (samlReq.getSamlRequest() instanceof LogoutResponse) {
+ } else if (pvpReq.getRequest() instanceof MOAResponse &&
+ ((MOAResponse)pvpReq.getRequest()).getResponse() instanceof LogoutResponse) {
Logger.debug("Process Single LogOut response");
- LogoutResponse logOutResp = (LogoutResponse) samlReq.getSamlRequest();
+ LogoutResponse logOutResp = (LogoutResponse) ((MOAResponse)pvpReq.getRequest()).getResponse();
- try {
- if (MiscUtil.isEmpty(samlReq.getRelayState())) {
+ try {
+ String relayState = pvpReq.getRequest().getRelayState();
+ if (MiscUtil.isEmpty(relayState)) {
Logger.warn("SLO Response from " + logOutResp.getIssuer().getValue()
+ " has no SAML2 RelayState.");
throw new SLOException("pvp2.19", null);
}
- SLOInformationContainer sloContainer =
- AssertionStorage.getInstance().get(samlReq.getRelayState(), SLOInformationContainer.class);
- checkStatusCode(sloContainer, logOutResp);
- sloContainer.removeFrontChannelOA(logOutResp.getIssuer().getValue());
- doFrontChannelLogOut(sloContainer, httpReq, httpResp);
+ Session session = MOASessionDBUtils.getCurrentSession();
+ boolean storageSuccess = false;
+ int counter = 0;
+
+ //TODO: add counter to prevent deadlock
+
+ while (!storageSuccess) {
+ Transaction tx = session.beginTransaction();
+
+ List result;
+ Query query = session.getNamedQuery("getAssertionWithArtifact");
+ query.setParameter("artifact", relayState);
+ result = query.list();
+ Logger.trace("Found entries: " + result.size());
+
+ //Assertion requires an unique artifact
+ if (result.size() != 1) {
+ Logger.trace("No entries found.");
+ throw new MOADatabaseException("No sessioninformation found with this ID");
+ }
+
+ AssertionStore element = (AssertionStore) result.get(0);
+ Object data = SerializationUtils.deserialize(element.getAssertion());
+
+ if (data instanceof SLOInformationContainer) {
+ SLOInformationContainer sloContainer = (SLOInformationContainer) data;
+
+ //check status
+ SingleLogOutBuilder.checkStatusCode(sloContainer, logOutResp);
+
+ if (sloContainer.hasFrontChannelOA()) {
+ try {
+ //some response are open
+ byte[] serializedSLOContainer = SerializationUtils.serialize((Serializable) sloContainer);
+ element.setAssertion(serializedSLOContainer);
+ element.setType(sloContainer.getClass().getName());
+
+ session.saveOrUpdate(element);
+ tx.commit();
+
+ //sloContainer could be stored to database
+ storageSuccess = true;
+
+ } catch(HibernateException e) {
+ tx.rollback();
+
+ counter++;
+ Logger.debug("SLOContainter could not stored to database. Wait some time and restart storage process ... ");
+ java.util.Random rand = new java.util.Random();
+
+ try {
+ Thread.sleep(rand.nextInt(20)*10);
+
+ } catch (InterruptedException e1) {
+ Logger.warn("Thread could not stopped. ReStart storage process immediately", e1);
+ }
+ }
+
+ } else {
+ //last response received.
+ try {
+ session.delete(element);
+ tx.commit();
+
+ } catch(HibernateException e) {
+ tx.rollback();
+ Logger.error("SLOContainter could not deleted from database. ");
+
+ }
+
+ storageSuccess = true;
+ String redirectURL = null;
+ if (sloContainer.getSloRequest() != null) {
+ //send SLO response to SLO request issuer
+ SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(sloContainer.getSloRequest());
+ LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, sloContainer.getSloRequest(), sloContainer.getSloFailedOAs());
+ redirectURL = SingleLogOutBuilder.getFrontChannelSLOMessageURL(sloService, message, httpReq, httpResp, sloContainer.getSloRequest().getRequest().getRelayState());
+
+ } else {
+ //print SLO information directly
+ redirectURL = AuthConfigurationProvider.getInstance().getPublicURLPrefix() + "/idpSingleLogout";
+
+ String artifact = Random.nextRandom();
+
+ String statusCode = null;
+ if (sloContainer.getSloFailedOAs() == null ||
+ sloContainer.getSloFailedOAs().size() == 0)
+ statusCode = SLOSTATUS_SUCCESS;
+ else
+ statusCode = SLOSTATUS_ERROR;
+
+ AssertionStorage.getInstance().put(artifact, statusCode);
+ redirectURL = addURLParameter(redirectURL, PARAM_SLOSTATUS, artifact);
+
+ }
+ //redirect to Redirect Servlet
+ String url = AuthConfigurationProvider.getInstance().getPublicURLPrefix() + "/RedirectServlet";
+ url = addURLParameter(url, RedirectServlet.REDIRCT_PARAM_URL, URLEncoder.encode(redirectURL, "UTF-8"));
+ url = httpResp.encodeRedirectURL(url);
+
+ httpResp.setContentType("text/html");
+ httpResp.setStatus(302);
+ httpResp.addHeader("Location", url);
+
+ }
+ } else {
+ Logger.warn("Sessioninformation Cast-Exception by using Artifact=" + relayState);
+ throw new MOADatabaseException("Sessioninformation Cast-Exception");
+
+ }
+ }
} catch (MOADatabaseException e) {
Logger.error("MOA AssertionDatabase ERROR", e);
throw new SLOException("pvp2.19", null);
+ } catch (UnsupportedEncodingException e) {
+ Logger.error("Finale SLO redirct not possible.", e);
+ throw new AuthenticationException("pvp2.13", new Object[]{});
+
}
} else {
@@ -218,13 +299,7 @@ public class SingleLogOutAction implements IAction {
throw new MOAIDException("pvp2.13", null);
}
-
- } else {
- Logger.error("Process SingleLogOutAction but request is NOT of type MOARequest.");
- throw new MOAIDException("pvp2.13", null);
-
- }
-
+
return null;
}
@@ -245,117 +320,12 @@ public class SingleLogOutAction implements IAction {
return PVP2XProtocol.SINGLELOGOUT;
}
- private void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) {
- Status status = logOutResp.getStatus();
- if (!status.getStatusCode().equals(StatusCode.SUCCESS_URI)) {
- Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue()
- + " FAILED. (ResponseCode: " + status.getStatusCode().getValue()
- + " Message: " + status.getStatusMessage().getMessage() + ")");
- sloContainer.putFailedOA(logOutResp.getIssuer().getValue());
-
- } else
- Logger.debug("Single LogOut for OA " + logOutResp.getIssuer().getValue() + " SUCCESS");
-
+ protected static String addURLParameter(String url, String paramname,
+ String paramvalue) {
+ String param = paramname + "=" + paramvalue;
+ if (url.indexOf("?") < 0)
+ return url + "?" + param;
+ else
+ return url + "&" + param;
}
-
- private void doFrontChannelLogOut(SLOInformationContainer sloContainer,
- HttpServletRequest httpReq, HttpServletResponse httpResp
- ) throws MOAIDException, MOADatabaseException {
- String nextOA = sloContainer.getNextFrontChannelOA();
- if (MiscUtil.isNotEmpty(nextOA)) {
- SLOInformationImpl sloDescr = sloContainer.getFrontChannelOASessionDescripten(nextOA);
- LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr);
- String relayState = Random.nextRandom();
-
- AssertionStorage.getInstance().put(relayState, sloContainer);
-
- sendFrontChannelSLOMessage(sloDescr.getServiceURL(), sloDescr.getBinding(),
- sloReq, httpReq, httpResp, relayState);
-
- } else {
- //send SLO response to SLO request issuer
- PVPTargetConfiguration pvpReq = sloContainer.getSloRequest();
- MOARequest samlReq = (MOARequest) pvpReq.getRequest();
- SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq);
- LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, pvpReq, sloContainer.getSloFailedOAs());
- sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState());
-
- }
- }
-
- /**
- * @param serviceURL
- * @param binding
- * @param sloReq
- * @param httpReq
- * @param httpResp
- * @param relayState
- */
- private void sendFrontChannelSLOMessage(String serviceURL, String bindingType,
- RequestAbstractType sloReq, HttpServletRequest httpReq,
- HttpServletResponse httpResp, String relayState) throws MOAIDException {
- IEncoder binding = null;
- if (bindingType.equals(
- SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
- binding = new RedirectBinding();
-
- } else if (bindingType.equals(
- SAMLConstants.SAML2_POST_BINDING_URI)) {
- binding = new PostBinding();
-
- }
-
- if (binding == null) {
- throw new BindingNotSupportedException(bindingType);
- }
-
- try {
- binding.encodeRequest(httpReq, httpResp, sloReq,
- serviceURL, relayState);
-
- } catch (MessageEncodingException e) {
- Logger.error("Message Encoding exception", e);
- throw new MOAIDException("pvp2.01", null, e);
-
- } catch (SecurityException e) {
- Logger.error("Security exception", e);
- throw new MOAIDException("pvp2.01", null, e);
-
- }
-
- }
-
- private void sendFrontChannelSLOMessage(SingleLogoutService consumerService,
- LogoutResponse sloResp, HttpServletRequest req, HttpServletResponse resp,
- String relayState) throws MOAIDException {
- IEncoder binding = null;
- if (consumerService.getBinding().equals(
- SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
- binding = new RedirectBinding();
-
- } else if (consumerService.getBinding().equals(
- SAMLConstants.SAML2_POST_BINDING_URI)) {
- binding = new PostBinding();
-
- }
-
- if (binding == null) {
- throw new BindingNotSupportedException(consumerService.getBinding());
- }
-
- try {
- binding.encodeRespone(req, resp, sloResp,
- consumerService.getLocation(), relayState);
-
- } catch (MessageEncodingException e) {
- Logger.error("Message Encoding exception", e);
- throw new MOAIDException("pvp2.01", null, e);
-
- } catch (SecurityException e) {
- Logger.error("Security exception", e);
- throw new MOAIDException("pvp2.01", null, e);
-
- }
-
- }
}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java
index 8691667f0..4d353ffcd 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java
@@ -102,7 +102,7 @@ public class ArtifactBinding implements IDecoder, IEncoder {
}
public InboundMessageInterface decode(HttpServletRequest req,
- HttpServletResponse resp) throws MessageDecodingException,
+ HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException,
SecurityException {
return null;
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java
index fb17c02b8..6619876dc 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java
@@ -33,7 +33,7 @@ import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessageInterface
public interface IDecoder {
public InboundMessageInterface decode(HttpServletRequest req,
- HttpServletResponse resp)
+ HttpServletResponse resp, boolean isSPEndPoint)
throws MessageDecodingException, SecurityException, PVP2Exception;
public boolean handleDecode(String action, HttpServletRequest req);
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java
index a2fe5c01b..7f73b1ed7 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java
@@ -139,7 +139,7 @@ public class PostBinding implements IDecoder, IEncoder {
}
public InboundMessageInterface decode(HttpServletRequest req,
- HttpServletResponse resp) throws MessageDecodingException,
+ HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException,
SecurityException {
HTTPPostDecoder decode = new HTTPPostDecoder(new BasicParserPool());
@@ -152,39 +152,38 @@ public class PostBinding implements IDecoder, IEncoder {
} catch (ConfigurationException e) {
throw new SecurityException(e);
}
-
- decode.decode(messageContext);
-
+
messageContext.setMetadataProvider(MOAMetadataProvider.getInstance());
- InboundMessage msg = null;
+ //set metadata descriptor type
+ if (isSPEndPoint)
+ messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+ else
+ messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
- if (messageContext.getInboundMessage() instanceof RequestAbstractType) {
- messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
-
+ decode.decode(messageContext);
+
+ InboundMessage msg = null;
+ if (messageContext.getInboundMessage() instanceof RequestAbstractType) {
RequestAbstractType inboundMessage = (RequestAbstractType) messageContext
.getInboundMessage();
msg = new MOARequest(inboundMessage, getSAML2BindingName());
- } else if (messageContext.getInboundMessage() instanceof Response){
- messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
-
- Response inboundMessage = (Response) messageContext.getInboundMessage();
+ } else if (messageContext.getInboundMessage() instanceof StatusResponseType){
+ StatusResponseType inboundMessage = (StatusResponseType) messageContext.getInboundMessage();
msg = new MOAResponse(inboundMessage);
} else
//create empty container if request type is unknown
msg = new InboundMessage();
-
- msg.setVerified(false);
-
- decode.decode(messageContext);
+
if (messageContext.getPeerEntityMetadata() != null)
msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID());
else
Logger.info("No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer());
-
+
+ msg.setVerified(false);
msg.setRelayState(messageContext.getRelayState());
return msg;
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java
index 8fba6cde0..26f6f3a62 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java
@@ -129,7 +129,7 @@ public class RedirectBinding implements IDecoder, IEncoder {
}
public InboundMessageInterface decode(HttpServletRequest req,
- HttpServletResponse resp) throws MessageDecodingException,
+ HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException,
SecurityException {
HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder(
@@ -146,8 +146,6 @@ public class RedirectBinding implements IDecoder, IEncoder {
BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
messageContext
.setInboundMessageTransport(new HttpServletRequestAdapter(req));
-
- decode.decode(messageContext);
messageContext.setMetadataProvider(MOAMetadataProvider.getInstance());
@@ -161,36 +159,39 @@ public class RedirectBinding implements IDecoder, IEncoder {
policy);
messageContext.setSecurityPolicyResolver(resolver);
- InboundMessage msg = null;
-
- if (messageContext.getInboundMessage() instanceof RequestAbstractType) {
+ //set metadata descriptor type
+ if (isSPEndPoint)
+ messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+ else
messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
-
+
+ decode.decode(messageContext);
+
+ //check signature
+ signatureRule.evaluate(messageContext);
+
+ InboundMessage msg = null;
+ if (messageContext.getInboundMessage() instanceof RequestAbstractType) {
RequestAbstractType inboundMessage = (RequestAbstractType) messageContext
.getInboundMessage();
msg = new MOARequest(inboundMessage, getSAML2BindingName());
- } else if (messageContext.getInboundMessage() instanceof Response){
- messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
-
- Response inboundMessage = (Response) messageContext.getInboundMessage();
+ } else if (messageContext.getInboundMessage() instanceof StatusResponseType){
+ StatusResponseType inboundMessage = (StatusResponseType) messageContext.getInboundMessage();
msg = new MOAResponse(inboundMessage);
} else
//create empty container if request type is unknown
msg = new InboundMessage();
- signatureRule.evaluate(messageContext);
- msg.setVerified(true);
-
- decode.decode(messageContext);
if (messageContext.getPeerEntityMetadata() != null)
msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID());
else
Logger.info("No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer());
+ msg.setVerified(true);
msg.setRelayState(messageContext.getRelayState());
return msg;
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java
index 75332cfea..f0eafe272 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java
@@ -59,7 +59,7 @@ import at.gv.egovernment.moa.logging.Logger;
public class SoapBinding implements IDecoder, IEncoder {
public InboundMessageInterface decode(HttpServletRequest req,
- HttpServletResponse resp) throws MessageDecodingException,
+ HttpServletResponse resp, boolean isSPEndPoint) throws MessageDecodingException,
SecurityException, PVP2Exception {
HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder(new BasicParserPool());
BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext =
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java
index 04d374e93..eeb1dd104 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java
@@ -22,30 +22,53 @@
*/
package at.gv.egovernment.moa.id.protocols.pvp2x.builder;
+import java.security.NoSuchAlgorithmException;
import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
import org.joda.time.DateTime;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.core.Issuer;
import org.opensaml.saml2.core.LogoutRequest;
import org.opensaml.saml2.core.LogoutResponse;
import org.opensaml.saml2.core.NameID;
+import org.opensaml.saml2.core.RequestAbstractType;
import org.opensaml.saml2.core.Status;
import org.opensaml.saml2.core.StatusCode;
import org.opensaml.saml2.core.StatusMessage;
+import org.opensaml.saml2.core.StatusResponseType;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.SSODescriptor;
import org.opensaml.saml2.metadata.SingleLogoutService;
+import org.opensaml.saml2.metadata.impl.SingleLogoutServiceBuilder;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
+import org.opensaml.ws.message.encoder.MessageEncodingException;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.x509.X509Credential;
+import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.config.ConfigurationException;
+import at.gv.egovernment.moa.id.data.SLOInformationContainer;
import at.gv.egovernment.moa.id.data.SLOInformationImpl;
+import at.gv.egovernment.moa.id.opemsaml.MOAStringRedirectDeflateEncoder;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration;
+import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder;
+import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding;
+import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding;
import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration;
+import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NOSLOServiceDescriptorException;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoMetadataInformationException;
import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest;
import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider;
+import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider;
import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils;
import at.gv.egovernment.moa.id.util.MOAIDMessageProvider;
import at.gv.egovernment.moa.logging.Logger;
@@ -56,9 +79,141 @@ import at.gv.egovernment.moa.logging.Logger;
*/
public class SingleLogOutBuilder {
- public static LogoutRequest buildSLORequestMessage(SLOInformationImpl sloInfo) throws ConfigurationException {
+ public static void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) {
+ Status status = logOutResp.getStatus();
+ if (!status.getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {
+ String message = " Message: ";
+ if (status.getStatusMessage() != null)
+ message += status.getStatusMessage().getMessage();
+ Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue()
+ + " FAILED. (ResponseCode: " + status.getStatusCode().getValue()
+ + message + ")");
+ sloContainer.putFailedOA(logOutResp.getIssuer().getValue());
+
+ } else
+ sloContainer.removeFrontChannelOA(logOutResp.getIssuer().getValue());
+ Logger.debug("Single LogOut for OA " + logOutResp.getIssuer().getValue() + " SUCCESS");
+
+ }
+
+ /**
+ * @param serviceURL
+ * @param binding
+ * @param sloReq
+ * @param httpReq
+ * @param httpResp
+ * @param relayState
+ * @return
+ */
+ public static String getFrontChannelSLOMessageURL(String serviceURL, String bindingType,
+ RequestAbstractType sloReq, HttpServletRequest httpReq,
+ HttpServletResponse httpResp, String relayState) throws MOAIDException {
+
+ try {
+ X509Credential credentials = CredentialProvider
+ .getIDPAssertionSigningCredential();
+
+ Logger.debug("create SAML RedirectBinding response");
+
+ MOAStringRedirectDeflateEncoder encoder = new MOAStringRedirectDeflateEncoder();
+ BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ SingleLogoutService service = new SingleLogoutServiceBuilder()
+ .buildObject();
+ service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ service.setLocation(serviceURL);
+ context.setOutboundSAMLMessageSigningCredential(credentials);
+ context.setPeerEntityEndpoint(service);
+ context.setOutboundSAMLMessage(sloReq);
+ context.setRelayState(relayState);
+
+ encoder.encode(context);
+
+ return encoder.getRedirectURL();
+
+ } catch (MessageEncodingException e) {
+ Logger.error("Message Encoding exception", e);
+ throw new MOAIDException("pvp2.01", null, e);
+
+ }
+ }
+
+ public static String getFrontChannelSLOMessageURL(SingleLogoutService service,
+ StatusResponseType sloResp, HttpServletRequest httpReq,
+ HttpServletResponse httpResp, String relayState) throws MOAIDException {
+
+ try {
+ X509Credential credentials = CredentialProvider
+ .getIDPAssertionSigningCredential();
+
+ Logger.debug("create SAML RedirectBinding response");
+
+ MOAStringRedirectDeflateEncoder encoder = new MOAStringRedirectDeflateEncoder();
+ BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
+ context.setOutboundSAMLMessageSigningCredential(credentials);
+ context.setPeerEntityEndpoint(service);
+ context.setOutboundSAMLMessage(sloResp);
+ context.setRelayState(relayState);
+
+ encoder.encode(context);
+
+ return encoder.getRedirectURL();
+
+ } catch (MessageEncodingException e) {
+ Logger.error("Message Encoding exception", e);
+ throw new MOAIDException("pvp2.01", null, e);
+
+ }
+ }
+
+ public static void sendFrontChannelSLOMessage(SingleLogoutService consumerService,
+ LogoutResponse sloResp, HttpServletRequest req, HttpServletResponse resp,
+ String relayState) throws MOAIDException {
+ IEncoder binding = null;
+ if (consumerService.getBinding().equals(
+ SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
+ binding = new RedirectBinding();
+
+ } else if (consumerService.getBinding().equals(
+ SAMLConstants.SAML2_POST_BINDING_URI)) {
+ binding = new PostBinding();
+
+ }
+
+ if (binding == null) {
+ throw new BindingNotSupportedException(consumerService.getBinding());
+ }
+
+ try {
+ binding.encodeRespone(req, resp, sloResp,
+ consumerService.getLocation(), relayState);
+
+ } catch (MessageEncodingException e) {
+ Logger.error("Message Encoding exception", e);
+ throw new MOAIDException("pvp2.01", null, e);
+
+ } catch (SecurityException e) {
+ Logger.error("Security exception", e);
+ throw new MOAIDException("pvp2.01", null, e);
+
+ }
+ }
+
+
+ public static LogoutRequest buildSLORequestMessage(SLOInformationImpl sloInfo) throws ConfigurationException, MOAIDException {
LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class);
+ SecureRandomIdentifierGenerator gen;
+ try {
+ gen = new SecureRandomIdentifierGenerator();
+ sloReq.setID(gen.generateIdentifier());
+
+ } catch (NoSuchAlgorithmException e) {
+ Logger.error("Internal server error", e);
+ throw new AuthenticationException("pvp2.13", new Object[]{});
+
+ }
+
+
Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath());
issuer.setFormat(NameID.ENTITY);
@@ -75,14 +230,9 @@ public class SingleLogOutBuilder {
return sloReq;
}
- public static LogoutResponse buildSLOErrorResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException {
- LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class);
- Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
- issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath());
- issuer.setFormat(NameID.ENTITY);
- sloResp.setIssuer(issuer);
- sloResp.setIssueInstant(new DateTime());
- sloResp.setDestination(sloService.getLocation());
+ public static LogoutResponse buildSLOErrorResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException, MOAIDException {
+ LogoutResponse sloResp = buildBasicResponse(sloService, spRequest);
+
Status status = SAML2Utils.createSAMLObject(Status.class);
StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class);
StatusMessage statusMessage = SAML2Utils.createSAMLObject(StatusMessage.class);
@@ -94,14 +244,8 @@ public class SingleLogOutBuilder {
return sloResp;
}
- public static LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService, PVPTargetConfiguration spRequest, List<String> failedOAs) throws ConfigurationException {
- LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class);
- Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
- issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath());
- issuer.setFormat(NameID.ENTITY);
- sloResp.setIssuer(issuer);
- sloResp.setIssueInstant(new DateTime());
- sloResp.setDestination(sloService.getLocation());
+ public static LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService, PVPTargetConfiguration spRequest, List<String> failedOAs) throws MOAIDException {
+ LogoutResponse sloResp = buildBasicResponse(sloService, spRequest);
Status status;
if (failedOAs == null || failedOAs.size() == 0) {
@@ -122,10 +266,41 @@ public class SingleLogOutBuilder {
}
+ private static LogoutResponse buildBasicResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException, MOAIDException {
+ LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class);
+ Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
+ issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath());
+ issuer.setFormat(NameID.ENTITY);
+ sloResp.setIssuer(issuer);
+ sloResp.setIssueInstant(new DateTime());
+ sloResp.setDestination(sloService.getLocation());
+
+ SecureRandomIdentifierGenerator gen;
+ try {
+ gen = new SecureRandomIdentifierGenerator();
+ sloResp.setID(gen.generateIdentifier());
+
+ } catch (NoSuchAlgorithmException e) {
+ Logger.error("Internal server error", e);
+ throw new AuthenticationException("pvp2.13", new Object[]{});
+
+ }
+
+ if (spRequest.getRequest() instanceof MOARequest &&
+ ((MOARequest)spRequest.getRequest()).getSamlRequest() instanceof LogoutRequest) {
+ LogoutRequest sloReq = (LogoutRequest) ((MOARequest)spRequest.getRequest()).getSamlRequest();
+ sloResp.setInResponseTo(sloReq.getID());
+
+ }
+
+ return sloResp;
+
+ }
+
public static SingleLogoutService getRequestSLODescriptor(String entityID) throws NOSLOServiceDescriptorException {
try {
EntityDescriptor entity = MOAMetadataProvider.getInstance().getEntityDescriptor(entityID);
- SPSSODescriptor spsso = entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS);
+ SSODescriptor spsso = entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS);
SingleLogoutService sloService = null;
for (SingleLogoutService el : spsso.getSingleLogoutServices()) {
@@ -139,19 +314,19 @@ public class SingleLogOutBuilder {
)
sloService = el;
- else if (el.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)
- && (
- (sloService != null
- && !sloService.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)
- && !sloService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI))
- || sloService == null)
- )
- sloService = el;
+// else if (el.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)
+// && (
+// (sloService != null
+// && !sloService.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)
+// && !sloService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI))
+// || sloService == null)
+// )
+// sloService = el;
}
if (sloService == null) {
- Logger.error("Found no SLO ServiceDescriptor in Metadata");
- throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null);
+ Logger.error("Found no valid SLO ServiceDescriptor in Metadata");
+ throw new NOSLOServiceDescriptorException("NO valid SLO ServiceDescriptor", null);
}
return sloService;
@@ -173,14 +348,18 @@ public class SingleLogOutBuilder {
if (el.getBinding().equals(spRequest.getBinding()))
sloService = el;
}
- if (sloService == null && spsso.getSingleLogoutServices().size() != 0)
- sloService = spsso.getSingleLogoutServices().get(0);
- else {
- Logger.error("Found no SLO ServiceDescriptor in Metadata");
- throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null);
+ if (sloService == null) {
+ if (spsso.getSingleLogoutServices().size() != 0)
+ sloService = spsso.getSingleLogoutServices().get(0);
+
+ else {
+ Logger.error("Found no SLO ServiceDescriptor in Metadata");
+ throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null);
+ }
}
- return sloService;
+
+ return sloService;
}
}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java
index 4d6343fce..fa5d252bd 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java
@@ -135,7 +135,8 @@ public class PVP2AssertionBuilder implements PVPConstants {
SubjectConfirmationData subjectConfirmationData = null;
return buildGenericAssertion(attrQuery.getIssuer().getValue(), date,
- authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex);
+ authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex,
+ new DateTime(authData.getSsoSessionValidTo().getTime()));
}
public static Assertion buildAssertion(AuthnRequest authnRequest,
@@ -393,8 +394,8 @@ public class PVP2AssertionBuilder implements PVPConstants {
SubjectConfirmationData subjectConfirmationData = SAML2Utils
.createSAMLObject(SubjectConfirmationData.class);
subjectConfirmationData.setInResponseTo(authnRequest.getID());
- subjectConfirmationData.setNotOnOrAfter(date.plusMinutes(5));
-
+ subjectConfirmationData.setNotOnOrAfter(new DateTime(authData.getSsoSessionValidTo().getTime()));
+
subjectConfirmationData.setRecipient(assertionConsumerService.getLocation());
//set SLO information
@@ -402,13 +403,13 @@ public class PVP2AssertionBuilder implements PVPConstants {
sloInformation.setNameIDFormat(subjectNameID.getFormat());
sloInformation.setSessionIndex(sessionIndex);
- return buildGenericAssertion(peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex);
+ return buildGenericAssertion(peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, subjectConfirmationData.getNotOnOrAfter());
}
private static Assertion buildGenericAssertion(String entityID, DateTime date,
AuthnContextClassRef authnContextClassRef, List<Attribute> attrList,
NameID subjectNameID, SubjectConfirmationData subjectConfirmationData,
- String sessionIndex) throws ConfigurationException {
+ String sessionIndex, DateTime isValidTo) throws ConfigurationException {
Assertion assertion = SAML2Utils.createSAMLObject(Assertion.class);
AuthnContext authnContext = SAML2Utils
@@ -448,10 +449,9 @@ public class PVP2AssertionBuilder implements PVPConstants {
audience.setAudienceURI(entityID);
audienceRestriction.getAudiences().add(audience);
- conditions.setNotBefore(date);
-
- conditions.setNotOnOrAfter(date.plusMinutes(5));
-
+ conditions.setNotBefore(date);
+ conditions.setNotOnOrAfter(isValidTo);
+
conditions.getAudienceRestrictions().add(audienceRestriction);
assertion.setConditions(conditions);
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java
index 255fba093..d3a9ad3e7 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java
@@ -33,7 +33,6 @@ import java.util.Properties;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
-import org.opensaml.Configuration;
import org.opensaml.saml2.metadata.Company;
import org.opensaml.saml2.metadata.ContactPerson;
import org.opensaml.saml2.metadata.ContactPersonTypeEnumeration;
@@ -46,7 +45,6 @@ import org.opensaml.saml2.metadata.OrganizationName;
import org.opensaml.saml2.metadata.OrganizationURL;
import org.opensaml.saml2.metadata.SurName;
import org.opensaml.saml2.metadata.TelephoneNumber;
-import org.opensaml.xml.security.SecurityConfiguration;
import at.gv.egovernment.moa.id.commons.db.dao.config.Contact;
import at.gv.egovernment.moa.id.commons.db.dao.config.OAPVP2;
@@ -71,10 +69,12 @@ public class PVPConfiguration {
}
public static final String PVP2_METADATA = "/pvp2/metadata";
- public static final String PVP2_REDIRECT = "/pvp2/redirect";
- public static final String PVP2_POST = "/pvp2/post";
- public static final String PVP2_SOAP = "/pvp2/soap";
- public static final String PVP2_ATTRIBUTEQUERY = "/pvp2/attributequery";
+ public static final String PVP2_IDP_REDIRECT = "/pvp2/redirect";
+ public static final String PVP2_IDP_POST = "/pvp2/post";
+ public static final String PVP2_IDP_SOAP = "/pvp2/soap";
+ public static final String PVP2_IDP_ATTRIBUTEQUERY = "/pvp2/attributequery";
+ public static final String PVP2_SP_REDIRECT = "/pvp2/sp/redirect";
+ public static final String PVP2_SP_POST = "/pvp2/sp/post";
public static final String PVP_CONFIG_FILE = "pvp2config.properties";
@@ -143,22 +143,30 @@ public class PVPConfiguration {
return publicPath;
}
- public String getIDPSSOPostService() throws ConfigurationException {
- return getIDPPublicPath() + PVP2_POST;
+ public String getSPSSOPostService() throws ConfigurationException {
+ return getIDPPublicPath() + PVP2_SP_POST;
}
- public String getIDPSSOSOAPService() throws ConfigurationException {
- return getIDPPublicPath() + PVP2_SOAP;
+ public String getSPSSORedirectService() throws ConfigurationException {
+ return getIDPPublicPath() + PVP2_SP_REDIRECT;
}
- public String getIDPAttributeQueryService() throws ConfigurationException {
- return getIDPPublicPath() + PVP2_ATTRIBUTEQUERY;
+ public String getIDPSSOPostService() throws ConfigurationException {
+ return getIDPPublicPath() + PVP2_IDP_POST;
}
-
+
public String getIDPSSORedirectService() throws ConfigurationException {
- return getIDPPublicPath() + PVP2_REDIRECT;
+ return getIDPPublicPath() + PVP2_IDP_REDIRECT;
}
+ public String getIDPSSOSOAPService() throws ConfigurationException {
+ return getIDPPublicPath() + PVP2_IDP_SOAP;
+ }
+
+ public String getIDPAttributeQueryService() throws ConfigurationException {
+ return getIDPPublicPath() + PVP2_IDP_ATTRIBUTEQUERY;
+ }
+
public String getIDPSSOMetadataService() throws ConfigurationException {
return getIDPPublicPath() + PVP2_METADATA;
}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java
index 870273cf3..f2512b122 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java
@@ -23,7 +23,7 @@
package at.gv.egovernment.moa.id.protocols.pvp2x.messages;
import org.opensaml.Configuration;
-import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.core.StatusResponseType;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.io.UnmarshallingException;
@@ -35,16 +35,16 @@ public class MOAResponse extends InboundMessage {
private static final long serialVersionUID = -1133012928130138501L;
- public MOAResponse(Response response) {
+ public MOAResponse(StatusResponseType response) {
setSAMLMessage(response.getDOM());
}
- public Response getResponse() {
+ public StatusResponseType getResponse() {
UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
Unmarshaller unmashaller = unmarshallerFactory.getUnmarshaller(getInboundMessage());
try {
- return (Response) unmashaller.unmarshall(getInboundMessage());
+ return (StatusResponseType) unmashaller.unmarshall(getInboundMessage());
} catch (UnmarshallingException e) {
Logger.warn("AuthnResponse Unmarshaller error", e);
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java
index 61b481447..ee0088576 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java
@@ -28,6 +28,7 @@ import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.AuthnContextClassRef;
import org.opensaml.saml2.core.AuthnStatement;
import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.core.StatusResponseType;
import org.opensaml.saml2.core.Subject;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionAttributeExtractorExeption;
@@ -38,15 +39,16 @@ public class AssertionAttributeExtractor {
private Assertion assertion = null;
- public AssertionAttributeExtractor(Response samlResponse) throws AssertionAttributeExtractorExeption {
- if (samlResponse != null) {
- if (samlResponse.getAssertions().size() == 0)
+ public AssertionAttributeExtractor(StatusResponseType samlResponse) throws AssertionAttributeExtractorExeption {
+ if (samlResponse != null && samlResponse instanceof Response) {
+ List<Assertion> assertions = ((Response) samlResponse).getAssertions();
+ if (assertions.size() == 0)
throw new AssertionAttributeExtractorExeption("Assertion");
- else if (samlResponse.getAssertions().size() > 1)
+ else if (assertions.size() > 1)
Logger.warn("Found more then ONE PVP2.1 assertions. Only the First is used.");
- assertion = samlResponse.getAssertions().get(0);
+ assertion = assertions.get(0);
} else
throw new AssertionAttributeExtractorExeption();
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java
index 6388042d9..3be5df917 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java
@@ -32,6 +32,7 @@ import org.opensaml.saml2.core.EncryptedAssertion;
import org.opensaml.saml2.core.RequestAbstractType;
import org.opensaml.saml2.core.Response;
import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.core.StatusResponseType;
import org.opensaml.saml2.encryption.Decrypter;
import org.opensaml.saml2.encryption.EncryptedElementTypeEncryptedKeyResolver;
import org.opensaml.saml2.metadata.IDPSSODescriptor;
@@ -76,7 +77,7 @@ public class SAMLVerificationEngine {
}
- public void verifyResponse(Response samlObj, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception {
+ public void verifyResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception {
SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
try {
profileValidator.validate(samlObj.getSignature());
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/storage/AuthenticationSessionStoreage.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/storage/AuthenticationSessionStoreage.java
index 6c2900752..1c74aea55 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/storage/AuthenticationSessionStoreage.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/storage/AuthenticationSessionStoreage.java
@@ -64,7 +64,7 @@ public class AuthenticationSessionStoreage {
AuthenticatedSessionStore session;
try {
- session = searchInDatabase(moaSessionID);
+ session = searchInDatabase(moaSessionID, true);
return session.isAuthenticated();
} catch (MOADatabaseException e) {
@@ -72,19 +72,20 @@ public class AuthenticationSessionStoreage {
}
}
- public static AuthenticationSession createSession() throws MOADatabaseException {
+ public static AuthenticationSession createSession() throws MOADatabaseException, BuildException {
String id = Random.nextRandom();
- AuthenticationSession session = new AuthenticationSession(id);
-
+
AuthenticatedSessionStore dbsession = new AuthenticatedSessionStore();
dbsession.setSessionid(id);
dbsession.setAuthenticated(false);
- //set Timestamp in this state, because automated timestamp generation is buggy in Hibernate 4.2.1
- dbsession.setCreated(new Date());
- dbsession.setUpdated(new Date());
+ //set Timestamp in this state, because automated timestamp generation is buggy in Hibernate 4.2.1
+ Date now = new Date();
+ dbsession.setCreated(now);
+ dbsession.setUpdated(now);
- dbsession.setSession(SerializationUtils.serialize(session));
+ AuthenticationSession session = new AuthenticationSession(id, now);
+ encryptSession(session, dbsession);
//store AssertionStore element to Database
try {
@@ -102,7 +103,7 @@ public class AuthenticationSessionStoreage {
public static AuthenticationSession getSession(String sessionID) throws MOADatabaseException {
try {
- AuthenticatedSessionStore dbsession = searchInDatabase(sessionID);
+ AuthenticatedSessionStore dbsession = searchInDatabase(sessionID, true);
return decryptSession(dbsession);
} catch (MOADatabaseException e) {
@@ -122,7 +123,7 @@ public class AuthenticationSessionStoreage {
public static void storeSession(AuthenticationSession session, String pendingRequestID) throws MOADatabaseException, BuildException {
try {
- AuthenticatedSessionStore dbsession = searchInDatabase(session.getSessionID());
+ AuthenticatedSessionStore dbsession = searchInDatabase(session.getSessionID(), true);
if (MiscUtil.isNotEmpty(pendingRequestID))
dbsession.setPendingRequestID(pendingRequestID);
@@ -175,7 +176,7 @@ public class AuthenticationSessionStoreage {
throws AuthenticationException, BuildException {
try {
- AuthenticatedSessionStore dbsession = searchInDatabase(session.getSessionID());
+ AuthenticatedSessionStore dbsession = searchInDatabase(session.getSessionID(), true);
String id = Random.nextRandom();
@@ -207,7 +208,7 @@ public class AuthenticationSessionStoreage {
AuthenticatedSessionStore session;
try {
- session = searchInDatabase(moaSessionID);
+ session = searchInDatabase(moaSessionID, true);
session.setAuthenticated(value);
MOASessionDBUtils.saveOrUpdate(session);
@@ -249,7 +250,7 @@ public class AuthenticationSessionStoreage {
public static boolean isSSOSession(String sessionID) throws MOADatabaseException {
try {
- AuthenticatedSessionStore dbsession = searchInDatabase(sessionID);
+ AuthenticatedSessionStore dbsession = searchInDatabase(sessionID, true);
return dbsession.isSSOSession();
} catch (MOADatabaseException e) {
@@ -391,8 +392,36 @@ public class AuthenticationSessionStoreage {
MiscUtil.assertNotNull(moaSession, "MOASession");
try {
- AuthenticatedSessionStore dbsession = searchInDatabase(moaSession.getSessionID());
- return dbsession.getActiveOAsessions();
+ List<OASessionStore> oas = new ArrayList<OASessionStore>();
+
+ AuthenticatedSessionStore dbsession = searchInDatabase(moaSession.getSessionID(), false);
+ oas.addAll(dbsession.getActiveOAsessions());
+
+ Session session = MOASessionDBUtils.getCurrentSession();
+ session.getTransaction().commit();
+
+ return oas;
+
+ } catch (MOADatabaseException e) {
+ Logger.warn("NO session information found for sessionID " + moaSession.getSessionID(), e);
+
+ }
+
+ return null;
+ }
+
+ public static List<InterfederationSessionStore> getAllActiveIDPsFromMOASession(AuthenticationSession moaSession) {
+ MiscUtil.assertNotNull(moaSession, "MOASession");
+
+ try {
+ List<InterfederationSessionStore> idps = new ArrayList<InterfederationSessionStore>();
+ AuthenticatedSessionStore dbsession = searchInDatabase(moaSession.getSessionID(), false);
+ idps.addAll(dbsession.getInderfederation());
+
+ Session session = MOASessionDBUtils.getCurrentSession();
+ session.getTransaction().commit();
+
+ return idps;
} catch (MOADatabaseException e) {
Logger.warn("NO session information found for sessionID " + moaSession.getSessionID(), e);
@@ -475,7 +504,7 @@ public class AuthenticationSessionStoreage {
public static String getPendingRequestID(String sessionID) {
try {
- AuthenticatedSessionStore dbsession = searchInDatabase(sessionID);
+ AuthenticatedSessionStore dbsession = searchInDatabase(sessionID, true);
return dbsession.getPendingRequestID();
} catch (MOADatabaseException e) {
@@ -646,7 +675,7 @@ public class AuthenticationSessionStoreage {
return result.get(0).getInderfederation().get(0);
}
- public static String createInterfederatedSession(IRequest req, boolean isAuthenticated, String ssoID) throws MOADatabaseException, AssertionAttributeExtractorExeption {
+ public static String createInterfederatedSession(IRequest req, boolean isAuthenticated, String ssoID) throws MOADatabaseException, AssertionAttributeExtractorExeption, BuildException {
AuthenticatedSessionStore dbsession = null;
//search for active SSO session
@@ -654,7 +683,7 @@ public class AuthenticationSessionStoreage {
String moaSession = getMOASessionSSOID(ssoID);
if (MiscUtil.isNotEmpty(moaSession)) {
try {
- dbsession = searchInDatabase(moaSession);
+ dbsession = searchInDatabase(moaSession, true);
}catch (MOADatabaseException e) {
@@ -664,28 +693,28 @@ public class AuthenticationSessionStoreage {
String id = null;
Date now = new Date();
-
//create new MOASession if any exists
+ AuthenticationSession session = null;
if (dbsession == null) {
id = Random.nextRandom();
dbsession = new AuthenticatedSessionStore();
dbsession.setSessionid(id);
dbsession.setCreated(now);
-
+ session = new AuthenticationSession(id, now);
+
} else {
id = dbsession.getSessionid();
-
+ session = decryptSession(dbsession);
+
}
-
+
dbsession.setInterfederatedSSOSession(true);
dbsession.setAuthenticated(isAuthenticated);
- dbsession.setUpdated(now);
-
- AuthenticationSession session = new AuthenticationSession(id);
+ dbsession.setUpdated(now);
session.setAuthenticated(true);
- session.setAuthenticatedUsed(false);
- dbsession.setSession(SerializationUtils.serialize(session));
-
+ session.setAuthenticatedUsed(false);
+ encryptSession(session, dbsession);
+
//add interfederation information
List<InterfederationSessionStore> idpList = dbsession.getInderfederation();
InterfederationSessionStore idp = null;
@@ -889,7 +918,7 @@ public class AuthenticationSessionStoreage {
}
@SuppressWarnings("rawtypes")
- private static AuthenticatedSessionStore searchInDatabase(String sessionID) throws MOADatabaseException {
+ private static AuthenticatedSessionStore searchInDatabase(String sessionID, boolean commit) throws MOADatabaseException {
MiscUtil.assertNotNull(sessionID, "moasessionID");
Logger.trace("Get authenticated session with sessionID " + sessionID + " from database.");
Session session = MOASessionDBUtils.getCurrentSession();
@@ -903,7 +932,8 @@ public class AuthenticationSessionStoreage {
result = query.list();
//send transaction
- session.getTransaction().commit();
+ if (commit)
+ session.getTransaction().commit();
}
Logger.trace("Found entries: " + result.size());
diff --git a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties
index c8cca157d..9aab22ef5 100644
--- a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties
+++ b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties
@@ -243,9 +243,9 @@ pvp2.16=Fehler beim verschl\u00FCsseln der PVP2 Assertion
pvp2.17=Der QAA Level {0} entspricht nicht dem angeforderten QAA Level {1}
pvp2.18=Es konnten nicht alle Single Sign-On Sessions beendet werden.
pvp2.19=Der Single LogOut Vorgang musste wegen eines unkorregierbaren Fehler abgebrochen werden.
-pvp2.20=Für die im Request angegebene EntityID konnten keine g\u00FCltigen Metadaten gefunden werden.
+pvp2.20=F\u00FCr die im Request angegebene EntityID konnten keine g\u00FCltigen Metadaten gefunden werden.
pvp2.21=Die Signature des Requests konnte nicht g\u00FCltig validiert werden.
-pvp2.22=Der Request konnte nicht g\u00FCltig validiert werden (Fehler={0}).
+pvp2.22=Der Request konnte nicht g\u00FCltig validiert werden (Fehler\={0}).
oauth20.01=Fehlerhafte redirect url
oauth20.02=Fehlender Parameter "{0}"
@@ -256,3 +256,6 @@ oauth20.06=Die angegebene OA kann nicht verwendet werden
oauth20.07=Angeforderter grant_type ist nicht erlaubt
oauth20.08=Nicht berechtigt f\u00FCr Token-Request
oauth20.09=Zertifikat fuer JSON Web-Token ist falsch konfiguriert. Fehler bei "{0}"
+
+slo.00=Sie konnten erfolgreich von allen Online-Applikation abgemeldet werden.
+slo.01=Sie konnten NICHT erfolgreich von allen Online-Applikationen abgemeldet werden\!<BR>Bitte schlie\u00DFen Sie aus sicherheitsgr\u00FCnden Ihren Browser.
diff --git a/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html b/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html
new file mode 100644
index 000000000..a652855c4
--- /dev/null
+++ b/id/server/idserverlib/src/main/resources/resources/templates/slo_template.html
@@ -0,0 +1,438 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+
+ <!-- MOA-ID 2.x BKUSelection Layout CSS -->
+ <style type="text/css">
+ @media screen and (min-width: 650px) {
+
+ body {
+ margin:0;
+ padding:0;
+ color : #000;
+ background-color : #fff;
+ text-align: center;
+ background-color: #6B7B8B;
+ }
+
+ #page {
+ display: block;
+ border: 2px solid rgb(0,0,0);
+ width: 650px;
+ height: 460px;
+ margin: 0 auto;
+ margin-top: 5%;
+ position: relative;
+ border-radius: 25px;
+ background: rgb(255,255,255);
+ }
+
+ #page1 {
+ text-align: center;
+ }
+
+ #main {
+ /* clear:both; */
+ position:relative;
+ margin: 0 auto;
+ width: 250px;
+ text-align: center;
+ }
+
+ .OA_header {
+ /* background-color: white;*/
+ font-size: 20pt;
+ margin-bottom: 25px;
+ margin-top: 25px;
+ }
+
+ #leftcontent {
+ /*float:left; */
+ width:250px;
+ margin-bottom: 25px;
+ text-align: left;
+ /*border: 1px solid rgb(0,0,0);*/
+ }
+
+ #leftcontent {
+ width: 300px;
+ margin-top: 30px;
+ }
+
+ h2#tabheader{
+ font-size: 1.1em;
+ padding-left: 2%;
+ padding-right: 2%;
+ position: relative;
+ }
+
+ .setAssertionButton_full {
+ background: #efefef;
+ cursor: pointer;
+ margin-top: 15px;
+ width: 100px;
+ height: 30px
+ }
+
+ #leftbutton {
+ width: 30%;
+ float:left;
+ margin-left: 40px;
+ }
+
+ #rightbutton {
+ width: 30%;
+ float:right;
+ margin-right: 45px;
+ text-align: right;
+ }
+
+ button {
+ height: 25px;
+ width: 75px;
+ margin-bottom: 10px;
+ }
+
+ #validation {
+ position: absolute;
+ bottom: 0px;
+ margin-left: 270px;
+ padding-bottom: 10px;
+ }
+
+ }
+
+ @media screen and (max-width: 205px) {
+ #localBKU p {
+ font-size: 0.6em;
+ }
+
+ #localBKU input {
+ font-size: 0.6em;
+ min-width: 60px;
+ /* max-width: 65px; */
+ min-height: 1.0em;
+ /* border-radius: 5px; */
+ }
+
+ }
+
+ @media screen and (max-width: 249px) and (min-width: 206px) {
+ #localBKU p {
+ font-size: 0.7em;
+ }
+
+ #localBKU input {
+ font-size: 0.7em;
+ min-width: 70px;
+ /* max-width: 75px; */
+ min-height: 0.95em;
+ /* border-radius: 6px; */
+ }
+
+ }
+
+ @media screen and (max-width: 299px) and (min-width: 250px) {
+ #localBKU p {
+ font-size: 0.9em;
+ }
+
+ #localBKU input {
+ font-size: 0.8em;
+ min-width: 70px;
+ /* max-width: 75px; */
+ /* border-radius: 6px; */
+ }
+
+ }
+
+ @media screen and (max-width: 399px) and (min-width: 300px) {
+ #localBKU p {
+ font-size: 0.9em;
+ }
+
+ #localBKU input {
+ font-size: 0.8em;
+ min-width: 70px;
+ /* max-width: 75px; */
+ /* border-radius: 6px; */
+ }
+
+ }
+
+ @media screen and (max-width: 649px) and (min-width: 400px) {
+ #localBKU p {
+ font-size: 0.9em;
+ }
+
+ #localBKU input {
+ font-size: 0.8em;
+ min-width: 70px;
+ /* max-width: 80px; */
+ /* border-radius: 6px; */
+ }
+
+ }
+
+
+
+ @media screen and (max-width: 649px) {
+
+ body {
+ margin:0;
+ padding:0;
+ color : #000;
+ text-align: center;
+ font-size: 100%;
+ background-color: #MAIN_BACKGOUNDCOLOR#;
+ }
+
+ #page {
+ visibility: hidden;
+ margin-top: 0%;
+ }
+
+ #page1 {
+ visibility: hidden;
+ }
+
+ #main {
+ visibility: hidden;
+ }
+
+ #validation {
+ visibility: hidden;
+ display: none;
+ }
+
+ .OA_header {
+ margin-bottom: 0px;
+ margin-top: 0px;
+ font-size: 0pt;
+ visibility: hidden;
+ }
+
+ #leftcontent {
+ visibility: visible;
+ margin-bottom: 0px;
+ text-align: left;
+ border:none;
+ vertical-align: middle;
+ min-height: 173px;
+ min-width: 204px;
+
+ }
+
+ input[type=button] {
+/* height: 11%; */
+ width: 70%;
+ }
+ }
+
+ * {
+ margin: 0;
+ padding: 0;
+ font-family: #FONTTYPE#;
+ }
+
+ #selectArea {
+ padding-top: 10px;
+ padding-bottom: 55px;
+ padding-left: 10px;
+ }
+
+ .setAssertionButton {
+ background: #efefef;
+ cursor: pointer;
+ margin-top: 15px;
+ width: 70px;
+ height: 25px;
+ }
+
+ #leftbutton {
+ width: 35%;
+ float:left;
+ margin-left: 15px;
+ }
+
+ #rightbutton {
+ width: 35%;
+ float:right;
+ margin-right: 25px;
+ text-align: right;
+ }
+
+/* input[type=button], .sendButton {
+ background: #BUTTON_BACKGROUNDCOLOR#;
+ color: #BUTTON_COLOR#;
+/* border:1px solid #000; */
+/* cursor: pointer;
+/* box-shadow: 3px 3px 3px #222222; */
+/* }
+
+/* button:hover, button:focus, button:active,
+ .sendButton:hover , .sendButton:focus, .sendButton:active,
+ #mandateCheckBox:hover, #mandateCheckBox:focus, #mandateCheckBox:active {
+ background: #BUTTON_BACKGROUNDCOLOR_FOCUS#;
+ color: #BUTTON_COLOR#;
+/* border:1px solid #000; */
+/* cursor: pointer;
+/* box-shadow: -1px -1px 3px #222222; */
+/* }
+
+*/
+ input {
+ /*border:1px solid #000;*/
+ cursor: pointer;
+ }
+
+ #localBKU input {
+/* color: #BUTTON_COLOR#; */
+ border: 0px;
+ display: inline-block;
+
+ }
+
+ #localBKU input:hover, #localBKU input:focus, #localBKU input:active {
+ text-decoration: underline;
+ }
+
+ #installJava, #BrowserNOK {
+ clear:both;
+ font-size:0.8em;
+ padding:4px;
+ }
+
+ .selectText{
+
+ }
+
+ .selectTextHeader{
+
+ }
+
+ .sendButton {
+ width: 30%;
+ margin-bottom: 1%;
+ }
+
+ #leftcontent a {
+ text-decoration:none;
+ color: #000;
+ /* display:block;*/
+ padding:4px;
+ }
+
+ #leftcontent a:hover, #leftcontent a:focus, #leftcontent a:active {
+ text-decoration:underline;
+ color: #000;
+ }
+
+ .infobutton {
+ background-color: #005a00;
+ color: white;
+ font-family: serif;
+ text-decoration: none;
+ padding-top: 2px;
+ padding-right: 4px;
+ padding-bottom: 2px;
+ padding-left: 4px;
+ font-weight: bold;
+ }
+
+ .hell {
+ background-color : #MAIN_BACKGOUNDCOLOR#;
+ color: #MAIN_COLOR#;
+ }
+
+ .dunkel {
+ background-color: #HEADER_BACKGROUNDCOLOR#;
+ color: #HEADER_COLOR#;
+ }
+
+ .main_header {
+ color: black;
+ font-size: 32pt;
+ position: absolute;
+ right: 10%;
+ top: 40px;
+
+ }
+
+ #alert {
+ margin: 100px 250px;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 14px;
+ font-weight: normal;
+ color: red;
+ }
+
+ .reqframe {
+ /*display: none;*/
+ visibility: hidden;
+
+ }
+
+ </style>
+
+
+ <title>Single LogOut Vorgang ... </title>
+</head>
+
+<body>
+ <noscript>
+ <p>
+ <strong>Note:</strong> Since your browser does not support
+ JavaScript, you must press the Continue button once to proceed.
+ </p>
+ </noscript>
+
+ <div id="page">
+ <div id="page1" class="case selected-case" role="main">
+ <h2 class="OA_header" role="heading">MOA-ID Single LogOut Information</h2>
+ <div id="main">
+ <div id="leftcontent" class="hell" role="application">
+
+ #if($errorMsg)
+ <div class="alert">
+ <p>$errorMsg</p>
+ </div>
+ #end
+
+ #if($successMsg)
+ <div>
+ <p>$successMsg</p>
+ </div>
+ #end
+
+ #if($redirectURLs)
+ <div>
+ <p>
+ Sie werden von allen Online-Applikationen abgemeldet. <br>
+ Dieser Vorgang kann einige Zeit in Anspruch nehmen.
+ </p>
+ </div>
+ #end
+
+ </div>
+ </div>
+ </div>
+ <div id="validation">
+ <a href="http://validator.w3.org/check?uri="> <img
+ style="border: 0; width: 88px; height: 31px"
+ src="$contextpath/img/valid-html5-blue.png" alt="HTML5 ist valide!" />
+ </a> <a href="http://jigsaw.w3.org/css-validator/"> <img
+ style="border: 0; width: 88px; height: 31px"
+ src="http://jigsaw.w3.org/css-validator/images/vcss-blue"
+ alt="CSS ist valide!" />
+ </a>
+ </div>
+ </div>
+
+
+ #foreach( $el in $redirectURLs )
+ <iframe src=$el class="reqframe"></iframe>
+ #end
+
+</body>
+</html> \ No newline at end of file