[FEDIZ-124] - Fediz-plugin for Tomcat 8
Project: http://git-wip-us.apache.org/repos/asf/cxf-fediz/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf-fediz/commit/0b2c2218 Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/0b2c2218 Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/0b2c2218 Branch: refs/heads/master Commit: 0b2c2218bf313825a4bc03fbdf5207f431df22e5 Parents: c9a72ed Author: Colm O hEigeartaigh <[email protected]> Authored: Thu Sep 3 16:59:31 2015 +0100 Committer: Colm O hEigeartaigh <[email protected]> Committed: Thu Sep 3 16:59:31 2015 +0100 ---------------------------------------------------------------------- plugins/pom.xml | 1 + plugins/tomcat8/README.txt | 10 + plugins/tomcat8/pom.xml | 77 ++++ plugins/tomcat8/src/main/assembly/assembly.xml | 18 + .../fediz/tomcat/FederationAuthenticator.java | 423 +++++++++++++++++++ .../fediz/tomcat/FederationPrincipalImpl.java | 52 +++ .../tomcat/handler/TomcatLogoutHandler.java | 58 +++ .../tomcat/handler/TomcatSigninHandler.java | 101 +++++ .../src/test/resources/logging.properties | 52 +++ pom.xml | 1 + systests/pom.xml | 3 +- systests/tomcat8/pom.xml | 243 +++++++++++ .../BadWReqCallbackHandler.java | 48 +++ .../cxf/fediz/integrationtests/BadWReqTest.java | 197 +++++++++ .../integrationtests/ClientCertificateTest.java | 179 ++++++++ .../EntityExpansionAttackTest.java | 247 +++++++++++ .../integrationtests/HOKCallbackHandler.java | 48 +++ .../fediz/integrationtests/HolderOfKeyTest.java | 249 +++++++++++ .../integrationtests/TestCallbackHandler.java | 48 +++ .../cxf/fediz/integrationtests/TomcatTest.java | 181 ++++++++ .../cxf/fediz/integrationtests/WReqTest.java | 255 +++++++++++ systests/tomcat8/src/test/resources/alice.cer | Bin 0 -> 873 bytes .../tomcat8/src/test/resources/alice_client.jks | Bin 0 -> 2225 bytes systests/tomcat8/src/test/resources/client.jks | Bin 0 -> 2061 bytes .../tomcat8/src/test/resources/clienttrust.jks | Bin 0 -> 1512 bytes systests/tomcat8/src/test/resources/entity.xml | 25 ++ .../tomcat8/src/test/resources/fediz_config.xml | 43 ++ .../test/resources/fediz_config_bad_wreq.xml | 39 ++ .../test/resources/fediz_config_client_cert.xml | 45 ++ .../src/test/resources/fediz_config_hok.xml | 39 ++ .../src/test/resources/fediz_config_wreq.xml | 39 ++ .../src/test/resources/logging.properties | 54 +++ systests/tomcat8/src/test/resources/server.jks | Bin 0 -> 3717 bytes 33 files changed, 2774 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/plugins/pom.xml ---------------------------------------------------------------------- diff --git a/plugins/pom.xml b/plugins/pom.xml index c46461e..e76ca6a 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -32,6 +32,7 @@ <modules> <module>core</module> <module>tomcat7</module> + <module>tomcat8</module> <module>jetty8</module> <module>spring</module> <module>spring2</module> http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/plugins/tomcat8/README.txt ---------------------------------------------------------------------- diff --git a/plugins/tomcat8/README.txt b/plugins/tomcat8/README.txt new file mode 100644 index 0000000..94565bb --- /dev/null +++ b/plugins/tomcat8/README.txt @@ -0,0 +1,10 @@ +Fediz configuration in Tomcat +----------------------------- + +The Tomcat installation must be updated before a Web Application can be deployed. + +The following wiki page gives instructions how to do that: +http://cxf.apache.org/fediz-tomcat.html + +The following wiki page explains the fediz configuration which is Container independent: +http://cxf.apache.org/fediz-configuration.html http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/plugins/tomcat8/pom.xml ---------------------------------------------------------------------- diff --git a/plugins/tomcat8/pom.xml b/plugins/tomcat8/pom.xml new file mode 100644 index 0000000..91382a2 --- /dev/null +++ b/plugins/tomcat8/pom.xml @@ -0,0 +1,77 @@ +<?xml version="1.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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.cxf.fediz</groupId> + <artifactId>plugin</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>fediz-tomcat8</artifactId> + <name>Apache Fediz Plugin for Tomcat 8</name> + <packaging>jar</packaging> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-catalina</artifactId> + <version>${tomcat8.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.cxf.fediz</groupId> + <artifactId>fediz-core</artifactId> + <version>${project.version}</version> + <type>jar</type> + <scope>compile</scope> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <id>zip-file</id> + <phase>package</phase> + <goals> + <goal>attached</goal> + </goals> + <configuration> + <descriptors> + <descriptor>src/main/assembly/assembly.xml</descriptor> + </descriptors> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/plugins/tomcat8/src/main/assembly/assembly.xml ---------------------------------------------------------------------- diff --git a/plugins/tomcat8/src/main/assembly/assembly.xml b/plugins/tomcat8/src/main/assembly/assembly.xml new file mode 100644 index 0000000..fb0d6aa --- /dev/null +++ b/plugins/tomcat8/src/main/assembly/assembly.xml @@ -0,0 +1,18 @@ +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 +http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>zip-with-dependencies</id> + <formats> + <format>zip</format> + </formats> + <includeBaseDirectory>false</includeBaseDirectory> + <dependencySets> + <dependencySet> + <outputDirectory>/</outputDirectory> + <useProjectArtifact>true</useProjectArtifact> + <unpack>false</unpack> + <scope>runtime</scope> + </dependencySet> + </dependencySets> +</assembly> http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/FederationAuthenticator.java ---------------------------------------------------------------------- diff --git a/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/FederationAuthenticator.java b/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/FederationAuthenticator.java new file mode 100644 index 0000000..c5d78e5 --- /dev/null +++ b/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/FederationAuthenticator.java @@ -0,0 +1,423 @@ +/** + * 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.tomcat; + +import java.io.File; +import java.io.IOException; +import java.security.Principal; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.JAXBException; + +import org.w3c.dom.Element; + +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.Constants; +import org.apache.catalina.authenticator.FormAuthenticator; +import org.apache.catalina.authenticator.SavedRequest; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.cxf.fediz.core.FederationConstants; +import org.apache.cxf.fediz.core.FedizPrincipal; +import org.apache.cxf.fediz.core.config.FedizConfigurator; +import org.apache.cxf.fediz.core.config.FedizContext; +import org.apache.cxf.fediz.core.exception.ProcessingException; +import org.apache.cxf.fediz.core.handler.LogoutHandler; +import org.apache.cxf.fediz.core.metadata.MetadataDocumentHandler; +import org.apache.cxf.fediz.core.processor.FedizProcessor; +import org.apache.cxf.fediz.core.processor.FedizProcessorFactory; +import org.apache.cxf.fediz.core.processor.FedizResponse; +import org.apache.cxf.fediz.core.processor.RedirectionResponse; +import org.apache.cxf.fediz.tomcat.handler.TomcatLogoutHandler; +import org.apache.cxf.fediz.tomcat.handler.TomcatSigninHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FederationAuthenticator extends FormAuthenticator { + + public static final String SESSION_SAVED_REQUEST_PREFIX = "SAVED_REQUEST_"; + public static final String SESSION_SAVED_URI_PREFIX = "SAVED_URI_"; + public static final String FEDERATION_NOTE = "org.apache.cxf.fediz.tomcat.FEDERATION"; + public static final String REQUEST_STATE = "org.apache.cxf.fediz.REQUEST_STATE"; + public static final String SECURITY_TOKEN = "org.apache.fediz.SECURITY_TOKEN"; + + /** + * Descriptive information about this implementation. + */ + protected static final String INFO = "org.apache.cxf.fediz.tomcat.WsFedAuthenticator/1.0"; + protected static final String TRUSTED_ISSUER = "org.apache.cxf.fediz.tomcat.TRUSTED_ISSUER"; + + private static final Logger LOG = LoggerFactory.getLogger(FormAuthenticator.class); + + /** + * Fediz Configuration file + */ + protected String configFile; + protected String encoding = "UTF-8"; + + private FedizConfigurator configurator; + + public FederationAuthenticator() { + LOG.debug("WsFedAuthenticator()"); + } + + public String getConfigFile() { + return configFile; + } + + public void setConfigFile(String configFile) { + this.configFile = configFile; + } + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + @Override + protected synchronized void startInternal() throws LifecycleException { + + try { + File f = new File(getConfigFile()); + if (!f.exists()) { + String catalinaBase = System.getProperty("catalina.base"); + if (catalinaBase != null && catalinaBase.length() > 0) { + f = new File(catalinaBase.concat(File.separator + getConfigFile())); + } + } + configurator = new FedizConfigurator(); + configurator.loadConfig(f); + LOG.debug("Fediz configuration read from " + f.getAbsolutePath()); + } catch (JAXBException e) { + throw new LifecycleException("Failed to load Fediz configuration", e); + } + super.startInternal(); + + } + + @Override + protected synchronized void stopInternal() throws LifecycleException { + if (configurator != null) { + List<FedizContext> fedContextList = configurator.getFedizContextList(); + if (fedContextList != null) { + for (FedizContext fedContext : fedContextList) { + try { + fedContext.close(); + } catch (IOException ex) { + // + } + } + } + } + super.stopInternal(); + } + + protected FedizContext getContextConfiguration(String contextName) { + if (configurator == null) { + throw new IllegalStateException("No Fediz configuration available"); + } + FedizContext config = configurator.getFedizContext(contextName); + if (config == null) { + throw new IllegalStateException("No Fediz configuration for context :" + contextName); + } + String catalinaBase = System.getProperty("catalina.base"); + if (catalinaBase != null && catalinaBase.length() > 0) { + config.setRelativePath(catalinaBase); + } + return config; + } + + @Override + public void invoke(final Request request, final Response response) throws IOException, ServletException { + + LOG.debug("WsFedAuthenticator:invoke()"); + request.setCharacterEncoding(this.encoding); + + String contextName = request.getServletContext().getContextPath(); + if (contextName == null || contextName.isEmpty()) { + contextName = "/"; + } + FedizContext fedConfig = getContextConfiguration(contextName); + + MetadataDocumentHandler mdHandler = new MetadataDocumentHandler(fedConfig); + if (mdHandler.canHandleRequest(request)) { + mdHandler.handleRequest(request, response); + return; + } + + LogoutHandler logoutHandler = new TomcatLogoutHandler(fedConfig, contextName, request); + if (logoutHandler.canHandleRequest(request)) { + Element token = (Element)request.getSession().getAttribute(SECURITY_TOKEN); + logoutHandler.setToken(token); + logoutHandler.handleRequest(request, response); + return; + } + + super.invoke(request, response); + } + + @Override + public boolean authenticate(Request request, HttpServletResponse response) throws IOException { + + LOG.debug("authenticate invoked"); + + String contextName = request.getServletContext().getContextPath(); + if (contextName == null || contextName.isEmpty()) { + contextName = "/"; + } + LOG.debug("reading configuration for context path: {}", contextName); + FedizContext fedCtx = getContextConfiguration(contextName); + + // Handle Signin requests + TomcatSigninHandler signinHandler = new TomcatSigninHandler(fedCtx); + signinHandler.setLandingPage(landingPage); + if (signinHandler.canHandleRequest(request)) { + FedizPrincipal principal = signinHandler.handleRequest(request, response); + if (principal != null) { + LOG.debug("Authentication of '{}' was successful", principal); + resumeRequest(request, response); + } else { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } + // The actual login will take place after redirect + return false; + } + + // Is this the re-submit of the original request URI after successful + // authentication? If so, forward the *original* request instead. + if (matchRequest(request)) { + return restoreRequest(request, response); + } + + // Check if user was authenticated previously and token is still valid + if (checkUserAuthentication(request, response, fedCtx)) { + return true; + } + + LOG.info("No valid principal found in existing session. Redirecting to IDP"); + redirectToIdp(request, response, fedCtx); + return false; + } + + protected void resumeRequest(HttpServletRequest request, HttpServletResponse response) { + String originalURL = null; + String contextId = request.getParameter(FederationConstants.PARAM_CONTEXT); + if (contextId != null) { + Session session = ((Request)request).getSessionInternal(); + originalURL = (String)session.getNote(FederationAuthenticator.SESSION_SAVED_URI_PREFIX + contextId); + session.removeNote(FederationAuthenticator.SESSION_SAVED_URI_PREFIX + contextId); // Cleanup session + + } else { + LOG.warn("The 'wctx' parameter has not been provided back with signin request. " + + "Trying to resume now with singin URL (without parameters)"); + originalURL = request.getRequestURI(); + } + try { + if (originalURL != null) { + LOG.debug("Restore request to {}", originalURL); + response.sendRedirect(response.encodeRedirectURL(originalURL)); + } else { + LOG.debug("User took so long to log on the session expired"); + if (landingPage == null) { + response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT, sm + .getString("authenticator.sessionExpired")); + } else { + // Redirect to landing page + String uri = request.getContextPath() + landingPage; + response.sendRedirect(response.encodeRedirectURL(uri)); + } + } + } catch (IOException e) { + LOG.error("Cannot resume with request.", e.getMessage()); + } + } + + protected boolean restoreRequest(Request request, HttpServletResponse response) throws IOException { + + Session session = request.getSessionInternal(); + LOG.debug("Restore request from session '{}'", session.getIdInternal()); + + // Get principal from session, register, and then remove it + Principal principal = (Principal)session.getNote(Constants.FORM_PRINCIPAL_NOTE); + register(request, response, principal, FederationConstants.WSFED_METHOD, null, null); + request.removeNote(Constants.FORM_PRINCIPAL_NOTE); + + if (restoreRequest(request)) { + LOG.debug("Proceed to restored request"); + return true; + } else { + LOG.warn("Restore of original request failed"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return false; + } + } + + protected void redirectToIdp(Request request, HttpServletResponse response, FedizContext fedCtx) + throws IOException { + + FedizProcessor processor = FedizProcessorFactory.newFedizProcessor(fedCtx.getProtocol()); + try { + RedirectionResponse redirectionResponse = processor.createSignInRequest(request, fedCtx); + String redirectURL = redirectionResponse.getRedirectionURL(); + if (redirectURL != null) { + Map<String, String> headers = redirectionResponse.getHeaders(); + if (!headers.isEmpty()) { + for (String headerName : headers.keySet()) { + response.addHeader(headerName, headers.get(headerName)); + } + } + + // Save original request in our session + try { + saveRequest(request, redirectionResponse.getRequestState().getState()); + } catch (IOException ioe) { + LOG.debug("Request body too big to save during authentication"); + response.sendError(HttpServletResponse.SC_FORBIDDEN, sm + .getString("authenticator.requestBodyTooBig")); + } + + response.sendRedirect(redirectURL); + } else { + LOG.warn("Failed to create SignInRequest."); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to create SignInRequest."); + } + } catch (ProcessingException ex) { + LOG.warn("Failed to create SignInRequest: {}", ex.getMessage()); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to create SignInRequest."); + } + } + + @Override + protected boolean matchRequest(Request request) { + Session session = request.getSessionInternal(false); + String uri = request.getDecodedRequestURI(); + if (session != null && uri != null) { + SavedRequest saved = (SavedRequest) session.getNote(SESSION_SAVED_REQUEST_PREFIX + uri); + if (saved != null) { + synchronized (session) { + session.setNote(Constants.FORM_REQUEST_NOTE, saved); + return super.matchRequest(request); + } + } + } + return false; + } + + protected void saveRequest(Request request, String contextId) throws IOException { + String uri = request.getDecodedRequestURI(); + Session session = request.getSessionInternal(true); + LOG.debug("Save request in session '{}'", session.getIdInternal()); + if (session != null && uri != null) { + SavedRequest saved; + synchronized (session) { + super.saveRequest(request, session); + saved = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE); + } + session.setNote(SESSION_SAVED_REQUEST_PREFIX + uri, saved); + StringBuilder sb = new StringBuilder(saved.getRequestURI()); + if (saved.getQueryString() != null) { + sb.append('?'); + sb.append(saved.getQueryString()); + } + session.setNote(SESSION_SAVED_URI_PREFIX + contextId, sb.toString()); + } + } + + protected boolean restoreRequest(Request request) throws IOException { + Session session = request.getSessionInternal(false); + String uri = request.getDecodedRequestURI(); + if (session != null && uri != null) { + SavedRequest saved = (SavedRequest)session.getNote(SESSION_SAVED_REQUEST_PREFIX + uri); + if (saved != null) { + session.removeNote(SESSION_SAVED_REQUEST_PREFIX + uri); // cleanup session + synchronized (session) { + session.setNote(Constants.FORM_REQUEST_NOTE, saved); + return super.restoreRequest(request, session); + } + } + } + return false; + } + + protected boolean checkUserAuthentication(Request request, HttpServletResponse response, FedizContext fedCtx) { + // Have we already authenticated someone? + Principal principal = request.getUserPrincipal(); + // String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); + if (principal != null) { + LOG.debug("Already authenticated '{}'", principal.getName()); + + // Associate the session with any existing SSO session + /* + * if (ssoId != null) associate(ssoId, request.getSessionInternal(true)); + */ + + if (fedCtx.isDetectExpiredTokens()) { + // Check whether security token still valid + return validateToken(request, response, fedCtx); + } else { + LOG.debug("Token expiration not validated."); + return true; + } + } + return false; + } + + protected boolean validateToken(Request request, HttpServletResponse response, FedizContext fedConfig) { + Session session = request.getSessionInternal(); + if (session != null) { + + FedizResponse wfRes = (FedizResponse)session.getNote(FEDERATION_NOTE); + Date tokenExpires = wfRes.getTokenExpires(); + if (tokenExpires == null) { + LOG.debug("Token doesn't expire"); + return true; + } + + Date currentTime = new Date(); + if (!currentTime.after(tokenExpires)) { + return true; + } else { + LOG.warn("Token already expired. Clean up and redirect"); + + session.removeNote(FEDERATION_NOTE); + session.setPrincipal(null); + request.getSession().removeAttribute(SECURITY_TOKEN); + } + } else { + LOG.debug("Session should not be null after authentication"); + } + return false; + } + + @Override + protected String getAuthMethod() { + return FederationConstants.WSFED_METHOD; + } + +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/FederationPrincipalImpl.java ---------------------------------------------------------------------- diff --git a/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/FederationPrincipalImpl.java b/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/FederationPrincipalImpl.java new file mode 100644 index 0000000..5739b19 --- /dev/null +++ b/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/FederationPrincipalImpl.java @@ -0,0 +1,52 @@ +/** + * 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.tomcat; + +import java.util.List; + +import org.w3c.dom.Element; +import org.apache.catalina.realm.GenericPrincipal; +import org.apache.cxf.fediz.core.Claim; +import org.apache.cxf.fediz.core.ClaimCollection; +import org.apache.cxf.fediz.core.FederationPrincipal; + +@SuppressWarnings("deprecation") +public class FederationPrincipalImpl extends GenericPrincipal implements FederationPrincipal { + + protected ClaimCollection claims; + protected Element loginToken; + + public FederationPrincipalImpl(String username, List<String> roles, + List<Claim> claims, Element loginToken) { + super(username, null, roles); + this.claims = new ClaimCollection(claims); + this.loginToken = loginToken; + } + + public ClaimCollection getClaims() { + return this.claims; + } + + @Override + public Element getLoginToken() { + return loginToken; + } + +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/handler/TomcatLogoutHandler.java ---------------------------------------------------------------------- diff --git a/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/handler/TomcatLogoutHandler.java b/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/handler/TomcatLogoutHandler.java new file mode 100644 index 0000000..fe39482 --- /dev/null +++ b/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/handler/TomcatLogoutHandler.java @@ -0,0 +1,58 @@ +/** + * 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.tomcat.handler; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Session; +import org.apache.catalina.connector.Request; +import org.apache.cxf.fediz.core.config.FedizContext; +import org.apache.cxf.fediz.core.handler.LogoutHandler; +import org.apache.cxf.fediz.tomcat.FederationAuthenticator; + +public class TomcatLogoutHandler extends LogoutHandler { + private final Request request; + + public TomcatLogoutHandler(FedizContext fedConfig, String servletContextPath, Request request) { + super(fedConfig, servletContextPath); + this.request = request; + } + + @Override + protected boolean signoutCleanup(HttpServletRequest req, HttpServletResponse resp) { + // Cleanup session internal + Session session = request.getSessionInternal(); + session.removeNote(FederationAuthenticator.FEDERATION_NOTE); + session.setPrincipal(null); + super.signoutCleanup(req, resp); + request.clearCookies(); + return true; + } + + @Override + protected boolean signout(HttpServletRequest req, HttpServletResponse resp) { + // Direct Logout + Session session = request.getSessionInternal(); + session.removeNote(FederationAuthenticator.FEDERATION_NOTE); + session.setPrincipal(null); + return super.signout(req, resp); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/handler/TomcatSigninHandler.java ---------------------------------------------------------------------- diff --git a/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/handler/TomcatSigninHandler.java b/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/handler/TomcatSigninHandler.java new file mode 100644 index 0000000..e7b01cb --- /dev/null +++ b/plugins/tomcat8/src/main/java/org/apache/cxf/fediz/tomcat/handler/TomcatSigninHandler.java @@ -0,0 +1,101 @@ +/** + * 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.tomcat.handler; + +import java.util.Collections; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.Constants; +import org.apache.catalina.connector.Request; +import org.apache.cxf.fediz.core.FederationConstants; +import org.apache.cxf.fediz.core.FedizPrincipal; +import org.apache.cxf.fediz.core.SAMLSSOConstants; +import org.apache.cxf.fediz.core.config.FederationProtocol; +import org.apache.cxf.fediz.core.config.FedizContext; +import org.apache.cxf.fediz.core.config.SAMLProtocol; +import org.apache.cxf.fediz.core.handler.SigninHandler; +import org.apache.cxf.fediz.core.processor.FedizResponse; +import org.apache.cxf.fediz.tomcat.FederationAuthenticator; +import org.apache.cxf.fediz.tomcat.FederationPrincipalImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TomcatSigninHandler extends SigninHandler<FedizPrincipal> { + + private static final Logger LOG = LoggerFactory.getLogger(TomcatSigninHandler.class); + private Object landingPage; + + public TomcatSigninHandler(FedizContext fedizContext) { + super(fedizContext); + } + + @Override + protected FedizPrincipal createPrincipal(HttpServletRequest request, HttpServletResponse response, + FedizResponse wfRes) { + + List<String> roles = wfRes.getRoles(); + if (roles == null || roles.size() == 0) { + roles = Collections.singletonList("Authenticated"); + } + + // proceed creating the JAAS Subject + FedizPrincipal principal = new FederationPrincipalImpl(wfRes.getUsername(), roles, + wfRes.getClaims(), wfRes.getToken()); + + Session session = ((Request)request).getSessionInternal(); + + // Save the authenticated Principal in our session + session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal); + + // Save Federation response in our session + session.setNote(FederationAuthenticator.FEDERATION_NOTE, wfRes); + + // Save Federation response in public session + request.getSession(true).setAttribute(FederationAuthenticator.SECURITY_TOKEN, wfRes.getToken()); + + LOG.debug("UserPrincipal was created successfully for {}", principal); + return principal; + } + + @Override + public boolean canHandleRequest(HttpServletRequest request) { + if (super.getFedizContext().getProtocol() instanceof FederationProtocol + && FederationConstants.ACTION_SIGNIN.equals(request.getParameter(FederationConstants.PARAM_ACTION))) { + return true; + } else if (super.getFedizContext().getProtocol() instanceof SAMLProtocol + && request.getParameter(SAMLSSOConstants.RELAY_STATE) != null) { + return true; + } + return false; + } + + public Object getLandingPage() { + return landingPage; + } + + public void setLandingPage(Object landingPage) { + this.landingPage = landingPage; + } + +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/plugins/tomcat8/src/test/resources/logging.properties ---------------------------------------------------------------------- diff --git a/plugins/tomcat8/src/test/resources/logging.properties b/plugins/tomcat8/src/test/resources/logging.properties new file mode 100644 index 0000000..992a78d --- /dev/null +++ b/plugins/tomcat8/src/test/resources/logging.properties @@ -0,0 +1,52 @@ +############################################################ +# Default Logging Configuration File +# +# You can use a different file by specifying a filename +# with the java.util.logging.config.file system property. +# For example java -Djava.util.logging.config.file=myfile +############################################################ + +############################################################ +# Global properties +############################################################ + +# "handlers" specifies a comma separated list of log Handler +# classes. These handlers will be installed during VM startup. +# Note that these classes must be on the system classpath. +# By default we only configure a ConsoleHandler, which will only +# show messages at the WARNING and above levels. +#handlers= java.util.logging.ConsoleHandler +#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +# Default global logging level. +# This specifies which kinds of events are logged across +# all loggers. For any given facility this global level +# can be overridden by a facility specific level +# Note that the ConsoleHandler also has a separate level +# setting to limit messages printed to the console. +.level= INFO + +############################################################ +# Handler specific properties. +# Describes specific configuration info for Handlers. +############################################################ + +# default file output is in user's home directory. +java.util.logging.FileHandler.pattern = %h/java%u.log +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 1 +java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter + +# Limit the message that are printed on the console to WARNING and above. +java.util.logging.ConsoleHandler.level = WARNING +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter + + +############################################################ +# Facility specific properties. +# Provides extra control for each logger. +############################################################ + +# For example, set the com.xyz.foo logger to only log SEVERE +# messages: +#com.xyz.foo.level = SEVERE http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 63fae21..9b4f001 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,7 @@ <spring.version>4.1.6.RELEASE</spring.version> <spring.security.version>3.1.4.RELEASE</spring.security.version> <tomcat7.version>7.0.54</tomcat7.version> + <tomcat8.version>8.0.26</tomcat8.version> <wss4j.version>2.1.2</wss4j.version> <xalan.version>2.7.2</xalan.version> http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/systests/pom.xml ---------------------------------------------------------------------- diff --git a/systests/pom.xml b/systests/pom.xml index 24b84c0..92612cd 100644 --- a/systests/pom.xml +++ b/systests/pom.xml @@ -33,7 +33,8 @@ <module>tests</module> <module>webapps</module> <module>jetty8</module> - <module>tomcat7</module> + <module>romcat7</module> + <module>tomcat8</module> <module>spring</module> <module>cxf</module> <module>federation</module> http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/systests/tomcat8/pom.xml ---------------------------------------------------------------------- diff --git a/systests/tomcat8/pom.xml b/systests/tomcat8/pom.xml new file mode 100644 index 0000000..71762f4 --- /dev/null +++ b/systests/tomcat8/pom.xml @@ -0,0 +1,243 @@ +<?xml version="1.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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.cxf.fediz</groupId> + <artifactId>fediz-systests</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <groupId>org.apache.cxf.fediz.systests</groupId> + <artifactId>fediz-systests-tomcat8</artifactId> + <name>Apache Fediz Systests Tomcat 8</name> + <packaging>jar</packaging> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + </properties> + <dependencies> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-core</artifactId> + <version>${tomcat8.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-logging-juli</artifactId> + <version>${tomcat8.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jdt.core.compiler</groupId> + <artifactId>ecj</artifactId> + <version>${ecj.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-jasper</artifactId> + <version>${tomcat8.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.cxf.fediz</groupId> + <artifactId>fediz-tomcat8</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.cxf.fediz.systests</groupId> + <artifactId>fediz-systests-tests</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-jdk14</artifactId> + <version>${slf4j.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hsqldb</groupId> + <artifactId>hsqldb</artifactId> + <version>${hsqldb.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <testResources> + <testResource> + <directory>src/test/resources</directory> + <filtering>true</filtering> + <includes> + <include>**/fediz_config*.xml</include> + </includes> + </testResource> + <testResource> + <directory>src/test/resources</directory> + <filtering>false</filtering> + <excludes> + <exclude>**/fediz_config*.xml</exclude> + </excludes> + </testResource> + </testResources> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <id>reserve-network-port</id> + <goals> + <goal>reserve-network-port</goal> + </goals> + <phase>initialize</phase> + <configuration> + <portNames> + <portName>idp.https.port</portName> + <portName>rp.https.port</portName> + </portNames> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-idp-sts</id> + <phase>generate-resources</phase> + <goals> + <goal>unpack</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>org.apache.cxf.fediz</groupId> + <artifactId>fediz-idp</artifactId> + <version>${project.version}</version> + <type>war</type> + <overWrite>true</overWrite> + <outputDirectory>target/tomcat/idp/webapps/fediz-idp</outputDirectory> + </artifactItem> + <artifactItem> + <groupId>org.apache.cxf.fediz</groupId> + <artifactId>fediz-idp-sts</artifactId> + <version>${project.version}</version> + <type>war</type> + <overWrite>true</overWrite> + <outputDirectory>target/tomcat/idp/webapps/fediz-idp-sts</outputDirectory> + </artifactItem> + <artifactItem> + <groupId>org.apache.cxf.fediz.systests.webapps</groupId> + <artifactId>fediz-systests-webapps-simple</artifactId> + <version>${project.version}</version> + <type>war</type> + <overWrite>true</overWrite> + <outputDirectory>target/tomcat/rp/webapps/simpleWebapp</outputDirectory> + </artifactItem> + </artifactItems> + <outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename> + <overWriteSnapshots>true</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + <stripVersion>true</stripVersion> + </configuration> + </execution> + <execution> + <id>copy-xalan-to-idp</id> + <phase>generate-resources</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>xalan</groupId> + <artifactId>xalan</artifactId> + <version>${xalan.version}</version> + <outputDirectory>target/tomcat/idp/webapps/fediz-idp/WEB-INF/lib</outputDirectory> + </artifactItem> + </artifactItems> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-failsafe-plugin</artifactId> + <inherited>true</inherited> + <executions> + <execution> + <id>integration-test</id> + <phase>integration-test</phase> + <goals> + <goal>integration-test</goal> + </goals> + <configuration> + <skip>false</skip> + <systemPropertyVariables> + <wt.headless>true</wt.headless> + <idp.https.port>${idp.https.port}</idp.https.port> + <rp.https.port>${rp.https.port}</rp.https.port> + </systemPropertyVariables> + <includes> + <include>**/integrationtests/**</include> + </includes> + <argLine>-Xms512m -Xmx1024m -XX:MaxPermSize=256m </argLine> + <!--argLine>-Xms512m -Xmx1024m -XX:MaxPermSize=256m -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y</argLine--> + </configuration> + </execution> + <execution> + <id>verify</id> + <phase>verify</phase> + <goals> + <goal>verify</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <inherited>true</inherited> + <configuration> + <excludes> + <exclude>**/integrationtests/**</exclude> + </excludes> + </configuration> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/BadWReqCallbackHandler.java ---------------------------------------------------------------------- diff --git a/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/BadWReqCallbackHandler.java b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/BadWReqCallbackHandler.java new file mode 100644 index 0000000..a35d286 --- /dev/null +++ b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/BadWReqCallbackHandler.java @@ -0,0 +1,48 @@ +/** + * 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.integrationtests; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.apache.cxf.fediz.core.spi.WReqCallback; + +public class BadWReqCallbackHandler implements CallbackHandler { + + static final String TEST_WREQ = + "<RequestSecurityToken xmlns=\"http://docs.oasis-open.org/ws-sx/ws-trust/200512\">" + + "<TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV3.0</TokenType>" + + "</RequestSecurityToken>"; + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof WReqCallback) { + WReqCallback callback = (WReqCallback) callbacks[i]; + callback.setWreq(TEST_WREQ); + } else { + throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback"); + } + } + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/BadWReqTest.java ---------------------------------------------------------------------- diff --git a/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/BadWReqTest.java b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/BadWReqTest.java new file mode 100644 index 0000000..99c4fe1 --- /dev/null +++ b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/BadWReqTest.java @@ -0,0 +1,197 @@ +/** + * 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.integrationtests; + +import java.io.File; + +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleState; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.startup.Tomcat; +import org.apache.cxf.fediz.tomcat.FederationAuthenticator; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; + +/** + * A test for sending a TokenType request to the IdP via the "wreq" parameter. This test sends + * a "bad" TokenType, and so a failure is expected. + */ +public class BadWReqTest { + + static String idpHttpsPort; + static String rpHttpsPort; + + private static Tomcat idpServer; + private static Tomcat rpServer; + + @BeforeClass + public static void init() { + System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); + System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true"); + System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.springframework.webflow", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.springframework.security.web", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.cxf.fediz", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.cxf", "info"); + + idpHttpsPort = System.getProperty("idp.https.port"); + Assert.assertNotNull("Property 'idp.https.port' null", idpHttpsPort); + rpHttpsPort = System.getProperty("rp.https.port"); + Assert.assertNotNull("Property 'rp.https.port' null", rpHttpsPort); + + initIdp(); + initRp(); + } + + private static void initIdp() { + try { + idpServer = new Tomcat(); + idpServer.setPort(0); + String currentDir = new File(".").getCanonicalPath(); + idpServer.setBaseDir(currentDir + File.separator + "target"); + + idpServer.getHost().setAppBase("tomcat/idp/webapps"); + idpServer.getHost().setAutoDeploy(true); + idpServer.getHost().setDeployOnStartup(true); + + Connector httpsConnector = new Connector(); + httpsConnector.setPort(Integer.parseInt(idpHttpsPort)); + httpsConnector.setSecure(true); + httpsConnector.setScheme("https"); + //httpsConnector.setAttribute("keyAlias", keyAlias); + httpsConnector.setAttribute("keystorePass", "tompass"); + httpsConnector.setAttribute("keystoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("truststorePass", "tompass"); + httpsConnector.setAttribute("truststoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("clientAuth", "want"); + // httpsConnector.setAttribute("clientAuth", "false"); + httpsConnector.setAttribute("sslProtocol", "TLS"); + httpsConnector.setAttribute("SSLEnabled", true); + + idpServer.getService().addConnector(httpsConnector); + + idpServer.addWebapp("/fediz-idp-sts", "fediz-idp-sts"); + idpServer.addWebapp("/fediz-idp", "fediz-idp"); + + idpServer.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void initRp() { + try { + rpServer = new Tomcat(); + rpServer.setPort(0); + String currentDir = new File(".").getCanonicalPath(); + rpServer.setBaseDir(currentDir + File.separator + "target"); + + rpServer.getHost().setAppBase("tomcat/rp/webapps"); + rpServer.getHost().setAutoDeploy(true); + rpServer.getHost().setDeployOnStartup(true); + + Connector httpsConnector = new Connector(); + httpsConnector.setPort(Integer.parseInt(rpHttpsPort)); + httpsConnector.setSecure(true); + httpsConnector.setScheme("https"); + //httpsConnector.setAttribute("keyAlias", keyAlias); + httpsConnector.setAttribute("keystorePass", "tompass"); + httpsConnector.setAttribute("keystoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("truststorePass", "tompass"); + httpsConnector.setAttribute("truststoreFile", "test-classes/server.jks"); + // httpsConnector.setAttribute("clientAuth", "false"); + httpsConnector.setAttribute("clientAuth", "want"); + httpsConnector.setAttribute("sslProtocol", "TLS"); + httpsConnector.setAttribute("SSLEnabled", true); + + rpServer.getService().addConnector(httpsConnector); + + //Context ctx = + Context cxt = rpServer.addWebapp("/fedizhelloworld", "simpleWebapp"); + FederationAuthenticator fa = new FederationAuthenticator(); + fa.setConfigFile(currentDir + File.separator + "target" + File.separator + + "test-classes" + File.separator + "fediz_config_bad_wreq.xml"); + cxt.getPipeline().addValve(fa); + + + rpServer.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void cleanup() { + try { + if (idpServer.getServer() != null + && idpServer.getServer().getState() != LifecycleState.DESTROYED) { + if (idpServer.getServer().getState() != LifecycleState.STOPPED) { + idpServer.stop(); + } + idpServer.destroy(); + } + } catch (Exception e) { + e.printStackTrace(); + } + + try { + if (rpServer.getServer() != null + && rpServer.getServer().getState() != LifecycleState.DESTROYED) { + if (rpServer.getServer().getState() != LifecycleState.STOPPED) { + rpServer.stop(); + } + rpServer.destroy(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public String getIdpHttpsPort() { + return idpHttpsPort; + } + + public String getRpHttpsPort() { + return rpHttpsPort; + } + + public String getServletContextName() { + return "fedizhelloworld"; + } + + @org.junit.Test + public void testSAML1TokenViaWReq() throws Exception { + String url = "https://localhost:" + getRpHttpsPort() + "/fedizhelloworld/secure/fedservlet"; + String user = "alice"; + String password = "ecila"; + + try { + HTTPTestUtils.login(url, user, password, getIdpHttpsPort()); + Assert.fail("Exception expected"); + } catch (FailingHttpStatusCodeException ex) { + Assert.assertEquals(ex.getStatusCode(), 400); + } + } + +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/ClientCertificateTest.java ---------------------------------------------------------------------- diff --git a/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/ClientCertificateTest.java b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/ClientCertificateTest.java new file mode 100644 index 0000000..078e032 --- /dev/null +++ b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/ClientCertificateTest.java @@ -0,0 +1,179 @@ +/** + * 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.integrationtests; + +import java.io.File; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleState; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.startup.Tomcat; +import org.apache.cxf.fediz.tomcat.FederationAuthenticator; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; + +/** + * In this test-case, the IdP is set up to require client authentication, rather than authenticating using a + * username + password, or via Kerberos. + */ +public class ClientCertificateTest extends AbstractClientCertTests { + + static String idpHttpsPort; + static String rpHttpsPort; + + private static Tomcat idpServer; + private static Tomcat rpServer; + + @BeforeClass + public static void init() { + System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); + System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true"); + System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.springframework.webflow", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.springframework.security.web", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.cxf.fediz", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.cxf", "info"); + + idpHttpsPort = System.getProperty("idp.https.port"); + Assert.assertNotNull("Property 'idp.https.port' null", idpHttpsPort); + rpHttpsPort = System.getProperty("rp.https.port"); + Assert.assertNotNull("Property 'rp.https.port' null", rpHttpsPort); + + initIdp(); + initRp(); + } + + private static void initIdp() { + try { + idpServer = new Tomcat(); + idpServer.setPort(0); + String currentDir = new File(".").getCanonicalPath(); + idpServer.setBaseDir(currentDir + File.separator + "target"); + + idpServer.getHost().setAppBase("tomcat/idp/webapps"); + idpServer.getHost().setAutoDeploy(true); + idpServer.getHost().setDeployOnStartup(true); + + Connector httpsConnector = new Connector(); + httpsConnector.setPort(Integer.parseInt(idpHttpsPort)); + httpsConnector.setSecure(true); + httpsConnector.setScheme("https"); + //httpsConnector.setAttribute("keyAlias", keyAlias); + httpsConnector.setAttribute("keystorePass", "tompass"); + httpsConnector.setAttribute("keystoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("truststorePass", "tompass"); + httpsConnector.setAttribute("truststoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("clientAuth", "true"); + httpsConnector.setAttribute("sslProtocol", "TLS"); + httpsConnector.setAttribute("SSLEnabled", true); + + idpServer.getService().addConnector(httpsConnector); + + idpServer.addWebapp("/fediz-idp-sts", "fediz-idp-sts"); + idpServer.addWebapp("/fediz-idp", "fediz-idp"); + + idpServer.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void initRp() { + try { + rpServer = new Tomcat(); + rpServer.setPort(0); + String currentDir = new File(".").getCanonicalPath(); + rpServer.setBaseDir(currentDir + File.separator + "target"); + + rpServer.getHost().setAppBase("tomcat/rp/webapps"); + rpServer.getHost().setAutoDeploy(true); + rpServer.getHost().setDeployOnStartup(true); + + Connector httpsConnector = new Connector(); + httpsConnector.setPort(Integer.parseInt(rpHttpsPort)); + httpsConnector.setSecure(true); + httpsConnector.setScheme("https"); + //httpsConnector.setAttribute("keyAlias", keyAlias); + httpsConnector.setAttribute("keystorePass", "tompass"); + httpsConnector.setAttribute("keystoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("truststorePass", "tompass"); + httpsConnector.setAttribute("truststoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("clientAuth", "true"); + httpsConnector.setAttribute("sslProtocol", "TLS"); + httpsConnector.setAttribute("SSLEnabled", true); + + rpServer.getService().addConnector(httpsConnector); + + //Context ctx = + Context cxt = rpServer.addWebapp("/fedizhelloworld", "simpleWebapp"); + FederationAuthenticator fa = new FederationAuthenticator(); + fa.setConfigFile(currentDir + File.separator + "target" + File.separator + + "test-classes" + File.separator + "fediz_config_client_cert.xml"); + cxt.getPipeline().addValve(fa); + + + rpServer.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void cleanup() { + try { + if (idpServer.getServer() != null + && idpServer.getServer().getState() != LifecycleState.DESTROYED) { + if (idpServer.getServer().getState() != LifecycleState.STOPPED) { + idpServer.stop(); + } + idpServer.destroy(); + } + } catch (Exception e) { + e.printStackTrace(); + } + + try { + if (rpServer.getServer() != null + && rpServer.getServer().getState() != LifecycleState.DESTROYED) { + if (rpServer.getServer().getState() != LifecycleState.STOPPED) { + rpServer.stop(); + } + rpServer.destroy(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public String getIdpHttpsPort() { + return idpHttpsPort; + } + + public String getRpHttpsPort() { + return rpHttpsPort; + } + + public String getServletContextName() { + return "fedizhelloworld"; + } + +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/EntityExpansionAttackTest.java ---------------------------------------------------------------------- diff --git a/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/EntityExpansionAttackTest.java b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/EntityExpansionAttackTest.java new file mode 100644 index 0000000..006fa2a --- /dev/null +++ b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/EntityExpansionAttackTest.java @@ -0,0 +1,247 @@ +/** + * 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.integrationtests; + + +import java.io.File; +import java.io.FileInputStream; + +import com.gargoylesoftware.htmlunit.CookieManager; +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.DomElement; +import com.gargoylesoftware.htmlunit.html.DomNodeList; +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleState; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.startup.Tomcat; +import org.apache.commons.io.IOUtils; +import org.apache.cxf.fediz.tomcat.FederationAuthenticator; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class EntityExpansionAttackTest { + + static String idpHttpsPort; + static String rpHttpsPort; + + private static Tomcat idpServer; + private static Tomcat rpServer; + + @BeforeClass + public static void init() { + System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); + System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true"); + System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.springframework.webflow", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.springframework.security.web", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.cxf.fediz", "info"); + System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.cxf", "info"); + + idpHttpsPort = System.getProperty("idp.https.port"); + Assert.assertNotNull("Property 'idp.https.port' null", idpHttpsPort); + rpHttpsPort = System.getProperty("rp.https.port"); + Assert.assertNotNull("Property 'rp.https.port' null", rpHttpsPort); + + initIdp(); + initRp(); + } + + private static void initIdp() { + try { + idpServer = new Tomcat(); + idpServer.setPort(0); + String currentDir = new File(".").getCanonicalPath(); + idpServer.setBaseDir(currentDir + File.separator + "target"); + + idpServer.getHost().setAppBase("tomcat/idp/webapps"); + idpServer.getHost().setAutoDeploy(true); + idpServer.getHost().setDeployOnStartup(true); + + Connector httpsConnector = new Connector(); + httpsConnector.setPort(Integer.parseInt(idpHttpsPort)); + httpsConnector.setSecure(true); + httpsConnector.setScheme("https"); + //httpsConnector.setAttribute("keyAlias", keyAlias); + httpsConnector.setAttribute("keystorePass", "tompass"); + httpsConnector.setAttribute("keystoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("truststorePass", "tompass"); + httpsConnector.setAttribute("truststoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("clientAuth", "want"); + // httpsConnector.setAttribute("clientAuth", "false"); + httpsConnector.setAttribute("sslProtocol", "TLS"); + httpsConnector.setAttribute("SSLEnabled", true); + + idpServer.getService().addConnector(httpsConnector); + + idpServer.addWebapp("/fediz-idp-sts", "fediz-idp-sts"); + idpServer.addWebapp("/fediz-idp", "fediz-idp"); + + idpServer.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void initRp() { + try { + rpServer = new Tomcat(); + rpServer.setPort(0); + String currentDir = new File(".").getCanonicalPath(); + rpServer.setBaseDir(currentDir + File.separator + "target"); + + rpServer.getHost().setAppBase("tomcat/rp/webapps"); + rpServer.getHost().setAutoDeploy(true); + rpServer.getHost().setDeployOnStartup(true); + + Connector httpsConnector = new Connector(); + httpsConnector.setPort(Integer.parseInt(rpHttpsPort)); + httpsConnector.setSecure(true); + httpsConnector.setScheme("https"); + //httpsConnector.setAttribute("keyAlias", keyAlias); + httpsConnector.setAttribute("keystorePass", "tompass"); + httpsConnector.setAttribute("keystoreFile", "test-classes/server.jks"); + httpsConnector.setAttribute("truststorePass", "tompass"); + httpsConnector.setAttribute("truststoreFile", "test-classes/server.jks"); + // httpsConnector.setAttribute("clientAuth", "false"); + httpsConnector.setAttribute("clientAuth", "want"); + httpsConnector.setAttribute("sslProtocol", "TLS"); + httpsConnector.setAttribute("SSLEnabled", true); + + rpServer.getService().addConnector(httpsConnector); + + //Context ctx = + Context cxt = rpServer.addWebapp("/fedizhelloworld", "simpleWebapp"); + FederationAuthenticator fa = new FederationAuthenticator(); + fa.setConfigFile(currentDir + File.separator + "target" + File.separator + + "test-classes" + File.separator + "fediz_config_wreq.xml"); + cxt.getPipeline().addValve(fa); + + + rpServer.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void cleanup() { + try { + if (idpServer.getServer() != null + && idpServer.getServer().getState() != LifecycleState.DESTROYED) { + if (idpServer.getServer().getState() != LifecycleState.STOPPED) { + idpServer.stop(); + } + idpServer.destroy(); + } + } catch (Exception e) { + e.printStackTrace(); + } + + try { + if (rpServer.getServer() != null + && rpServer.getServer().getState() != LifecycleState.DESTROYED) { + if (rpServer.getServer().getState() != LifecycleState.STOPPED) { + rpServer.stop(); + } + rpServer.destroy(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public String getIdpHttpsPort() { + return idpHttpsPort; + } + + public String getRpHttpsPort() { + return rpHttpsPort; + } + + public String getServletContextName() { + return "fedizhelloworld"; + } + + @Test + public void testEntityExpansionAttack() throws Exception { + String url = "https://localhost:" + getRpHttpsPort() + "/fedizhelloworld/secure/fedservlet"; + String user = "alice"; + String password = "ecila"; + + // Get the initial token + CookieManager cookieManager = new CookieManager(); + final 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); + final HtmlPage idpPage = webClient.getPage(url); + webClient.getOptions().setJavaScriptEnabled(true); + Assert.assertEquals("IDP SignIn Response Form", idpPage.getTitleText()); + + // Parse the form to get the token (wresult) + DomNodeList<DomElement> results = idpPage.getElementsByTagName("input"); + + FileInputStream is = new FileInputStream("src/test/resources/entity.xml"); + String entity = IOUtils.toString(is); + String reference = "&m;"; + + for (DomElement result : results) { + if ("wresult".equals(result.getAttributeNS(null, "name"))) { + // Now modify the Signature + String value = result.getAttributeNS(null, "value"); + value = entity + value; + value = value.replace("alice", reference); + result.setAttributeNS(null, "value", value); + } + } + + // Invoke back on the RP + + final HtmlForm form = idpPage.getFormByName("signinresponseform"); + final HtmlSubmitInput button = form.getInputByName("_eventId_submit"); + + try { + button.click(); + Assert.fail("Failure expected on an entity expansion attack"); + } catch (FailingHttpStatusCodeException ex) { + ex.printStackTrace(); + // expected + Assert.assertTrue(ex.getMessage().contains("401 Unauthorized") + || ex.getMessage().contains("401 Authentication Failed") + || ex.getMessage().contains("403 Forbidden")); + } + + } + +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/0b2c2218/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/HOKCallbackHandler.java ---------------------------------------------------------------------- diff --git a/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/HOKCallbackHandler.java b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/HOKCallbackHandler.java new file mode 100644 index 0000000..e2f402c --- /dev/null +++ b/systests/tomcat8/src/test/java/org/apache/cxf/fediz/integrationtests/HOKCallbackHandler.java @@ -0,0 +1,48 @@ +/** + * 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.integrationtests; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.apache.cxf.fediz.core.spi.WReqCallback; + +public class HOKCallbackHandler implements CallbackHandler { + + static final String HOK_WREQ = + "<RequestSecurityToken xmlns=\"http://docs.oasis-open.org/ws-sx/ws-trust/200512\">" + + "<KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey</KeyType>" + + "</RequestSecurityToken>"; + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof WReqCallback) { + WReqCallback callback = (WReqCallback) callbacks[i]; + callback.setWreq(HOK_WREQ); + } else { + throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback"); + } + } + } + +} \ No newline at end of file
