cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cohei...@apache.org
Subject cxf-fediz git commit: FEDIZ-200 - Make one of logoutEndpoint or logoutEndpointConstraint mandatory in the IDP
Date Thu, 13 Apr 2017 12:38:54 GMT
Repository: cxf-fediz
Updated Branches:
  refs/heads/1.3.x-fixes d0af658b6 -> 5eba7a0c8


FEDIZ-200 - Make one of logoutEndpoint or logoutEndpointConstraint mandatory in the IDP


Project: http://git-wip-us.apache.org/repos/asf/cxf-fediz/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf-fediz/commit/5eba7a0c
Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/5eba7a0c
Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/5eba7a0c

Branch: refs/heads/1.3.x-fixes
Commit: 5eba7a0c8bf0115d8600a92150caf3dcfbe79919
Parents: d0af658
Author: Colm O hEigeartaigh <coheigea@apache.org>
Authored: Thu Apr 13 13:01:12 2017 +0100
Committer: Colm O hEigeartaigh <coheigea@apache.org>
Committed: Thu Apr 13 13:38:45 2017 +0100

----------------------------------------------------------------------
 .../core/processor/FederationProcessorImpl.java |   7 +
 .../core/federation/FederationLogoutTest.java   |  53 +--
 .../idp/beans/EndpointAddressValidator.java     | 128 +++++++
 .../idp/beans/PassiveRequestorValidator.java    |  76 ----
 .../fediz/service/idp/domain/Application.java   |  36 +-
 .../cxf/fediz/service/idp/domain/Idp.java       |  15 +-
 .../idp/service/jpa/ApplicationDAOJPAImpl.java  |   6 +-
 .../idp/service/jpa/ApplicationEntity.java      |  21 ++
 .../service/idp/service/jpa/IdpDAOJPAImpl.java  |   6 +-
 .../service/idp/service/jpa/IdpEntity.java      |  12 +-
 .../idp/src/main/resources/entities-realma.xml  |   2 +
 .../WEB-INF/flows/federation-signin-request.xml |   2 +-
 .../flows/federation-validate-request.xml       |   3 +-
 .../WEB-INF/flows/saml-signin-request.xml       |   2 +-
 .../apache/cxf/fediz/systests/idp/IdpTest.java  | 374 +++++++++++++++++--
 .../test/resources/realma/entities-realma.xml   |   2 +
 .../test/resources/realma/entities-realma.xml   |   3 +-
 .../test/resources/realma/entities-realma.xml   |   1 +
 18 files changed, 608 insertions(+), 141 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
index 0044373..4f6e495 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
@@ -534,6 +534,13 @@ public class FederationProcessorImpl extends AbstractFedizProcessor {
                 sb.append(URLEncoder.encode(logoutRedirectTo, "UTF-8"));
             }
 
+            String realm = resolveWTRealm(request, config);
+            LOG.debug("wtrealm={}", realm);
+
+            // add wtrealm parameter
+            sb.append('&').append(FederationConstants.PARAM_TREALM).append('=').append(URLEncoder
+                                                                                           .encode(realm, "UTF-8"));
+
             redirectURL = redirectURL + "?" + sb.toString();
         } catch (Exception ex) {
             LOG.error("Failed to create SignInRequest", ex);

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationLogoutTest.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationLogoutTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationLogoutTest.java
index f1d1c44..134ed05 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationLogoutTest.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationLogoutTest.java
@@ -105,8 +105,9 @@ public class FederationLogoutTest {
         Assert.assertTrue(logoutHandler.canHandleRequest(req));
         
         HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
-        String expectedRedirectToIdP = 
-            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Flogout%2Findex.html";
+        String expectedRedirectToIdP =
+            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Flogout%2Findex.html"
+            + "&wtrealm=target+realm";
         resp.sendRedirect(expectedRedirectToIdP);
         EasyMock.expectLastCall();
         EasyMock.replay(resp);
@@ -119,7 +120,7 @@ public class FederationLogoutTest {
         
         HttpServletRequest req = EasyMock.createMock(HttpServletRequest.class);
         EasyMock.expect(req.getParameter(FederationConstants.PARAM_ACTION)).andReturn(null).anyTimes();
-        EasyMock.expect(req.getParameter(FederationConstants.PARAM_REPLY)).andReturn(REPLY_URI).anyTimes();
+        EasyMock.expect(req.getParameter(FederationConstants.PARAM_REPLY)).andReturn(REPLY_URL).anyTimes();
         EasyMock.expect(req.getRequestURL()).andReturn(new StringBuffer(LOGOUT_URL));
         EasyMock.expect(req.getRequestURI()).andReturn(LOGOUT_URI);
         EasyMock.expect(req.getContextPath()).andReturn(LOGOUT_URI);
@@ -129,8 +130,9 @@ public class FederationLogoutTest {
         Assert.assertTrue(logoutHandler.canHandleRequest(req));
         
         HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
-        String expectedRedirectToIdP = 
-            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Flogout%2Fwreply.html";
+        String expectedRedirectToIdP =
+            "http://url_to_the_issuer?wa=wsignout1.0&wreply=" + URLEncoder.encode(REPLY_URL, "UTF-8")
+            + "&wtrealm=target+realm";
         resp.sendRedirect(expectedRedirectToIdP);
         EasyMock.expectLastCall();
         EasyMock.replay(resp);
@@ -153,14 +155,15 @@ public class FederationLogoutTest {
         Assert.assertTrue(logoutHandler.canHandleRequest(req));
         
         HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
-        String expectedRedirectToIdP = 
-            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Flogout%2Findex.html";
+        String expectedRedirectToIdP =
+            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Flogout%2Findex.html"
+            + "&wtrealm=target+realm";
         resp.sendRedirect(expectedRedirectToIdP);
         EasyMock.expectLastCall();
         EasyMock.replay(resp);
         logoutHandler.handleRequest(req, resp);
     }
-    
+
     @org.junit.Test
     public void testSignoutCustomURLWithNoConfiguredConstraint() throws Exception {
         FedizContext config = getFederationConfigurator().getFedizContext("ROOT2");
@@ -177,8 +180,9 @@ public class FederationLogoutTest {
         Assert.assertTrue(logoutHandler.canHandleRequest(req));
         
         HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
-        String expectedRedirectToIdP = 
-            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Flogout%2Findex.html";
+        String expectedRedirectToIdP =
+            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Flogout%2Findex.html"
+            + "&wtrealm=target+realm";
         resp.sendRedirect(expectedRedirectToIdP);
         EasyMock.expectLastCall();
         EasyMock.replay(resp);
@@ -201,8 +205,9 @@ public class FederationLogoutTest {
         Assert.assertTrue(logoutHandler.canHandleRequest(req));
         
         HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
-        String expectedRedirectToIdP = 
-            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Flogout%2Findex.html";
+        String expectedRedirectToIdP =
+            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Flogout%2Findex.html"
+            + "&wtrealm=target+realm";
         resp.sendRedirect(expectedRedirectToIdP);
         EasyMock.expectLastCall();
         EasyMock.replay(resp);
@@ -226,8 +231,9 @@ public class FederationLogoutTest {
         Assert.assertTrue(logoutHandler.canHandleRequest(req));
         
         HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
-        String expectedRedirectToIdP = 
-            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Findex.html";
+        String expectedRedirectToIdP =
+            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Findex.html"
+            + "&wtrealm=target+realm";
         resp.sendRedirect(expectedRedirectToIdP);
         EasyMock.expectLastCall();
         EasyMock.replay(resp);
@@ -241,7 +247,7 @@ public class FederationLogoutTest {
         HttpServletRequest req = EasyMock.createMock(HttpServletRequest.class);
         EasyMock.expect(req.getParameter(FederationConstants.PARAM_ACTION))
             .andReturn(FederationConstants.ACTION_SIGNOUT).anyTimes();
-        EasyMock.expect(req.getParameter(FederationConstants.PARAM_REPLY)).andReturn(REPLY_URI).anyTimes();
+        EasyMock.expect(req.getParameter(FederationConstants.PARAM_REPLY)).andReturn(REPLY_URL).anyTimes();
         EasyMock.expect(req.getRequestURL()).andReturn(new StringBuffer("https://localhost/fedizhelloworld/secure"));
         EasyMock.expect(req.getRequestURI()).andReturn("/secure");
         EasyMock.expect(req.getContextPath()).andReturn("/secure");
@@ -251,8 +257,9 @@ public class FederationLogoutTest {
         Assert.assertTrue(logoutHandler.canHandleRequest(req));
         
         HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
-        String expectedRedirectToIdP = 
-            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Fwreply.html";
+        String expectedRedirectToIdP =
+            "http://url_to_the_issuer?wa=wsignout1.0&wreply=" + URLEncoder.encode(REPLY_URL, "UTF-8")
+            + "&wtrealm=target+realm";
         resp.sendRedirect(expectedRedirectToIdP);
         EasyMock.expectLastCall();
         EasyMock.replay(resp);
@@ -276,8 +283,9 @@ public class FederationLogoutTest {
         Assert.assertTrue(logoutHandler.canHandleRequest(req));
         
         HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
-        String expectedRedirectToIdP = 
-            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Findex.html";
+        String expectedRedirectToIdP =
+            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Findex.html"
+            + "&wtrealm=target+realm";
         resp.sendRedirect(expectedRedirectToIdP);
         EasyMock.expectLastCall();
         EasyMock.replay(resp);
@@ -301,8 +309,9 @@ public class FederationLogoutTest {
         Assert.assertTrue(logoutHandler.canHandleRequest(req));
         
         HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
-        String expectedRedirectToIdP = 
-            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Findex.html";
+        String expectedRedirectToIdP =
+            "http://url_to_the_issuer?wa=wsignout1.0&wreply=https%3A%2F%2Flocalhost%2Fsecure%2Findex.html"
+            + "&wtrealm=target+realm";
         resp.sendRedirect(expectedRedirectToIdP);
         EasyMock.expectLastCall();
         EasyMock.replay(resp);
@@ -379,4 +388,4 @@ public class FederationLogoutTest {
         EasyMock.replay(resp);
         logoutHandler.handleRequest(req, resp);
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/EndpointAddressValidator.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/EndpointAddressValidator.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/EndpointAddressValidator.java
new file mode 100644
index 0000000..536a2e6
--- /dev/null
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/EndpointAddressValidator.java
@@ -0,0 +1,128 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.fediz.service.idp.beans;
+
+import java.util.regex.Matcher;
+
+import org.apache.cxf.fediz.service.idp.domain.Application;
+import org.apache.cxf.fediz.service.idp.domain.Idp;
+import org.apache.cxf.fediz.service.idp.util.WebUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.webflow.execution.RequestContext;
+
+/**
+ * This class is responsible to validate the 'wreply' parameter for WS-Federation, or else the
+ * AssertionConsumer URL address for SAML SSO, by comparing it to a regular expression.
+ */
+@Component
+public class EndpointAddressValidator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EndpointAddressValidator.class);
+
+    public boolean isValidSigninAddress(RequestContext context, String endpointAddress, String realm)
+        throws Exception {
+        if (endpointAddress == null) {
+            return true;
+        }
+
+        Idp idpConfig = (Idp) WebUtils.getAttributeFromFlowScope(context, "idpConfig");
+        Application serviceConfig = idpConfig.findApplication(realm);
+        if (serviceConfig == null) {
+            LOG.warn("No service config found for " + realm);
+            return false;
+        }
+
+        return validateSigninEndpointAddress(serviceConfig, endpointAddress);
+    }
+
+    public boolean isValidSignoutAddress(RequestContext context, String endpointAddress, String realm)
+        throws Exception {
+        System.out.println("EA: " + endpointAddress + " " + realm);
+        if (endpointAddress == null) {
+            return true;
+        }
+
+        Idp idpConfig = (Idp) WebUtils.getAttributeFromFlowScope(context, "idpConfig");
+        if (idpConfig.isDisableLogoutAddressValidation()) {
+            return true;
+        }
+
+        Application serviceConfig = idpConfig.findApplication(realm);
+        if (serviceConfig == null) {
+            LOG.warn("No service config found for " + realm);
+            return false;
+        }
+
+        return validateSignoutEndpointAddress(serviceConfig, endpointAddress);
+    }
+
+    private boolean validateSigninEndpointAddress(Application serviceConfig, String endpointAddress) {
+        if (serviceConfig.getPassiveRequestorEndpoint() == null
+            && serviceConfig.getCompiledPassiveRequestorEndpointConstraint() == null) {
+            LOG.error("Either the 'passiveRequestorEndpoint' or the 'passiveRequestorEndpointConstraint' "
+                + "configuration values must be specified for the application");
+        } else if (serviceConfig.getPassiveRequestorEndpoint() != null
+            && serviceConfig.getPassiveRequestorEndpoint().equals(endpointAddress)) {
+            LOG.debug("The supplied endpoint address {} matches the configured passive requestor endpoint value",
+                      endpointAddress);
+            return true;
+        } else if (serviceConfig.getCompiledPassiveRequestorEndpointConstraint() != null) {
+            Matcher matcher =
+                serviceConfig.getCompiledPassiveRequestorEndpointConstraint().matcher(endpointAddress);
+            if (matcher.matches()) {
+                return true;
+            } else {
+                LOG.error("The endpointAddress value of {} does not match any of the passive requestor values",
+                          endpointAddress);
+            }
+        }
+
+        return false;
+    }
+
+    private boolean validateSignoutEndpointAddress(Application serviceConfig, String endpointAddress) {
+        System.out.println("HERE");
+        if (serviceConfig.getLogoutEndpoint() == null
+            && serviceConfig.getCompiledLogoutEndpointConstraint() == null) {
+            LOG.error("Either the 'logoutEndpoint' or the 'logoutEndpointConstraint' "
+                + "configuration values must be specified for the application");
+        } else if (serviceConfig.getLogoutEndpoint() != null
+            && serviceConfig.getLogoutEndpoint().equals(endpointAddress)) {
+            LOG.debug("The supplied endpoint address {} matches the configured logout endpoint value",
+                      endpointAddress);
+            return true;
+        } else if (serviceConfig.getCompiledLogoutEndpointConstraint() != null) {
+            Matcher matcher =
+                serviceConfig.getCompiledLogoutEndpointConstraint().matcher(endpointAddress);
+            if (matcher.matches()) {
+                return true;
+            } else {
+                LOG.error("The endpointAddress value of {} does not match any of the logout address values",
+                          endpointAddress);
+            }
+        }
+        
+        System.out.println("RET FALSE");
+
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/PassiveRequestorValidator.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/PassiveRequestorValidator.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/PassiveRequestorValidator.java
deleted file mode 100644
index 3f5be36..0000000
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/beans/PassiveRequestorValidator.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.fediz.service.idp.beans;
-
-import java.util.regex.Matcher;
-
-import org.apache.cxf.fediz.service.idp.domain.Application;
-import org.apache.cxf.fediz.service.idp.domain.Idp;
-import org.apache.cxf.fediz.service.idp.util.WebUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-import org.springframework.webflow.execution.RequestContext;
-
-/**
- * This class is responsible to validate the 'wreply' parameter for WS-Federation, or else the
- * AssertionConsumer URL address for SAML SSO, by comparing it to a regular expression.
- */
-@Component
-public class PassiveRequestorValidator {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PassiveRequestorValidator.class);
-
-    public boolean isValid(RequestContext context, String endpointAddress, String realm)
-        throws Exception {
-        if (endpointAddress == null) {
-            return true;
-        }
-        
-        Idp idpConfig = (Idp) WebUtils.getAttributeFromFlowScope(context, "idpConfig");
-        Application serviceConfig = idpConfig.findApplication(realm);
-        if (serviceConfig == null) {
-            LOG.warn("No service config found for " + realm);
-            return false;
-        }
-        
-        if (serviceConfig.getPassiveRequestorEndpoint() == null 
-            && serviceConfig.getCompiledPassiveRequestorEndpointConstraint() == null) {
-            LOG.error("Either the 'passiveRequestorEndpoint' or the 'passiveRequestorEndpointConstraint' "
-                + "configuration values must be specified for the application");
-        } else if (serviceConfig.getPassiveRequestorEndpoint() != null 
-            && serviceConfig.getPassiveRequestorEndpoint().equals(endpointAddress)) {
-            LOG.debug("The supplied endpoint address {} matches the configured passive requestor endpoint value", 
-                      endpointAddress);
-            return true;
-        } else if (serviceConfig.getCompiledPassiveRequestorEndpointConstraint() != null) {
-            Matcher matcher = 
-                serviceConfig.getCompiledPassiveRequestorEndpointConstraint().matcher(endpointAddress);
-            if (matcher.matches()) {
-                return true;
-            } else {
-                LOG.error("The endpointAddress value of {} does not match any of the passive requestor values",
-                          endpointAddress);
-            }
-        }
-        
-        return false;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Application.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Application.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Application.java
index 814e342..119d452 100644
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Application.java
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Application.java
@@ -34,7 +34,7 @@ import javax.xml.bind.annotation.XmlType;
 @XmlType(propOrder = {"realm", "role", "serviceDisplayName", "serviceDescription", "protocol",
                       "tokenType", "lifeTime", "encryptionCertificate", "requestedClaims",
                       "policyNamespace", "passiveRequestorEndpoint", "passiveRequestorEndpointConstraint", "id",
-                      "validatingCertificate", "enableAppliesTo"})
+                      "validatingCertificate", "enableAppliesTo", "logoutEndpoint", "logoutEndpointConstraint"})
 public class Application implements Serializable {
         
     private static final long serialVersionUID = 5644327504861846964L;
@@ -97,8 +97,13 @@ public class Application implements Serializable {
     // A regular expression constraint on the passiveRequestorEndpoint
     private String passiveRequestorEndpointConstraint;
     private Pattern compiledPassiveRequestorEndpointConstraint;
-    
-    
+
+    private String logoutEndpoint;
+
+    // A regular expression constraint on the logoutEndpoint
+    private String logoutEndpointConstraint;
+    private Pattern compiledLogoutEndpointConstraint;
+
     @XmlAttribute
     public int getId() {
         return id;
@@ -239,4 +244,29 @@ public class Application implements Serializable {
     public void setEnableAppliesTo(boolean useAudienceRestriction) {
         this.enableAppliesTo = useAudienceRestriction;
     }
+
+    public String getLogoutEndpoint() {
+        return logoutEndpoint;
+    }
+
+    public void setLogoutEndpoint(String logoutEndpoint) {
+        this.logoutEndpoint = logoutEndpoint;
+    }
+
+    public String getLogoutEndpointConstraint() {
+        return logoutEndpointConstraint;
+    }
+
+    public void setLogoutEndpointConstraint(String logoutEndpointConstraint) {
+        this.logoutEndpointConstraint = logoutEndpointConstraint;
+        if (logoutEndpointConstraint != null) {
+            compiledLogoutEndpointConstraint = Pattern.compile(logoutEndpointConstraint);
+        } else {
+            compiledLogoutEndpointConstraint = null;
+        }
+    }
+
+    public Pattern getCompiledLogoutEndpointConstraint() {
+        return compiledLogoutEndpointConstraint;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Idp.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Idp.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Idp.java
index d382184..13ee842 100644
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Idp.java
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/domain/Idp.java
@@ -35,7 +35,8 @@ import javax.xml.bind.annotation.XmlType;
 @XmlType(propOrder = {"realm", "uri", "serviceDisplayName", "serviceDescription", "idpUrl", "stsUrl",
                      "certificate", "certificatePassword", "provideIdpList", "useCurrentIdp", "hrds",
                      "rpSingleSignOutConfirmation", "supportedProtocols", "tokenTypesOffered", "claimTypesOffered",
-                     "authenticationURIs", "applications", "trustedIdps", "id", "rpSingleSignOutCleanupConfirmation" })
+                     "authenticationURIs", "applications", "trustedIdps", "id", "rpSingleSignOutCleanupConfirmation",
+                     "disableLogoutAddressValidation"})
 public class Idp implements Serializable {
 
     private static final long serialVersionUID = -5570301342547139039L;
@@ -117,7 +118,9 @@ public class Idp implements Serializable {
     
     // Is explicit confirmation required when the "cleanup" URL is called
     private boolean rpSingleSignOutCleanupConfirmation;
-    
+
+    private boolean disableLogoutAddressValidation;
+
     @XmlAttribute
     public int getId() {
         return id;
@@ -301,4 +304,12 @@ public class Idp implements Serializable {
         this.rpSingleSignOutCleanupConfirmation = rpSingleSignOutCleanupConfirmation;
     }
 
+    public boolean isDisableLogoutAddressValidation() {
+        return disableLogoutAddressValidation;
+    }
+
+    public void setDisableLogoutAddressValidation(boolean disableLogoutAddressValidation) {
+        this.disableLogoutAddressValidation = disableLogoutAddressValidation;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationDAOJPAImpl.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationDAOJPAImpl.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationDAOJPAImpl.java
index 307e381..8901c51 100644
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationDAOJPAImpl.java
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationDAOJPAImpl.java
@@ -203,6 +203,8 @@ public class ApplicationDAOJPAImpl implements ApplicationDAO {
         entity.setPassiveRequestorEndpoint(application.getPassiveRequestorEndpoint());
         entity.setPassiveRequestorEndpointConstraint(application.getPassiveRequestorEndpointConstraint());
         entity.setEnableAppliesTo(application.isEnableAppliesTo());
+        entity.setLogoutEndpoint(application.getLogoutEndpoint());
+        entity.setLogoutEndpointConstraint(entity.getLogoutEndpointConstraint());
     }
     
     public static Application entity2domain(ApplicationEntity entity, List<String> expandList) {
@@ -221,7 +223,9 @@ public class ApplicationDAOJPAImpl implements ApplicationDAO {
         application.setPassiveRequestorEndpoint(entity.getPassiveRequestorEndpoint());
         application.setPassiveRequestorEndpointConstraint(entity.getPassiveRequestorEndpointConstraint());
         application.setEnableAppliesTo(entity.isEnableAppliesTo());
-        
+        application.setLogoutEndpoint(entity.getLogoutEndpoint());
+        application.setLogoutEndpointConstraint(entity.getLogoutEndpointConstraint());
+
         if (expandList != null && (expandList.contains("all") || expandList.contains("claims"))) {
             for (ApplicationClaimEntity item : entity.getRequestedClaims()) {
                 RequestClaim claim = entity2domain(item);

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationEntity.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationEntity.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationEntity.java
index 1397da2..6bd8240 100644
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationEntity.java
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/ApplicationEntity.java
@@ -91,6 +91,11 @@ public class ApplicationEntity {
     // A regular expression constraint on the passiveRequestorEndpoint
     private String passiveRequestorEndpointConstraint;
 
+    private String logoutEndpoint;
+
+    // A regular expression constraint on the logoutEndpoint
+    private String logoutEndpointConstraint;
+
 
     public int getId() {
         return id;
@@ -211,4 +216,20 @@ public class ApplicationEntity {
     public void setEnableAppliesTo(boolean enableAppliesTo) {
         this.enableAppliesTo = enableAppliesTo;
     }
+
+    public String getLogoutEndpoint() {
+        return logoutEndpoint;
+    }
+
+    public void setLogoutEndpoint(String logoutEndpoint) {
+        this.logoutEndpoint = logoutEndpoint;
+    }
+
+    public String getLogoutEndpointConstraint() {
+        return logoutEndpointConstraint;
+    }
+
+    public void setLogoutEndpointConstraint(String logoutEndpointConstraint) {
+        this.logoutEndpointConstraint = logoutEndpointConstraint;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpDAOJPAImpl.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpDAOJPAImpl.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpDAOJPAImpl.java
index 5025a25..36630ba 100644
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpDAOJPAImpl.java
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpDAOJPAImpl.java
@@ -294,7 +294,8 @@ public class IdpDAOJPAImpl implements IdpDAO {
         entity.setUseCurrentIdp(idp.isUseCurrentIdp());
         entity.setRpSingleSignOutConfirmation(idp.isRpSingleSignOutConfirmation());
         entity.setRpSingleSignOutCleanupConfirmation(idp.isRpSingleSignOutCleanupConfirmation());
-        
+        entity.setDisableLogoutAddressValidation(idp.isDisableLogoutAddressValidation());
+
         entity.getAuthenticationURIs().clear();
         for (Map.Entry<String, String> item : idp.getAuthenticationURIs().entrySet()) {
             entity.getAuthenticationURIs().put(item.getKey(), item.getValue());
@@ -328,7 +329,8 @@ public class IdpDAOJPAImpl implements IdpDAO {
         idp.setUseCurrentIdp(entity.isUseCurrentIdp());
         idp.setRpSingleSignOutConfirmation(entity.isRpSingleSignOutConfirmation());
         idp.setRpSingleSignOutCleanupConfirmation(entity.isRpSingleSignOutCleanupConfirmation());
-        
+        idp.setDisableLogoutAddressValidation(entity.isDisableLogoutAddressValidation());
+
         if (expandList != null && (expandList.contains("all") || expandList.contains("applications"))) {
             for (ApplicationEntity item : entity.getApplications()) {
                 Application application = ApplicationDAOJPAImpl.entity2domain(item, expandList);

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpEntity.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpEntity.java b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpEntity.java
index 986b28d..3e55a27 100644
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpEntity.java
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/service/jpa/IdpEntity.java
@@ -134,9 +134,11 @@ public class IdpEntity {
 
     // ServiceDescription
     private String serviceDescription;
-    
+
     private boolean rpSingleSignOutCleanupConfirmation;
 
+    private boolean disableLogoutAddressValidation;
+
 
     public int getId() {
         return id;
@@ -298,4 +300,12 @@ public class IdpEntity {
         this.rpSingleSignOutCleanupConfirmation = rpSingleSignOutCleanupConfirmation;
     }
 
+    public boolean isDisableLogoutAddressValidation() {
+        return disableLogoutAddressValidation;
+    }
+
+    public void setDisableLogoutAddressValidation(boolean disableLogoutAddressValidation) {
+        this.disableLogoutAddressValidation = disableLogoutAddressValidation;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/resources/entities-realma.xml
----------------------------------------------------------------------
diff --git a/services/idp/src/main/resources/entities-realma.xml b/services/idp/src/main/resources/entities-realma.xml
index 01969a6..3968afc 100644
--- a/services/idp/src/main/resources/entities-realma.xml
+++ b/services/idp/src/main/resources/entities-realma.xml
@@ -105,6 +105,7 @@
         <property name="tokenType" value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" />
         <property name="lifeTime" value="3600" />
         <property name="passiveRequestorEndpointConstraint" value="https://localhost:?(\d)*/.*" />
+        <property name="logoutEndpointConstraint" value="https://localhost:?(\d)*/.*" />
     </bean>
 	
 	<bean id="srv-oidc" class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationEntity">
@@ -116,6 +117,7 @@
         <property name="tokenType" value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" />
         <property name="lifeTime" value="3600" />
         <property name="passiveRequestorEndpointConstraint" value="https://localhost:?(\d)*/fediz-oidc/.*" />
+        <property name="logoutEndpointConstraint" value="https://localhost:?(\d)*/.*" />
     </bean>
     
     <bean class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationClaimEntity">

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/webapp/WEB-INF/flows/federation-signin-request.xml
----------------------------------------------------------------------
diff --git a/services/idp/src/main/webapp/WEB-INF/flows/federation-signin-request.xml b/services/idp/src/main/webapp/WEB-INF/flows/federation-signin-request.xml
index b6d70a6..ec03982 100644
--- a/services/idp/src/main/webapp/WEB-INF/flows/federation-signin-request.xml
+++ b/services/idp/src/main/webapp/WEB-INF/flows/federation-signin-request.xml
@@ -103,7 +103,7 @@
     
     <action-state id="validateWReply">
         <evaluate expression="commonsURLValidator.isValid(flowRequestContext, flowScope.wreply)
-                              and passiveRequestorValidator.isValid(flowRequestContext, flowScope.wreply, flowScope.wtrealm)"/>
+                              and endpointAddressValidator.isValidSigninAddress(flowRequestContext, flowScope.wreply, flowScope.wtrealm)"/>
         <transition on="yes" to="requestRpToken" />
         <transition on="no" to="viewBadRequest" />
     </action-state>

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/webapp/WEB-INF/flows/federation-validate-request.xml
----------------------------------------------------------------------
diff --git a/services/idp/src/main/webapp/WEB-INF/flows/federation-validate-request.xml b/services/idp/src/main/webapp/WEB-INF/flows/federation-validate-request.xml
index bee5ce0..325c582 100644
--- a/services/idp/src/main/webapp/WEB-INF/flows/federation-validate-request.xml
+++ b/services/idp/src/main/webapp/WEB-INF/flows/federation-validate-request.xml
@@ -70,7 +70,8 @@
     </decision-state>
     
     <action-state id="validateWReplyForSignout">
-        <evaluate expression="commonsURLValidator.isValid(flowRequestContext, flowScope.wreply)"/>
+        <evaluate expression="commonsURLValidator.isValid(flowRequestContext, flowScope.wreply)
+                              and endpointAddressValidator.isValidSignoutAddress(flowRequestContext, flowScope.wreply, flowScope.wtrealm)"/>
         <transition on="yes" to="selectSignOutProcess" />
         <transition on="no" to="viewBadRequestAndLogout" />
     </action-state>

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/services/idp/src/main/webapp/WEB-INF/flows/saml-signin-request.xml
----------------------------------------------------------------------
diff --git a/services/idp/src/main/webapp/WEB-INF/flows/saml-signin-request.xml b/services/idp/src/main/webapp/WEB-INF/flows/saml-signin-request.xml
index 70f7452..f68e48b 100644
--- a/services/idp/src/main/webapp/WEB-INF/flows/saml-signin-request.xml
+++ b/services/idp/src/main/webapp/WEB-INF/flows/saml-signin-request.xml
@@ -89,7 +89,7 @@
             <evaluate expression="authnRequestParser.retrieveConsumerURL(flowRequestContext)" 
                       result="flowScope.consumerURL"/>
         </on-entry>
-        <evaluate expression="passiveRequestorValidator.isValid(flowRequestContext, flowScope.consumerURL, flowScope.realm)"/>
+        <evaluate expression="endpointAddressValidator.isValidSigninAddress(flowRequestContext, flowScope.consumerURL, flowScope.realm)"/>
         <transition on="yes" to="requestRpToken" />
         <transition on="no" to="viewBadRequest" />
     </action-state>

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/systests/idp/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java
----------------------------------------------------------------------
diff --git a/systests/idp/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java b/systests/idp/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java
index b8c0e50..10a6ce7 100644
--- a/systests/idp/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java
+++ b/systests/idp/src/test/java/org/apache/cxf/fediz/systests/idp/IdpTest.java
@@ -89,7 +89,7 @@ public class IdpTest {
         WSSConfig.init();
     }
 
-    private static Tomcat startServer(boolean idp, String port) 
+    private static Tomcat startServer(boolean idp, String port)
         throws ServletException, LifecycleException, IOException {
         Tomcat server = new Tomcat();
         server.setPort(0);
@@ -132,7 +132,7 @@ public class IdpTest {
     public static void cleanup() {
         shutdownServer(idpServer);
     }
-    
+
     private static void shutdownServer(Tomcat server) {
         try {
             if (server != null && server.getServer() != null
@@ -197,7 +197,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     @org.junit.Test
     public void testSuccessfulSSOInvokeOnIdP() throws Exception {
         String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
@@ -213,7 +213,7 @@ public class IdpTest {
         final WebClient webClient = new WebClient();
         webClient.getOptions().setUseInsecureSSL(true);
         webClient.addRequestHeader("Authorization", "Basic " + Base64.encode((user + ":" + password).getBytes()));
-        
+
         //
         // First invocation
         //
@@ -235,14 +235,14 @@ public class IdpTest {
         }
 
         Assert.assertNotNull(wresult);
-        
+
         //
         // Second invocation - change the credentials to make sure the session is set up correctly
-        // 
+        //
 
         webClient.removeRequestHeader("Authorization");
         webClient.addRequestHeader("Authorization", "Basic " + Base64.encode(("mallory" + ":" + password).getBytes()));
-        
+
         webClient.getOptions().setJavaScriptEnabled(false);
         idpPage = webClient.getPage(url);
         webClient.getOptions().setJavaScriptEnabled(true);
@@ -260,7 +260,7 @@ public class IdpTest {
         }
 
         Assert.assertNotNull(wresult);
-        
+
         webClient.close();
     }
 
@@ -441,7 +441,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     // Send an unknown wa value
     @org.junit.Test
     public void testBadWa() throws Exception {
@@ -471,7 +471,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     // Send an unknown whr value
     @org.junit.Test
     public void testBadWHR() throws Exception {
@@ -501,7 +501,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     // Send an unknown wtrealm value
     @org.junit.Test
     public void testBadWtRealm() throws Exception {
@@ -531,7 +531,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     // Send an malformed wreply value
     @org.junit.Test
     public void testMalformedWReply() throws Exception {
@@ -561,7 +561,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     // Send a bad wreply value
     @org.junit.Test
     public void testBadWReply() throws Exception {
@@ -569,7 +569,7 @@ public class IdpTest {
         url += "wa=wsignin1.0";
         url += "&whr=urn:org:apache:cxf:fediz:idp:realm-A";
         url += "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld";
-        String wreply = "https://www.apache.org:" + getRpHttpsPort() + "/" 
+        String wreply = "https://www.apache.org:" + getRpHttpsPort() + "/"
             + getServletContextName() + "/secure/fedservlet";
         url += "&wreply=" + wreply;
 
@@ -592,7 +592,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     @org.junit.Test
     public void testValidWReplyWrongApplication() throws Exception {
         String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
@@ -621,7 +621,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     @org.junit.Test
     public void testWReplyExactMatchingSuccess() throws Exception {
         String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
@@ -645,14 +645,14 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     @org.junit.Test
     public void testWReplyExactMatchingFailure() throws Exception {
         String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
         url += "wa=wsignin1.0";
         url += "&whr=urn:org:apache:cxf:fediz:idp:realm-A";
         url += "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld3";
-        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() 
+        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName()
             + "/secure/fedservlet/blah";
         url += "&wreply=" + wreply;
 
@@ -675,7 +675,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     @org.junit.Test
     public void testNoEndpointAddressOrConstraint() throws Exception {
         String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
@@ -705,8 +705,8 @@ public class IdpTest {
 
         webClient.close();
     }
-    
-    // Send a bad wreply value. This will pass the reg ex validation but fail the commons-validator 
+
+    // Send a bad wreply value. This will pass the reg ex validation but fail the commons-validator
     // validation
     @org.junit.Test
     public void testWReplyWithDoubleSlashes() throws Exception {
@@ -714,7 +714,7 @@ public class IdpTest {
         url += "wa=wsignin1.0";
         url += "&whr=urn:org:apache:cxf:fediz:idp:realm-A";
         url += "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld";
-        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() 
+        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName()
             + "/secure//fedservlet";
         url += "&wreply=" + wreply;
 
@@ -737,8 +737,8 @@ public class IdpTest {
 
         webClient.close();
     }
-  
-    
+
+
     @Test
     public void testIdPLogout() throws Exception {
 
@@ -752,7 +752,7 @@ public class IdpTest {
 
         String user = "alice";
         String password = "ecila";
-        
+
         CookieManager cookieManager = new CookieManager();
 
         WebClient webClient = new WebClient();
@@ -797,7 +797,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     @Test
     public void testIdPLogoutCleanup() throws Exception {
 
@@ -811,7 +811,7 @@ public class IdpTest {
 
         String user = "alice";
         String password = "ecila";
-        
+
         CookieManager cookieManager = new CookieManager();
 
         WebClient webClient = new WebClient();
@@ -852,7 +852,7 @@ public class IdpTest {
 
         webClient.close();
     }
-    
+
     @Test
     public void testIdPLogoutCleanupWithBadWReply() throws Exception {
 
@@ -866,7 +866,7 @@ public class IdpTest {
 
         String user = "alice";
         String password = "ecila";
-        
+
         CookieManager cookieManager = new CookieManager();
 
         WebClient webClient = new WebClient();
@@ -883,7 +883,7 @@ public class IdpTest {
         webClient.close();
 
         // 2. now we logout from IdP using a bad wreply
-        String badWReply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() 
+        String badWReply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName()
             + "/secure//fedservlet";
         String idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa="
             + FederationConstants.ACTION_SIGNOUT_CLEANUP;
@@ -914,4 +914,318 @@ public class IdpTest {
 
         webClient.close();
     }
+
+    @Test
+    public void testIdPLogoutWithWreplyConstraint() throws Exception {
+
+        // 1. First let's login to the IdP
+        String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
+        url += "wa=wsignin1.0";
+        url += "&whr=urn:org:apache:cxf:fediz:idp:realm-A";
+        url += "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld";
+        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure/fedservlet";
+        url += "&wreply=" + wreply;
+
+        String user = "alice";
+        String password = "ecila";
+
+        CookieManager cookieManager = new CookieManager();
+
+        WebClient webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getCredentialsProvider().setCredentials(
+            new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())),
+            new UsernamePasswordCredentials(user, password));
+
+        webClient.getOptions().setJavaScriptEnabled(false);
+        HtmlPage idpPage = webClient.getPage(url);
+        webClient.getOptions().setJavaScriptEnabled(true);
+        Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText());
+        webClient.close();
+
+        // 2. now we logout from IdP
+        String logoutWReply = "https://localhost:12345";
+        String idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa="
+            + FederationConstants.ACTION_SIGNOUT + "&wreply=" + logoutWReply
+            + "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld";
+
+        webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        idpPage = webClient.getPage(idpLogoutUrl);
+
+        Assert.assertEquals("IDP SignOut Confirmation Response Page", idpPage.getTitleText());
+
+        HtmlForm form = idpPage.getFormByName("signoutconfirmationresponseform");
+        HtmlSubmitInput button = form.getInputByName("_eventId_submit");
+        button.click();
+
+        webClient.close();
+
+        // 3. now we try to access the idp without authentication but with the existing cookies
+        // to see if we are really logged out
+        webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
+        idpPage = webClient.getPage(url);
+
+        Assert.assertEquals(401, idpPage.getWebResponse().getStatusCode());
+
+        webClient.close();
+    }
+
+    @Test
+    public void testIdPLogoutWithWreplyBadAddress() throws Exception {
+
+        // 1. First let's login to the IdP
+        String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
+        url += "wa=wsignin1.0";
+        url += "&whr=urn:org:apache:cxf:fediz:idp:realm-A";
+        url += "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld";
+        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure/fedservlet";
+        url += "&wreply=" + wreply;
+
+        String user = "alice";
+        String password = "ecila";
+
+        CookieManager cookieManager = new CookieManager();
+
+        WebClient webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getCredentialsProvider().setCredentials(
+            new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())),
+            new UsernamePasswordCredentials(user, password));
+
+        webClient.getOptions().setJavaScriptEnabled(false);
+        HtmlPage idpPage = webClient.getPage(url);
+        webClient.getOptions().setJavaScriptEnabled(true);
+        Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText());
+        webClient.close();
+
+        // 2. now we logout from IdP
+        String logoutWReply = "https://localhost:123456";
+        String idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa="
+            + FederationConstants.ACTION_SIGNOUT + "&wreply=" + logoutWReply
+            + "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld";
+
+        webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        try {
+            webClient.getPage(idpLogoutUrl);
+            Assert.fail("Failure expected on a non-matching wreply address");
+        } catch (FailingHttpStatusCodeException ex) {
+            Assert.assertEquals(ex.getStatusCode(), 400);
+        }
+
+        webClient.close();
+    }
+
+    @Test
+    public void testIdPLogoutWithNoRealm() throws Exception {
+
+        // 1. First let's login to the IdP
+        String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
+        url += "wa=wsignin1.0";
+        url += "&whr=urn:org:apache:cxf:fediz:idp:realm-A";
+        url += "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld";
+        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure/fedservlet";
+        url += "&wreply=" + wreply;
+
+        String user = "alice";
+        String password = "ecila";
+
+        CookieManager cookieManager = new CookieManager();
+
+        WebClient webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getCredentialsProvider().setCredentials(
+            new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())),
+            new UsernamePasswordCredentials(user, password));
+
+        webClient.getOptions().setJavaScriptEnabled(false);
+        HtmlPage idpPage = webClient.getPage(url);
+        webClient.getOptions().setJavaScriptEnabled(true);
+        Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText());
+        webClient.close();
+
+        // 2. now we logout from IdP
+        String logoutWReply = "https://localhost:12345";
+        String idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa="
+            + FederationConstants.ACTION_SIGNOUT + "&wreply=" + logoutWReply;
+
+        webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        try {
+            webClient.getPage(idpLogoutUrl);
+            Assert.fail("Failure expected on a non-matching wreply address");
+        } catch (FailingHttpStatusCodeException ex) {
+            Assert.assertEquals(ex.getStatusCode(), 400);
+        }
+
+        webClient.close();
+    }
+
+    @Test
+    public void testIdPLogoutWithWreplyAddress() throws Exception {
+
+        // 1. First let's login to the IdP
+        String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
+        url += "wa=wsignin1.0";
+        url += "&whr=urn:org:apache:cxf:fediz:idp:realm-A";
+        url += "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld3";
+        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure/fedservlet";
+        url += "&wreply=" + wreply;
+
+        String user = "alice";
+        String password = "ecila";
+
+        CookieManager cookieManager = new CookieManager();
+
+        WebClient webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getCredentialsProvider().setCredentials(
+            new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())),
+            new UsernamePasswordCredentials(user, password));
+
+        webClient.getOptions().setJavaScriptEnabled(false);
+        HtmlPage idpPage = webClient.getPage(url);
+        webClient.getOptions().setJavaScriptEnabled(true);
+        Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText());
+        webClient.close();
+
+        // 2. now we logout from IdP
+        String logoutWReply = "https://localhost:12345";
+        String idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa="
+            + FederationConstants.ACTION_SIGNOUT + "&wreply=" + logoutWReply
+            + "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld3";
+
+        webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        idpPage = webClient.getPage(idpLogoutUrl);
+
+        Assert.assertEquals("IDP SignOut Confirmation Response Page", idpPage.getTitleText());
+
+        HtmlForm form = idpPage.getFormByName("signoutconfirmationresponseform");
+        HtmlSubmitInput button = form.getInputByName("_eventId_submit");
+        button.click();
+
+        webClient.close();
+
+        // 3. now we try to access the idp without authentication but with the existing cookies
+        // to see if we are really logged out
+        webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
+        idpPage = webClient.getPage(url);
+
+        Assert.assertEquals(401, idpPage.getWebResponse().getStatusCode());
+
+        webClient.close();
+    }
+
+    @Test
+    public void testIdPLogoutWithBadAddress() throws Exception {
+
+        // 1. First let's login to the IdP
+        String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
+        url += "wa=wsignin1.0";
+        url += "&whr=urn:org:apache:cxf:fediz:idp:realm-A";
+        url += "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld3";
+        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure/fedservlet";
+        url += "&wreply=" + wreply;
+
+        String user = "alice";
+        String password = "ecila";
+
+        CookieManager cookieManager = new CookieManager();
+
+        WebClient webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getCredentialsProvider().setCredentials(
+            new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())),
+            new UsernamePasswordCredentials(user, password));
+
+        webClient.getOptions().setJavaScriptEnabled(false);
+        HtmlPage idpPage = webClient.getPage(url);
+        webClient.getOptions().setJavaScriptEnabled(true);
+        Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText());
+        webClient.close();
+
+        // 2. now we logout from IdP
+        String logoutWReply = "https://localhost:123456";
+        String idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa="
+            + FederationConstants.ACTION_SIGNOUT + "&wreply=" + logoutWReply
+            + "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld3";
+
+        webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        try {
+            webClient.getPage(idpLogoutUrl);
+            Assert.fail("Failure expected on a non-matching wreply address");
+        } catch (FailingHttpStatusCodeException ex) {
+            Assert.assertEquals(ex.getStatusCode(), 400);
+        }
+
+        webClient.close();
+    }
+
+    @Test
+    public void testIdPLogoutWithNoConfiguredConstraint() throws Exception {
+
+        // 1. First let's login to the IdP
+        String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?";
+        url += "wa=wsignin1.0";
+        url += "&whr=urn:org:apache:cxf:fediz:idp:realm-A";
+        url += "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld2";
+        String wreply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure2/fedservlet";
+        url += "&wreply=" + wreply;
+
+        String user = "alice";
+        String password = "ecila";
+
+        CookieManager cookieManager = new CookieManager();
+
+        WebClient webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getCredentialsProvider().setCredentials(
+            new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())),
+            new UsernamePasswordCredentials(user, password));
+
+        webClient.getOptions().setJavaScriptEnabled(false);
+        HtmlPage idpPage = webClient.getPage(url);
+        webClient.getOptions().setJavaScriptEnabled(true);
+        Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText());
+        webClient.close();
+
+        // 2. now we logout from IdP
+        String logoutWReply = "https://localhost:12345";
+        String idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa="
+            + FederationConstants.ACTION_SIGNOUT + "&wreply=" + logoutWReply
+            + "&wtrealm=urn:org:apache:cxf:fediz:fedizhelloworld2";
+
+        webClient = new WebClient();
+        webClient.setCookieManager(cookieManager);
+        webClient.getOptions().setUseInsecureSSL(true);
+        try {
+            webClient.getPage(idpLogoutUrl);
+            Assert.fail("Failure expected on a non-matching wreply address");
+        } catch (FailingHttpStatusCodeException ex) {
+            Assert.assertEquals(ex.getStatusCode(), 400);
+        }
+
+        webClient.close();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/systests/idp/src/test/resources/realma/entities-realma.xml
----------------------------------------------------------------------
diff --git a/systests/idp/src/test/resources/realma/entities-realma.xml b/systests/idp/src/test/resources/realma/entities-realma.xml
index 49506fa..108464c 100644
--- a/systests/idp/src/test/resources/realma/entities-realma.xml
+++ b/systests/idp/src/test/resources/realma/entities-realma.xml
@@ -109,6 +109,7 @@
         <property name="lifeTime" value="3600" />
         <property name="passiveRequestorEndpointConstraint" 
                   value="https://localhost:(\d)*/(\w)*helloworld(\w)*/secure/.*" />
+        <property name="logoutEndpointConstraint" value="https://localhost:(\d)*" />
     </bean>
     
     <bean id="srv-fedizhelloworld2" class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationEntity">
@@ -133,6 +134,7 @@
         <property name="lifeTime" value="3600" />
         <property name="passiveRequestorEndpoint" 
                   value="https://localhost:${rp.https.port}/fedizhelloworld/secure/fedservlet" />
+        <property name="logoutEndpoint" value="https://localhost:12345" />
     </bean>
     
     <bean id="srv-fedizhelloworld4" class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationEntity">

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/systests/oidc/src/test/resources/realma/entities-realma.xml
----------------------------------------------------------------------
diff --git a/systests/oidc/src/test/resources/realma/entities-realma.xml b/systests/oidc/src/test/resources/realma/entities-realma.xml
index 95a91eb..95353f2 100644
--- a/systests/oidc/src/test/resources/realma/entities-realma.xml
+++ b/systests/oidc/src/test/resources/realma/entities-realma.xml
@@ -35,7 +35,8 @@
         <property name="certificatePassword" value="realma" />
         <property name="stsUrl" value="https://localhost:${idp.https.port}/fediz-idp-sts/REALMA" />
         <property name="idpUrl" value="https://localhost:${idp.https.port}/fediz-idp/federation" />
-        <property name="rpSingleSignOutConfirmation" value="true"/>
+        <property name="rpSingleSignOutConfirmation" value="false"/>
+        <property name="disableLogoutAddressValidation" value="true"/>
         <property name="supportedProtocols">
             <util:list>
                 <value>http://docs.oasis-open.org/wsfed/federation/200706

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5eba7a0c/systests/tomcat7/src/test/resources/realma/entities-realma.xml
----------------------------------------------------------------------
diff --git a/systests/tomcat7/src/test/resources/realma/entities-realma.xml b/systests/tomcat7/src/test/resources/realma/entities-realma.xml
index f947274..95bfc9d 100644
--- a/systests/tomcat7/src/test/resources/realma/entities-realma.xml
+++ b/systests/tomcat7/src/test/resources/realma/entities-realma.xml
@@ -106,6 +106,7 @@
         <property name="lifeTime" value="3600" />
         <property name="passiveRequestorEndpointConstraint" 
                   value="https://localhost:(\d)*/(\w)*helloworld(\w)*/secure/.*" />
+        <property name="logoutEndpointConstraint" value="https://localhost:?(\d)*/.*" />
     </bean>
     
     <bean class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationClaimEntity">


Mime
View raw message