Repository: cxf-fediz Updated Branches: refs/heads/1.2.x-fixes 66f1ffa4f -> bf5f471d4
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/30e0d900 Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/30e0d900 Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/30e0d900 Branch: refs/heads/1.2.x-fixes Commit: 30e0d900e3eb77f0417cd41708f2340c11310d25 Parents: 66f1ffa Author: Colm O hEigeartaigh <[email protected]> Authored: Thu Apr 13 13:01:12 2017 +0100 Committer: Colm O hEigeartaigh <[email protected]> Committed: Thu Apr 13 14:50:03 2017 +0100 ---------------------------------------------------------------------- .../core/processor/FederationProcessorImpl.java | 7 + .../core/federation/FederationLogoutTest.java | 46 +- .../idp/beans/EndpointAddressValidator.java | 128 +++++ .../fediz/service/idp/domain/Application.java | 35 +- .../cxf/fediz/service/idp/domain/Idp.java | 15 +- .../idp/service/jpa/ApplicationDAOJPAImpl.java | 6 +- .../idp/service/jpa/ApplicationEntity.java | 20 + .../service/idp/service/jpa/IdpDAOJPAImpl.java | 6 +- .../service/idp/service/jpa/IdpEntity.java | 12 +- .../idp/src/main/resources/entities-realma.xml | 14 + .../WEB-INF/federation-validate-request.xml | 23 +- .../apache/cxf/fediz/systests/idp/IdpTest.java | 533 ++++++++++++++++++- .../test/resources/realma/entities-realma.xml | 2 + .../test/resources/realma/entities-realma.xml | 1 + 14 files changed, 794 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/30e0d900/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 fbf7600..646f267 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 @@ -538,6 +538,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/30e0d900/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 36a6d96..fd2163e 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); @@ -202,8 +206,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); @@ -217,7 +222,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"); @@ -227,8 +232,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); @@ -252,8 +258,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); @@ -277,8 +284,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); http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/30e0d900/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/30e0d900/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 43c7e8a..fca01e1 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,6 +34,7 @@ import javax.xml.bind.annotation.XmlType; @XmlType(propOrder = {"realm", "role", "serviceDisplayName", "serviceDescription", "protocol", "tokenType", "lifeTime", "encryptionCertificate", "requestedClaims", "policyNamespace", "passiveRequestorEndpoint", "passiveRequestorEndpointConstraint", "id" }) + "logoutEndpoint", "logoutEndpointConstraint"}) public class Application implements Serializable { private static final long serialVersionUID = 5644327504861846964L; @@ -90,8 +91,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; @@ -216,4 +222,29 @@ public class Application implements Serializable { public Pattern getCompiledPassiveRequestorEndpointConstraint() { return compiledPassiveRequestorEndpointConstraint; } + + 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/30e0d900/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 389348b..bc4fe27 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/30e0d900/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 4829764..5f56a4d 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 @@ -201,6 +201,8 @@ public class ApplicationDAOJPAImpl implements ApplicationDAO { entity.setPolicyNamespace(application.getPolicyNamespace()); entity.setPassiveRequestorEndpoint(application.getPassiveRequestorEndpoint()); entity.setPassiveRequestorEndpointConstraint(application.getPassiveRequestorEndpointConstraint()); + entity.setLogoutEndpoint(application.getLogoutEndpoint()); + entity.setLogoutEndpointConstraint(entity.getLogoutEndpointConstraint()); } public static Application entity2domain(ApplicationEntity entity, List<String> expandList) { @@ -217,7 +219,9 @@ public class ApplicationDAOJPAImpl implements ApplicationDAO { application.setPolicyNamespace(entity.getPolicyNamespace()); application.setPassiveRequestorEndpoint(entity.getPassiveRequestorEndpoint()); application.setPassiveRequestorEndpointConstraint(entity.getPassiveRequestorEndpointConstraint()); - + 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/30e0d900/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 e450132..7175a7d 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 @@ -85,6 +85,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; @@ -190,4 +195,19 @@ public class ApplicationEntity { this.passiveRequestorEndpointConstraint = passiveRequestorEndpointConstraint; } + 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/30e0d900/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 c553400..502568f 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/30e0d900/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 1eda135..0ea23f4 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/30e0d900/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 2965df9..cdb116f 100644 --- a/services/idp/src/main/resources/entities-realma.xml +++ b/services/idp/src/main/resources/entities-realma.xml @@ -105,6 +105,20 @@ <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"> + <property name="realm" value="urn:org:apache:cxf:fediz:oidc" /> + <property name="protocol" value="http://docs.oasis-open.org/wsfed/federation/200706" /> + <property name="serviceDisplayName" value="OIDC Provider" /> + <property name="serviceDescription" value="OpenID Connect Provider" /> + <property name="role" value="ApplicationServiceType" /> + <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)*/.*" /> +>>>>>>> 5eba7a0... FEDIZ-200 - Make one of logoutEndpoint or logoutEndpointConstraint mandatory in the IDP </bean> <bean class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationClaimEntity"> http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/30e0d900/services/idp/src/main/webapp/WEB-INF/federation-validate-request.xml ---------------------------------------------------------------------- diff --git a/services/idp/src/main/webapp/WEB-INF/federation-validate-request.xml b/services/idp/src/main/webapp/WEB-INF/federation-validate-request.xml index 733d5d3..d37b13a 100644 --- a/services/idp/src/main/webapp/WEB-INF/federation-validate-request.xml +++ b/services/idp/src/main/webapp/WEB-INF/federation-validate-request.xml @@ -40,7 +40,7 @@ </on-entry> <if test="requestParameters.wa == 'wsignout1.0' or requestParameters.wa == 'wsignoutcleanup1.0'" - then="selectSignOutProcess" /> + then="validateWReplyForSignout" /> <if test="requestParameters.wa == 'wsignin1.0'" then="selectWsFedProcess" else="selectSAMLProcess" /> @@ -63,15 +63,16 @@ </decision-state> <action-state id="validateWReplyForSignout"> - <evaluate expression="commonsURLValidator.isValid(flowRequestContext, flowScope.wreply)"/> + <on-entry> + <evaluate expression="@org.apache.cxf.fediz.service.idp.util.WebUtils@getHttpHeader(flowRequestContext, 'Referer')" result="flowScope.wreply"/> + </on-entry> + <evaluate expression="commonsURLValidator.isValid(flowRequestContext, flowScope.wreply) + and endpointAddressValidator.isValidSignoutAddress(flowRequestContext, flowScope.wreply, flowScope.wtrealm)"/> <transition on="yes" to="selectSignOutProcess" /> - <transition on="no" to="viewBadRequest" /> + <transition on="no" to="viewBadRequestAndLogout" /> </action-state> <decision-state id="selectSignOutProcess"> - <on-entry> - <evaluate expression="@org.apache.cxf.fediz.service.idp.util.WebUtils@getHttpHeader(flowRequestContext, 'Referer')" result="flowScope.wreply"/> - </on-entry> <if test="requestParameters.wa == 'wsignout1.0' and flowScope.idpConfig.rpSingleSignOutConfirmation == true or requestParameters.wa == 'wsignoutcleanup1.0' and flowScope.idpConfig.rpSingleSignOutCleanupConfirmation == true" @@ -185,6 +186,16 @@ </on-entry> </end-state> + <end-state id="viewBadRequestAndLogout" view="genericerror"> + <on-entry> + <evaluate expression="homeRealmReminder.removeCookie(flowRequestContext)" /> + <evaluate expression="logoutAction.submit(flowRequestContext)" /> + <evaluate + expression="externalContext.nativeResponse.setStatus(400,flowRequestContext.currentTransition.toString())" /> + <!--<set name="requestScope.reason" value="flowRequestContext.currentTransition" />--> + </on-entry> + </end-state> + <!-- abnormal exit point : Http 500 Internal Server Error --> <end-state id="scInternalServerError" view="genericerror"> <on-entry> http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/30e0d900/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 b0e5816..61d10ff 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 @@ -84,7 +84,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); @@ -127,7 +127,7 @@ public class IdpTest { public static void cleanup() { shutdownServer(idpServer); } - + private static void shutdownServer(Tomcat server) { try { if (server != null && server.getServer() != null @@ -190,7 +190,7 @@ public class IdpTest { Assert.assertNotNull(wresult); } - + @org.junit.Test public void testSuccessfulSSOInvokeOnIdP() throws Exception { String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?"; @@ -206,7 +206,7 @@ public class IdpTest { final WebClient webClient = new WebClient(); webClient.getOptions().setUseInsecureSSL(true); webClient.addRequestHeader("Authorization", "Basic " + Base64.encode((user + ":" + password).getBytes())); - + // // First invocation // @@ -228,14 +228,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); @@ -253,6 +253,7 @@ public class IdpTest { } Assert.assertNotNull(wresult); + } @Test @@ -420,7 +421,7 @@ public class IdpTest { Assert.assertEquals(ex.getStatusCode(), 400); } } - + // Send an unknown wa value @org.junit.Test public void testBadWa() throws Exception { @@ -448,7 +449,7 @@ public class IdpTest { Assert.assertEquals(ex.getStatusCode(), 400); } } - + // Send an unknown whr value @org.junit.Test public void testBadWHR() throws Exception { @@ -476,7 +477,7 @@ public class IdpTest { Assert.assertEquals(ex.getStatusCode(), 500); } } - + // Send an unknown wtrealm value @org.junit.Test public void testBadWtRealm() throws Exception { @@ -504,7 +505,7 @@ public class IdpTest { Assert.assertEquals(ex.getStatusCode(), 400); } } - + // Send an malformed wreply value @org.junit.Test public void testMalformedWReply() throws Exception { @@ -532,7 +533,7 @@ public class IdpTest { Assert.assertEquals(ex.getStatusCode(), 400); } } - + // Send a bad wreply value @org.junit.Test public void testBadWReply() throws Exception { @@ -540,7 +541,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; @@ -561,7 +562,7 @@ public class IdpTest { Assert.assertEquals(ex.getStatusCode(), 400); } } - + @org.junit.Test public void testValidWReplyWrongApplication() throws Exception { String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?"; @@ -588,7 +589,7 @@ public class IdpTest { Assert.assertEquals(ex.getStatusCode(), 400); } } - + @org.junit.Test public void testWReplyExactMatchingSuccess() throws Exception { String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?"; @@ -610,14 +611,14 @@ public class IdpTest { webClient.getOptions().setJavaScriptEnabled(false); webClient.getPage(url); } - + @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; @@ -638,7 +639,7 @@ public class IdpTest { Assert.assertEquals(ex.getStatusCode(), 400); } } - + @org.junit.Test public void testNoEndpointAddressOrConstraint() throws Exception { String url = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?"; @@ -666,8 +667,8 @@ public class IdpTest { Assert.assertEquals(ex.getStatusCode(), 400); } } - - // 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 { @@ -675,7 +676,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; @@ -697,4 +698,494 @@ public class IdpTest { } } + @Test + public void testIdPLogout() 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 idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa=" + + FederationConstants.ACTION_SIGNOUT; + + 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 testIdPLogoutCleanup() 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 idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa=" + + FederationConstants.ACTION_SIGNOUT_CLEANUP; + + webClient = new WebClient(); + webClient.setCookieManager(cookieManager); + webClient.getOptions().setUseInsecureSSL(true); + idpPage = webClient.getPage(idpLogoutUrl); + + Assert.assertEquals("IDP SignOut Response Page", idpPage.getTitleText()); + + 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 testIdPLogoutCleanupWithBadWReply() 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 using a bad wreply + String badWReply = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + + "/secure//fedservlet"; + String idpLogoutUrl = "https://localhost:" + getIdpHttpsPort() + "/fediz-idp/federation?wa=" + + FederationConstants.ACTION_SIGNOUT_CLEANUP; + idpLogoutUrl += "&wreply=" + badWReply; + + webClient = new WebClient(); + webClient.setCookieManager(cookieManager); + webClient.getOptions().setUseInsecureSSL(true); + try { + webClient.getPage(idpLogoutUrl); + Assert.fail("Failure expected on a bad wreply value"); + } catch (FailingHttpStatusCodeException ex) { + Assert.assertEquals(ex.getStatusCode(), 400); + } + + 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. Even though an error was thrown on a bad wreply, we should still + // be 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 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(); + } + +>>>>>>> 5eba7a0... FEDIZ-200 - Make one of logoutEndpoint or logoutEndpointConstraint mandatory in the IDP } http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/30e0d900/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 76008b1..51ca9df 100644 --- a/systests/idp/src/test/resources/realma/entities-realma.xml +++ b/systests/idp/src/test/resources/realma/entities-realma.xml @@ -108,6 +108,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)*/(\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"> @@ -132,6 +133,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/30e0d900/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">
