diff --git a/agent/pom.xml b/agent/pom.xml deleted file mode 100644 index 3ba348b63..000000000 --- a/agent/pom.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - org.exoplatform.gatein.sso - sso-parent - ../pom.xml - 6.6.x-SNAPSHOT - - - 4.0.0 - sso-agent - jar - GateIn SSO - Agent - - - 0.18 - - - - - org.exoplatform.gatein.sso - sso-auth-callback - - - org.gatein.common - common-common - - - org.apache.tomcat - tomcat-catalina - provided - - - org.exoplatform.core - exo.core.component.organization.api - provided - - - org.exoplatform.gatein.wci - wci-wci - provided - - - org.apache.httpcomponents - httpclient - provided - - - org.jboss.security - jboss-negotiation-spnego - provided - - - org.picketlink - picketlink-federation - provided - - - org.picketlink.distribution - picketlink-wildfly8 - provided - - - org.mockito - mockito-core - test - - - junit - junit - test - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - true - - - - - - - - - run-its - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - - - - diff --git a/agent/src/main/java/org/gatein/sso/agent/GenericAgent.java b/agent/src/main/java/org/gatein/sso/agent/GenericAgent.java deleted file mode 100644 index 24b52a690..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/GenericAgent.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.gatein.sso.agent; - -import org.apache.commons.lang.StringUtils; -import org.exoplatform.commons.utils.ListAccess; -import org.exoplatform.commons.utils.PropertyManager; -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.exoplatform.services.organization.Query; -import org.exoplatform.services.organization.User; -import org.gatein.wci.security.Credentials; - -import org.exoplatform.container.ExoContainer; -import org.exoplatform.container.ExoContainerContext; -import org.exoplatform.container.PortalContainer; -import org.exoplatform.container.RootContainer; -import org.exoplatform.services.organization.OrganizationService; - -import javax.servlet.http.HttpServletRequest; - -/** - * Base agent superclass used by other SSO agents (CAS, OpenAM) - * - * @author Marek Posolda - */ -public abstract class GenericAgent -{ - private static Log log = ExoLogger.getLogger(GenericAgent.class); - - public static final String AUTHENTICATED_CREDENTIALS = "authenticatedCredentials"; - - private static final String IS_CASE_INSENSITIVE = "exo.auth.case.insensitive"; - - - public void saveSSOCredentials(String username, HttpServletRequest httpRequest) - { - boolean case_insensitive_bool = true; - String case_insensitive_str = PropertyManager.getProperty(IS_CASE_INSENSITIVE); - if(case_insensitive_str != null) { - case_insensitive_bool = Boolean.valueOf(case_insensitive_str); - } - if(case_insensitive_bool) { - username = getUserPrincipal(username); - } - //Use empty password....it shouldn't be needed...this is a SSO login. The password has - //already been presented with the SSO server. It should not be passed around for - //better security - Credentials credentials = new Credentials(username, ""); - - httpRequest.getSession().setAttribute(Credentials.CREDENTIALS, credentials); - - // This is needed when using default login module stack instead of SSOLoginModule. In this case, GateIn authentication is done thanks to PortalLoginModule. - httpRequest.getSession().setAttribute(GenericAgent.AUTHENTICATED_CREDENTIALS, credentials); - - log.debug("Credentials of user " + username + " saved into HTTP session."); - } - - /** - * @param username - * @return gets the right username if the login input contains capital letters: EXOGTN-2267 - */ - public String getUserPrincipal(String username) { - try { - OrganizationService organizationService = - (OrganizationService) getContainer() - .getComponentInstance(OrganizationService.class); - Query query = new Query(); - query.setUserName(username); - ListAccess users = organizationService.getUserHandler().findUsersByQuery(query); - if (users.getSize() >= 1) { - String loadedUsername = ""; - User[] listusers = users.load(0, users.getSize()); - int found = 0; - for(User user : listusers){ - if (username.equalsIgnoreCase(user.getUserName())) { - loadedUsername = user.getUserName(); - found ++; - } - } - if(found == 1 && StringUtils.isNotBlank(loadedUsername)) - username = loadedUsername; - else - log.warn("duplicate entry for user " + username); - - } - } catch (Exception exception) { - log.warn("Error while retrieving user " + username + " from IDM stores " , exception); - } - return username; - } - - /** - * @return Gives the {@link ExoContainer} that fits best with the current context - */ - protected final ExoContainer getContainer() - { - ExoContainer container = ExoContainerContext.getCurrentContainer(); - if (container instanceof RootContainer) { - container = PortalContainer.getInstance(); - } - // The container is a PortalContainer or a StandaloneContainer - return container; - } - -} diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/AbstractLogoutFilter.java b/agent/src/main/java/org/gatein/sso/agent/filter/AbstractLogoutFilter.java deleted file mode 100644 index 71dbc2b46..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/filter/AbstractLogoutFilter.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.gatein.sso.agent.filter; - -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.gatein.common.http.QueryStringParser; -import org.gatein.sso.agent.filter.api.AbstractSSOInterceptor; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.Map; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -/** - * @author Sohil Shah - */ -public abstract class AbstractLogoutFilter extends AbstractSSOInterceptor -{ - protected String logoutUrl; - private static final String fileEncoding = System.getProperty("file.encoding"); - - private static final String SSO_LOGOUT_FLAG = "SSO_LOGOUT_FLAG"; - private static final String SSO_LOGOUT_REQ_URI = "SSO_LOGOUT_REQ_URI"; - private static final String SSO_LOGOUT_REQ_QUERY_STRING = "SSO_LOGOUT_REQ_QUERY_STRING"; - - protected final Log log = ExoLogger.getLogger(this.getClass()); - - protected void initImpl() - { - this.logoutUrl = getInitParameter("LOGOUT_URL"); - - log.info("Reading filter configuration: logoutUrl=" + this.logoutUrl); - } - - public void destroy() - { - } - - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException - { - HttpServletRequest httpRequest = (HttpServletRequest) request; - HttpServletResponse httpResponse = (HttpServletResponse) response; - - boolean isLogoutInProgress = this.isLogoutInProgress(httpRequest); - - if (isLogoutInProgress) - { - boolean redirectionSent = handleLogout(httpRequest, httpResponse); - if (redirectionSent) - { - return; - } - } - // This means that we returned from SSO logout, but we need to redirect request to portal logout URI (something like - // /portal/classic/home?portal:componentId=UIPortal&portal:action=Logout) because current request is not logout request - // This can happen with some SSO servers, which doesn't redirect to logout URL (CAS) - else if (httpRequest.getSession().getAttribute(SSO_LOGOUT_FLAG) != null) - { - // Restore previously saved logout URI - HttpSession httpSession = httpRequest.getSession(); - String restoredURI = (String)httpSession.getAttribute(SSO_LOGOUT_REQ_URI); - String restoredQueryString = (String)httpSession.getAttribute(SSO_LOGOUT_REQ_QUERY_STRING); - - // Cleanup all helper session attributes but keep SSO_LOGOUT_FLAG - httpSession.removeAttribute(SSO_LOGOUT_REQ_URI); - httpSession.removeAttribute(SSO_LOGOUT_REQ_QUERY_STRING); - - if (restoredURI != null && restoredQueryString != null) - { - String portalLogoutURI = restoredURI + "?" + restoredQueryString; - portalLogoutURI = httpResponse.encodeRedirectURL(portalLogoutURI); - httpResponse.sendRedirect(portalLogoutURI); - - if (log.isTraceEnabled()) - { - log.trace("SSO logout performed. Redirecting to portal logout URI: " + portalLogoutURI); - } - - return; - } - } - - chain.doFilter(request, response); - } - - protected boolean isLogoutInProgress(HttpServletRequest request) throws UnsupportedEncodingException - { - // set character encoding before retrieving request parameters - if(fileEncoding!=null) - { - request.setCharacterEncoding(fileEncoding); - } - - String action = null; - String queryString = request.getQueryString(); - if (queryString != null) { - // The QueryStringParser currently only likes & and not & - queryString = queryString.replace("&", "&"); - Map queryParams = QueryStringParser.getInstance().parseQueryString(queryString); - String[] portalActions = queryParams.get("portal:action"); - if (portalActions != null && portalActions.length > 0) { - action = portalActions[0]; - } - } - - if (action != null && action.equals("Logout")) - { - return true; - } - - return false; - } - - /** - * Handle logout on SSO server side - * - * @param httpRequest - * @param httpResponse - * @return true if redirection to SSO server was send. We need to return immediately from filter invocation then - * @throws IOException - */ - protected boolean handleLogout(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException - { - HttpSession httpSession = httpRequest.getSession(); - - // We need to perform redirection to SSO server to handle logout on SSO side - if (httpRequest.getSession().getAttribute(SSO_LOGOUT_FLAG) == null) - { - httpSession.setAttribute(SSO_LOGOUT_FLAG, Boolean.TRUE); - httpSession.setAttribute(SSO_LOGOUT_REQ_URI, httpRequest.getRequestURI()); - httpSession.setAttribute(SSO_LOGOUT_REQ_QUERY_STRING, httpRequest.getQueryString()); - - String redirectUrl = this.getRedirectUrl(httpRequest); - redirectUrl = httpResponse.encodeRedirectURL(redirectUrl); - httpResponse.sendRedirect(redirectUrl); - - if (log.isTraceEnabled()) - { - log.trace("Redirecting to SSO logout URL: " + redirectUrl); - } - - return true; - } - else - { - // We returned from SSO server. Clear the LOGOUT flag and continue with this httpRequest - httpSession.removeAttribute(SSO_LOGOUT_FLAG); - if (log.isTraceEnabled()) - { - log.trace("SSO logout performed and SSO_LOGOUT_FLAG removed from session. Continue with portal logout"); - } - - return false; - } - } - - protected abstract String getRedirectUrl(HttpServletRequest httpRequest); -} diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/InitiateLoginFilter.java b/agent/src/main/java/org/gatein/sso/agent/filter/InitiateLoginFilter.java deleted file mode 100644 index 59103b8a1..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/filter/InitiateLoginFilter.java +++ /dev/null @@ -1,177 +0,0 @@ -/** - * - */ -package org.gatein.sso.agent.filter; - -import java.io.IOException; - -import javax.servlet.*; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang.StringUtils; -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.gatein.sso.agent.GenericAgent; -import org.gatein.sso.agent.filter.api.AbstractSSOInterceptor; -import org.gatein.sso.agent.opensso.OpenSSOAgent; -import org.gatein.wci.security.Credentials; - -import org.exoplatform.commons.utils.PropertyManager; - -/** - * @author soshah - */ -public class InitiateLoginFilter extends AbstractSSOInterceptor { - private static Log log = ExoLogger.getLogger(InitiateLoginFilter.class); - - private static final int DEFAULT_MAX_NUMBER_OF_LOGIN_ERRORS = 3; - - private String ssoServerUrl; - - private String ssoCookieName; - - private String loginUrl; - - private int maxNumberOfLoginErrors; - - private boolean attachUsernamePasswordToLoginURL; - - private OpenSSOAgent openSSOAgent; - - @Override - protected void initImpl() { - this.ssoServerUrl = getInitParameter("ssoServerUrl"); - this.ssoCookieName = getInitParameter("ssoCookieName"); - this.loginUrl = getInitParameter("loginUrl"); - - String maxNumberOfLoginErrorsConfig = getInitParameter("maxNumberOfLoginErrors"); - this.maxNumberOfLoginErrors = maxNumberOfLoginErrorsConfig == null ? DEFAULT_MAX_NUMBER_OF_LOGIN_ERRORS - : Integer.parseInt(maxNumberOfLoginErrorsConfig); - - String attachUsernamePasswordToLoginURLConfig = getInitParameter("attachUsernamePasswordToLoginURL"); - this.attachUsernamePasswordToLoginURL = - attachUsernamePasswordToLoginURLConfig == null - || Boolean.parseBoolean(attachUsernamePasswordToLoginURLConfig); - } - - public void doFilter(ServletRequest request, - ServletResponse response, - FilterChain chain) throws IOException, ServletException { - try { - HttpServletRequest req = (HttpServletRequest) request; - HttpServletResponse resp = (HttpServletResponse) response; - - this.processSSOToken(req, resp); - - // Redirection can be already performed from processSSOToken call - if (resp.isCommitted()) { - return; - } - - String portalContext = req.getContextPath(); - if (req.getAttribute("abort") != null) { - String ssoSuffix = PropertyManager.getProperty("gatein.sso.uri.suffix"); - if (StringUtils.isBlank(ssoSuffix)) { - ssoSuffix = "/sso"; - } - String ssoRedirect = portalContext + (ssoSuffix.startsWith("/") ? ssoSuffix : ("/" + ssoSuffix)); - resp.sendRedirect(ssoRedirect); - return; - } - - String loginRedirectURL = getLoginRedirectUrl(req); - if (StringUtils.isBlank(loginRedirectURL)) { - log.warn("Can't redirect to null SSO URL"); - chain.doFilter(request, response); - } else { - loginRedirectURL = resp.encodeRedirectURL(loginRedirectURL); - resp.sendRedirect(loginRedirectURL); - } - } catch (Exception e) { - throw new ServletException(e); - } - } - - @Override - public void destroy() { - // Nothing to proceed - } - - protected OpenSSOAgent getOpenSSOAgent() { - if (this.openSSOAgent == null) { - OpenSSOAgent openssoAgent = getExoContainer().getComponentInstanceOfType(OpenSSOAgent.class); - if (openssoAgent == null) { - throw new IllegalStateException("OpenSSOAgent component not provided in PortalContainer"); - } - - openssoAgent.setServerUrl(ssoServerUrl); - openssoAgent.setCookieName(ssoCookieName); - this.openSSOAgent = openssoAgent; - } - - return this.openSSOAgent; - } - - protected void processSSOToken(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws Exception { - try { - // See if an OpenSSO Token was used - getOpenSSOAgent().validateTicket(httpRequest, httpResponse); - } catch (IllegalStateException ilse) { - // Somehow cookie failed validation, retry by starting the opensso login - // process again. - // To avoid infinite loop of redirects, we are tracking maximum number - // of SSO errors for this client - int currentNumberOfErrors = getCountOfUnsuccessfulAttempts(httpRequest); - log.warn("Count of login errors: " + currentNumberOfErrors); - - if (currentNumberOfErrors >= maxNumberOfLoginErrors) { - log.warn("Max. number of login errors reached. Rethrowing exception"); - throw ilse; - } else { - httpRequest.setAttribute("abort", Boolean.TRUE); - } - } - } - - // Tracking maximum number of SSO errors for this client in session attribute - private int getCountOfUnsuccessfulAttempts(HttpServletRequest httpRequest) { - Integer currentNumberOfErrors = (Integer) httpRequest.getSession().getAttribute("InitiateLoginFilter.currentNumberOfErrors"); - if (currentNumberOfErrors == null) { - currentNumberOfErrors = 0; - } - - currentNumberOfErrors = currentNumberOfErrors + 1; - httpRequest.getSession().setAttribute("InitiateLoginFilter.currentNumberOfErrors", currentNumberOfErrors); - - return currentNumberOfErrors; - } - - protected String getLoginRedirectUrl(HttpServletRequest req) { - if (this.loginUrl == null) { - return null; - } - StringBuilder url = new StringBuilder(this.loginUrl); - - if (attachUsernamePasswordToLoginURL) { - String fakePassword = req.getSession().getId() + "_" + System.currentTimeMillis(); - - // Try to use username from authenticated credentials - String username; - Credentials creds = (Credentials) req.getSession().getAttribute(GenericAgent.AUTHENTICATED_CREDENTIALS); - if (creds != null) { - username = creds.getUsername(); - } else { - // Fallback to fakePassword, but this should't happen (credentials - // should always be available when this method is called) - username = fakePassword; - } - - // Use sessionId and system millis as password (similar like spnego is - // doing) - url.append("?username=").append(username).append("&password=").append(fakePassword); - } - - return url.toString(); - } -} diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/OpenSSOCDLoginRedirectFilter.java b/agent/src/main/java/org/gatein/sso/agent/filter/OpenSSOCDLoginRedirectFilter.java deleted file mode 100644 index bd2d9e380..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/filter/OpenSSOCDLoginRedirectFilter.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual contributors as indicated - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - * - */ - -package org.gatein.sso.agent.filter; - -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.gatein.sso.agent.opensso.OpenSSOAgentImpl; - -import javax.servlet.http.HttpServletRequest; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.Random; - -/** - * Filter is used for redirection to OpenSSO CDCServlet. It is intended to be used in Cross-Domain authentication scenario - * when GateIn and OpenSSO servers are in different DNS domains. - * - * @author Marek Posolda - */ -public class OpenSSOCDLoginRedirectFilter extends LoginRedirectFilter -{ - private static final Log log = ExoLogger.getLogger(OpenSSOCDLoginRedirectFilter.class); - - private String openSSORealm; - private String agentUrl; - - private Random random = new Random(); - private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", new Locale("en")); - private SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss", new Locale("en")); - - @Override - public void initImpl() - { - super.initImpl(); - - this.openSSORealm = getInitParameter("OpenSSORealm"); - this.agentUrl = getInitParameter("AgentUrl"); - log.info("Filter configuration: loginUrl=" + loginUrl + - ", openSSORealm=" + openSSORealm + - ", agentUrl=" + agentUrl); - } - - /** - * Constructs URL for redirection to OpenSSO CDCServlet. - * It will be something like: - * {@code - * http://localhost:8888/opensso/cdcservlet?realm=gatein&goto=http://opensso.local.network:8080/portal/initiatessologin& - * ProviderID=http://opensso.local.network:8080/portal/initiatessologin/?Realm=ggatein - * &RequestID=124&IssueInstant=2012-04-10T23:28:50Z&MajorVersion=1&MinorVersion=0 - * } - * - * @return url for redirection - */ - @Override - protected String getLoginRedirectURL(HttpServletRequest httpRequest) - { - try - { - StringBuilder urlBuilder = new StringBuilder(loginUrl); - urlBuilder.append("?realm=").append(openSSORealm); - urlBuilder.append("&goto=").append(URLEncoder.encode(agentUrl, "UTF-8")); - - // We need to use Realm=g because of bug (or strange behaviour) of OpenAM, which cuts first character of realmName during parsing - // Update GTNSSO-28 - This extra char is supposed to be a "slash" on pre-10.1 versions. So, adding the "g" - // is not really appropriate. Replacing the "g" with "/" makes it work for both 9.x up to 12.0 (latest tested). - String providerId = agentUrl + "/?Realm=" + URLEncoder.encode("/" + openSSORealm, "UTF-8"); - urlBuilder.append("&ProviderID=").append(URLEncoder.encode(providerId, "UTF-8")); - - // Generate random number for parameter "inResponseTo" and save it to session. This ID must be in response message in parameter "inResponseTo" - int requestId = random.nextInt(100000) + 1; - urlBuilder.append("&RequestID=").append(requestId); - httpRequest.getSession().setAttribute(OpenSSOAgentImpl.IN_RESPONSE_TO_ATTR, requestId); - - String issueInstant = getFormattedDate(); - urlBuilder.append("&IssueInstant=" + URLEncoder.encode(issueInstant, "UTF-8")); - - urlBuilder.append("&MajorVersion=1&MinorVersion=0"); - - String urlToRedirect = urlBuilder.toString(); - - if (log.isTraceEnabled()) - { - log.trace("URL for redirection to CDCServlet: " + urlToRedirect); - } - - return urlToRedirect; - } - catch (UnsupportedEncodingException uee) - { - throw new RuntimeException(uee); - } - - } - - private String getFormattedDate() - { - Date d = new Date(); - return dateFormat.format(d) + "T" + timeFormat.format(d) + "Z"; - } - -} diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/OpenSSOLogoutFilter.java b/agent/src/main/java/org/gatein/sso/agent/filter/OpenSSOLogoutFilter.java deleted file mode 100644 index fcbb36e89..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/filter/OpenSSOLogoutFilter.java +++ /dev/null @@ -1,75 +0,0 @@ -/* -* JBoss, a division of Red Hat -* Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated -* by the @authors tag. See the copyright.txt in the distribution for a -* full listing of individual contributors. -* -* This is free software; you can redistribute it and/or modify it -* under the terms of the GNU Lesser General Public License as -* published by the Free Software Foundation; either version 2.1 of -* the License, or (at your option) any later version. -* -* This software is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this software; if not, write to the Free -* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -* 02110-1301 USA, or see the FSF site: http://www.fsf.org. -*/ -package org.gatein.sso.agent.filter; - -import java.net.URLEncoder; -import javax.servlet.http.HttpServletRequest; - -//Works for GateIn Portal Logout URL = {AnyURL}?portal:componentId=UIPortal&portal:action=Logout - -/** - * Usage: - * - * Add the following to portal.war/WEB-INF/web.xml - * - * - * OpenSSOLogoutFilter - * org.gatein.sso.agent.filter.OpenSSOLogoutFilter - * - * - * LOGOUT_URL - * http://localhost:8888/opensso/UI/Logout - * - * - * - * - * OpenSSOLogoutFilter - * /* - * - * - * - * - */ - - -/** - * @author Sohil Shah - */ -public class OpenSSOLogoutFilter extends AbstractLogoutFilter -{ - protected String getRedirectUrl(HttpServletRequest httpRequest) - { - try - { - String parameters = URLEncoder.encode( - "portal:componentId=UIPortal&portal:action=Logout", "UTF-8"); - - String redirectUrl = this.logoutUrl+"?realm=gatein&goto="+httpRequest.getRequestURL()+"?"+parameters; - - return redirectUrl; - } - catch(Exception e) - { - throw new RuntimeException(e); - } - } -} diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/PicketlinkSTSIntegrationFilter.java b/agent/src/main/java/org/gatein/sso/agent/filter/PicketlinkSTSIntegrationFilter.java deleted file mode 100644 index 73ec84271..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/filter/PicketlinkSTSIntegrationFilter.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.gatein.sso.agent.filter; - -import org.exoplatform.container.web.AbstractFilter; -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.exoplatform.services.security.jaas.UserPrincipal; -import org.jboss.security.SecurityContext; -import org.jboss.security.SecurityContextAssociation; -import org.jboss.security.client.SecurityClient; -import org.jboss.security.client.SecurityClientFactory; - -import javax.security.auth.Subject; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Set; -import org.picketlink.identity.federation.core.wstrust.SamlCredential; - -/** - * Filter for set {@link SamlCredential} into {@link SecurityClient}, which enables to propagate authentication from SAML2 ticket into - * underlying EJB or WS calls. - * - * @author Marek Posolda - */ -public class PicketlinkSTSIntegrationFilter extends AbstractFilter -{ - private static Log log = ExoLogger.getLogger(PicketlinkSTSIntegrationFilter.class); - - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException - { - HttpServletRequest httpRequest = (HttpServletRequest)request; - if (httpRequest.getRemoteUser() != null) - { - try - { - SamlCredential samlCredential = getSamlCredential(); - - if (log.isTraceEnabled()) - { - log.trace("Found SamlCredential inside Subject: " + samlCredential); - } - - // Now set the security context, which can be used in EJB or other calls - if (samlCredential != null) - { - SecurityClient client = SecurityClientFactory.getSecurityClient(); - // Simple login just updates the security context - client.setSimple(new UserPrincipal(httpRequest.getRemoteUser()), samlCredential); - client.login(); - - if (log.isTraceEnabled()) - { - log.trace("SecurityClient successfully updated with SAMLCredential"); - } - } - - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - chain.doFilter(request, response); - } - - public void destroy() - { - } - - private SamlCredential getSamlCredential() - { - Subject subj = getCurrentSubject(); - - if (log.isTraceEnabled()) - { - log.trace("Found subject " + subj); - } - - if (subj == null) - { - return null; - } - - Set credentials = subj.getPublicCredentials(); - for (Object credential : credentials) - { - if (credential instanceof SamlCredential) - { - return (SamlCredential)credential; - } - } - - return null; - } - - /** - * JBoss specific way for obtaining a Subject. - * TODO: is JBoss specific way needed? subject should be available in ConversationState - * - * @return subject - */ - protected Subject getCurrentSubject() - { - SecurityContext securityContext = AccessController.doPrivileged(new PrivilegedAction() - { - public SecurityContext run() - { - return SecurityContextAssociation.getSecurityContext(); - } - }); - return securityContext.getSubjectInfo().getAuthenticatedSubject(); - } -} diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/SPNEGOFilter.java b/agent/src/main/java/org/gatein/sso/agent/filter/SPNEGOFilter.java deleted file mode 100644 index 3616a5c66..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/filter/SPNEGOFilter.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2011, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.gatein.sso.agent.filter; - -import java.io.IOException; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import org.exoplatform.container.web.AbstractFilter; - -/** - * Filter is needed because when fallback to FORM authentication, we don't need to redirect request to /dologin, which is secured URI, - * but we need to go directly to /initiatelogin without going again through Tomcat authenticator. - * - * TODO: Suggest removing this filter as with new GateIn (Servlet 3.0 authentication) it may not be needed anymore - * - * @author Marek Posolda - */ -public class SPNEGOFilter extends AbstractFilter -{ - - public static final String ATTR_INITIAL_URI = "SPNEGOFilter.initialURI"; - - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException - { - HttpServletRequest httpRequest = (HttpServletRequest)request; - HttpServletResponse httpResponse = (HttpServletResponse)response; - try - { - - // first save initialURI as parameter into HTTP session. We may need it later in authenticator - String initialURI = httpRequest.getParameter("initialURI"); - if (initialURI != null) - { - httpRequest.getSession().setAttribute(ATTR_INITIAL_URI, initialURI); - } - - // we need to redirect directly to initiatelogin without going through secured URL. - HttpServletResponse wrapperResponse = new IgnoreRedirectHttpResponse(httpResponse); - chain.doFilter(request, wrapperResponse); - httpResponse.sendRedirect(httpRequest.getContextPath() + "/initiatelogin"); - } - catch(Throwable t) - { - throw new RuntimeException(t); - } - } - - public void destroy() - { - } - - // Ignoring calls to response.sendRedirect, which are performed from PortalLoginController - private class IgnoreRedirectHttpResponse extends HttpServletResponseWrapper - { - - public IgnoreRedirectHttpResponse(HttpServletResponse response) - { - super(response); - } - - @Override - public void sendRedirect(String location) - { - } - - } -} diff --git a/agent/src/main/java/org/gatein/sso/agent/login/SSOLoginModule.java b/agent/src/main/java/org/gatein/sso/agent/login/SSOLoginModule.java deleted file mode 100644 index e8abf9982..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/login/SSOLoginModule.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.gatein.sso.agent.login; - -import java.lang.reflect.Method; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.LoginException; -import javax.servlet.http.HttpServletRequest; - -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.exoplatform.services.security.Authenticator; -import org.exoplatform.services.security.Identity; -import org.exoplatform.services.security.UsernameCredential; -import org.exoplatform.services.security.jaas.AbstractLoginModule; -import org.gatein.sso.agent.GenericAgent; -import org.gatein.sso.agent.tomcat.ServletAccess; -import org.gatein.wci.security.Credentials; - -/** - * @author Sohil Shah - */ -public final class SSOLoginModule extends AbstractLoginModule -{ - private static final Log log = ExoLogger.getLogger(SSOLoginModule.class); - - /** JACC get context method. */ - private static Method getContextMethod; - - static - { - try - { - Class policyContextClass = Thread.currentThread().getContextClassLoader().loadClass("javax.security.jacc.PolicyContext"); - getContextMethod = policyContextClass.getDeclaredMethod("getContext", String.class); - } - catch (ClassNotFoundException ignore) - { - log.debug("JACC not found ignoring it", ignore); - } - catch (Exception e) - { - log.error("Could not obtain JACC get context method", e); - } - } - - public boolean login() throws LoginException - { - try - { - // Check credentials stored and propagated in session. - String username = null; - HttpServletRequest request = getCurrentHttpServletRequest(); - - if (request == null) - { - log.debug("HttpServletRequest is null. SSOLoginModule will be ignored."); - return false; - } - - - Credentials credsFromSession = (Credentials)request.getSession().getAttribute(GenericAgent.AUTHENTICATED_CREDENTIALS); - if (credsFromSession != null) - { - username = credsFromSession.getUsername(); - if (log.isTraceEnabled()) - { - log.trace("Found credentials in session. Username: " + username); - } - } - - if (username == null) - { - //SSO token could not be validated...hence a user id cannot be found - log.debug("SSOLogin Failed. Credential Not Found!!"); - return false; - } - - //Perform authentication by setting up the proper Application State - Authenticator authenticator = (Authenticator) getContainer() - .getComponentInstanceOfType(Authenticator.class); - - if (authenticator == null) - { - throw new LoginException( - "No Authenticator component found, check your configuration"); - } - - Identity identity = authenticator.createIdentity(username); - - sharedState.put("exo.security.identity", identity); - sharedState.put("javax.security.auth.login.name", username); - subject.getPublicCredentials().add(new UsernameCredential(username)); - - return true; - } - catch (final Throwable e) - { - throw new LoginException(e.getMessage()); - } - } - - public boolean logout() throws LoginException - { - return true; - } - - public boolean abort() throws LoginException - { - return true; - } - - public boolean commit() throws LoginException - { - return true; - } - - @Override - protected Log getLogger() - { - return log; - } - - protected HttpServletRequest getCurrentHttpServletRequest() - { - HttpServletRequest request = null; - - // JBoss way - if (getContextMethod != null) - { - try - { - request = (HttpServletRequest)getContextMethod.invoke(null, "javax.servlet.http.HttpServletRequest"); - } - catch(Throwable e) - { - log.error("LoginModule error. Turn off session credentials checking with proper configuration option of " + - "LoginModule set to false"); - log.error(this, e); - } - } - // Tomcat way (Assumed that ServletAccessValve has been configured in context.xml) - else - { - request = ServletAccess.getRequest(); - } - - if (log.isTraceEnabled()) - { - log.trace("Returning HttpServletRequest " + request); - } - - return request; - } -} \ No newline at end of file diff --git a/agent/src/main/java/org/gatein/sso/agent/opensso/CDMessageContext.java b/agent/src/main/java/org/gatein/sso/agent/opensso/CDMessageContext.java deleted file mode 100644 index 3cc347d65..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/opensso/CDMessageContext.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual contributors as indicated - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - * - */ - -package org.gatein.sso.agent.opensso; - -/** - * Encapsulate all important informations from SAML message received from OpenSSO CDCServlet - * - * @author Marek Posolda - */ -class CDMessageContext -{ - - private final Boolean success; - private final Integer inResponseTo; - private final String notBefore; - private final String notOnOrAfter; - private final String ssoToken; - - public CDMessageContext(Boolean success, Integer inResponseTo, String notBefore, - String notOnOrAfter, String ssoToken) - { - this.success = success; - this.inResponseTo = inResponseTo; - this.notBefore = notBefore; - this.notOnOrAfter = notOnOrAfter; - this.ssoToken = ssoToken; - } - - public Boolean getSuccess() - { - return success; - } - - public Integer getInResponseTo() - { - return inResponseTo; - } - - public String getNotBefore() - { - return notBefore; - } - - public String getNotOnOrAfter() - { - return notOnOrAfter; - } - - public String getSsoToken() - { - return ssoToken; - } - - @Override - public String toString() - { - StringBuilder builder = new StringBuilder("CDMessageContext [ success="); - builder.append(success).append(", inResponseTo=").append(inResponseTo); - builder.append(", notBefore=").append(notBefore); - builder.append(", notOnOrAfter=").append(notOnOrAfter); - builder.append(", token=").append(ssoToken).append(" ]"); - return builder.toString(); - } -} diff --git a/agent/src/main/java/org/gatein/sso/agent/opensso/CDMessageParser.java b/agent/src/main/java/org/gatein/sso/agent/opensso/CDMessageParser.java deleted file mode 100644 index b10e28205..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/opensso/CDMessageParser.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual contributors as indicated - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - * - */ - -package org.gatein.sso.agent.opensso; - -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.gatein.common.util.Base64; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Parsing of SAML message received from OpenSSO CDCServlet - * - * @author Marek Posolda - */ -class CDMessageParser -{ - - private static final Log log = ExoLogger.getLogger(CDMessageParser.class); - - private static final Pattern SAML_SUCCESS_PATTERN = Pattern.compile(""); - private static final Pattern SAML_DATE_CONDITIONS = Pattern.compile(""); - private static final Pattern IN_RESPONSE_TO_PATTERN = Pattern.compile("InResponseTo=\"([0-9]*)\""); - private static final Pattern TOKEN_PATTERN = Pattern.compile("(.*)"); - - /** - * - * @param encodedInputMessage - * @return decoded and parsed object with all important informations from SAML message - */ - public CDMessageContext parseMessage(String encodedInputMessage) - { - String decodedMessage = decodeMessage(encodedInputMessage); - - if (log.isTraceEnabled()) - { - log.trace("Decoded message from CDCServlet: "); - log.trace(decodedMessage); - } - - boolean success = false; - Matcher m = SAML_SUCCESS_PATTERN.matcher(decodedMessage); - if (m.find()) - { - String group = m.group(1); - if (group.contains("samlp:Success")) - { - success = true; - } - } - - String beforeDate = null; - String afterDate = null; - m = SAML_DATE_CONDITIONS.matcher(decodedMessage); - if (m.find()) - { - beforeDate = m.group(1); - afterDate = m.group(2); - } - - Integer inResponseTo = -1; - m = IN_RESPONSE_TO_PATTERN.matcher(decodedMessage); - if (m.find()) - { - inResponseTo = Integer.parseInt(m.group(1)); - } - - String token = null; - m = TOKEN_PATTERN.matcher(decodedMessage); - if (m.find()) - { - token = m.group(1); - } - // Token is URL encoded in OpenSSO and we need to decode it (not encoded in OpenAM but we can decode in either case) - try - { - token = URLDecoder.decode(token, "UTF-8"); - } - catch (UnsupportedEncodingException uee) - { - throw new RuntimeException(uee); - } - - return new CDMessageContext(success, inResponseTo, beforeDate, afterDate, token); - } - - /** - * @param encodedInputMessage - * @return decoded string, which represents SAML message received from CDCServlet - */ - String decodeMessage(String encodedInputMessage) - { - byte[] bytes = Base64.decode(encodedInputMessage); - String decodedSamlMessage = new String(bytes); - return decodedSamlMessage; - } -} diff --git a/agent/src/main/java/org/gatein/sso/agent/opensso/OpenSSOAgent.java b/agent/src/main/java/org/gatein/sso/agent/opensso/OpenSSOAgent.java deleted file mode 100644 index 8f6965857..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/opensso/OpenSSOAgent.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.gatein.sso.agent.opensso; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Contract for OpenSSO agent - * - * @author Marek Posolda - */ -public interface OpenSSOAgent -{ - public void setCookieName(String cookieName); - - public void setServerUrl(String serverUrl); - - public void validateTicket(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws Exception; -} diff --git a/agent/src/main/java/org/gatein/sso/agent/opensso/OpenSSOAgentImpl.java b/agent/src/main/java/org/gatein/sso/agent/opensso/OpenSSOAgentImpl.java deleted file mode 100644 index 006223c5e..000000000 --- a/agent/src/main/java/org/gatein/sso/agent/opensso/OpenSSOAgentImpl.java +++ /dev/null @@ -1,378 +0,0 @@ -/* -* JBoss, a division of Red Hat -* Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated -* by the @authors tag. See the copyright.txt in the distribution for a -* full listing of individual contributors. -* -* This is free software; you can redistribute it and/or modify it -* under the terms of the GNU Lesser General Public License as -* published by the Free Software Foundation; either version 2.1 of -* the License, or (at your option) any later version. -* -* This software is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this software; if not, write to the Free -* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -* 02110-1301 USA, or see the FSF site: http://www.fsf.org. -*/ -package org.gatein.sso.agent.opensso; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.exoplatform.container.xml.InitParams; -import org.exoplatform.container.xml.ValueParam; -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.gatein.sso.agent.GenericAgent; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -/** - * @author Sohil Shah - */ -public class OpenSSOAgentImpl extends GenericAgent implements OpenSSOAgent -{ - // HttpSession attribute, which will be used to check that response message from CDC contains same ID of InResponseTo as the ID, which we used in OpenSSOCDLoginRedirectFilter - public static final String IN_RESPONSE_TO_ATTR = "OpenSSOAgent.InResponseTo"; - - // Possible line separators on various OS - private static final String WINDOWS_SEPARATOR = "\r\n"; - private static final String UNIX_SEPARATOR = "\n"; - private static final String MAC_SEPARATOR = "\r"; - - private static final String[] LINE_SEPARATORS = new String[] { WINDOWS_SEPARATOR, UNIX_SEPARATOR, MAC_SEPARATOR }; - - private static Log log = ExoLogger.getLogger(OpenSSOAgentImpl.class); - - private String cookieName; - private String serverUrl; - private final String lineSeparator; - - private CDMessageParser cdcMessageParser = new CDMessageParser(); - - public OpenSSOAgentImpl(InitParams params) - { - // TODO: Read serverUrl and cookieName from params - if (params == null) - { - this.lineSeparator = null; - return; - } - - ValueParam lineSeparatorParam = params.getValueParam("lineSeparator"); - if (lineSeparatorParam != null) - { - this.lineSeparator = lineSeparatorParam.getValue(); - } - else - { - this.lineSeparator = null; - } - - log.debug("Agent configured with line separator: " + this.lineSeparator); - } - - public void setCookieName(String cookieName) - { - this.cookieName = cookieName; - } - - public void setServerUrl(String serverUrl) - { - this.serverUrl = serverUrl; - } - - - - public void validateTicket(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws Exception - { - // Start with processing message from CDCServlet if this message is available (it should be in servlet request parameter "LARES") - if (tryMessageFromCDC(httpRequest, httpResponse)) - { - return; - } - - // Now cookie should be set and we can continue with cookie processing - String token = null; - Cookie[] cookies = httpRequest.getCookies(); - if(cookies == null) - { - return; - } - - for(Cookie cookie: cookies) - { - if(cookie.getName().equals(this.cookieName)) - { - token = cookie.getValue(); - break; - } - } - - if(token == null) - { - throwIllegalStateException("No SSO Tokens Found"); - } - - if(token != null) - { - boolean isValid = this.isTokenValid(token); - - if(!isValid) - { - throwIllegalStateException("OpenSSO Token is not valid!!"); - } - - String subject = this.getSubject(token); - if(subject != null) - { - this.saveSSOCredentials(subject, httpRequest); - } - } - } - - /** - * This method is useful only for Cross-Domain (CD) authentication scenario when GateIn and OpenSSO are in different DNS domains and they can't share cookie. - * - * It performs: - *
    - *
  • Parse and validate message from OpenSSO CDCServlet.
  • - *
  • Use ssoToken from parsed message and establish OpenSSO cookie iPlanetDirectoryPro
  • - *
  • Redirects to InitiateLoginFilter but with cookie established. So in next request, we can perform agent validation against OpenSSO server
  • - *
- * - * @param httpRequest - * @param httpResponse - * @return true if parameter LARES with message from CDC is present in HttpServletRequest - * @throws IOException - */ - protected boolean tryMessageFromCDC(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException - { - String encodedCDCMessage = httpRequest.getParameter("LARES"); - - if (encodedCDCMessage == null) - { - if (log.isTraceEnabled()) - { - log.trace("Message from CDC not found in this HttpServletRequest"); - } - return false; - } - - CDMessageContext messageContext = cdcMessageParser.parseMessage(encodedCDCMessage); - if (log.isTraceEnabled()) - { - log.trace("Successfully parsed messageContext " + messageContext); - } - - // Validate received messageContext - validateCDMessageContext(httpRequest, messageContext); - - // Establish cookie with ssoToken - String ssoToken = messageContext.getSsoToken(); - Cookie cookie = new Cookie(cookieName, "\"" + ssoToken + "\""); - cookie.setPath(httpRequest.getContextPath()); - httpResponse.addCookie(cookie); - if (log.isTraceEnabled()) - { - log.trace("Cookie " + cookieName + " with value " + ssoToken + " added to HttpResponse"); - } - - // Redirect again this request to be processed by OpenSSOAgent. Now we have cookie established - String urlToRedirect = httpResponse.encodeRedirectURL(httpRequest.getRequestURI()); - httpResponse.sendRedirect(urlToRedirect); - - return true; - } - - - /** - * Validation of various criterias in {@link CDMessageContext} - * - * @param httpRequest - * @param context - */ - protected void validateCDMessageContext(HttpServletRequest httpRequest, CDMessageContext context) - { - // First validate if context contains success - if (!context.getSuccess()) - { - throwIllegalStateException("CDMessageContext contains success=false. Check SAML message from CDCServlet"); - } - - // Now validate inResponseTo - Integer inResponseToFromCDC = context.getInResponseTo(); - Integer inResponseToFromSession = (Integer)httpRequest.getSession().getAttribute(IN_RESPONSE_TO_ATTR); - if (inResponseToFromSession == null || inResponseToFromCDC == null || !inResponseToFromCDC.equals(inResponseToFromSession)) - { - throwIllegalStateException("inResponseTo from CDC message is " + inResponseToFromCDC + ", inResponseTo from Http session is " + inResponseToFromSession + ". Both should have same value"); - } - - // TODO: validate dates notBefore and notOnOrAfter - - // Validate that token is present - if (context.getSsoToken() == null) - { - throwIllegalStateException("No token found in CDMessageContext. Check SAML message from CDCServlet"); - } - } - - //------------------------------------------------------------------------------------------------------------------------------------------------------------------- - protected boolean isTokenValid(String token) throws Exception - { - DefaultHttpClient client = new DefaultHttpClient(); - HttpPost post; - try - { - String url = this.serverUrl+"/identity/isTokenValid"; - post = new HttpPost(url); - - List nameValuePairs = new ArrayList(2); - nameValuePairs.add(new BasicNameValuePair("tokenid", token)); - post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); - - HttpResponse httpResponse = client.execute(post); - int status = httpResponse.getStatusLine().getStatusCode(); - HttpEntity entity = httpResponse.getEntity(); - String response = entity == null ? null : EntityUtils.toString(entity); - - log.debug("Status of token validation: " + status); - log.debug("Response from token validation: " + response); - - if(response.contains(Boolean.TRUE.toString())) - { - return true; - } - - return false; - } - finally - { - client.getConnectionManager().shutdown(); - } - } - - protected String getSubject(String token) throws Exception - { - DefaultHttpClient client = new DefaultHttpClient(); - HttpPost post; - try - { - String uid = null; - String url = this.serverUrl+"/identity/attributes"; - post = new HttpPost(url); - - List nameValuePairs = new ArrayList(2); - nameValuePairs.add(new BasicNameValuePair("subjectid", token)); - nameValuePairs.add(new BasicNameValuePair("attributes_names", "uid")); - post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); - - HttpResponse httpResponse = client.execute(post); - int status = httpResponse.getStatusLine().getStatusCode(); - HttpEntity entity = httpResponse.getEntity(); - String response = entity == null ? null : EntityUtils.toString(entity); - - log.debug("Status of get subject: " + status); - log.debug(response); - - if(response != null) - { - Properties properties = this.loadAttributes(response); - uid = properties.getProperty("uid"); - } - - - return uid; - } - finally - { - client.getConnectionManager().shutdown(); - } - } - - protected Properties loadAttributes(String response) throws Exception - { - InputStream is = null; - try - { - Properties properties = new Properties(); - - String[] tokens = response.split(getLineSeparator(response)); - String name = null; - for(String token: tokens) - { - if(token.startsWith("userdetails.attribute.name")) - { - name = token.substring(token.indexOf("=")+1); - } - else if(token.startsWith("userdetails.attribute.value")) - { - String value = token.substring(token.indexOf("=")+1); - - if(name != null) - { - properties.setProperty(name, value); - } - - //cleanup - name = null; - } - } - - return properties; - } - finally - { - if(is != null) - { - is.close(); - } - } - } - - // Use configured line separator or try to "guess" it from LINE_SEPARATORS set - private String getLineSeparator(String response) - { - if (this.lineSeparator != null) - { - return lineSeparator; - } - else - { - for (String current : LINE_SEPARATORS) - { - if (response.contains(current)) - { - return current; - } - } - - throw new IllegalArgumentException("Can't obtain line separator from response string: " + response); - } - } - - private void throwIllegalStateException(String message) - { - log.warn(message); - IllegalStateException ise = new IllegalStateException(message); - throw ise; - } - -} diff --git a/agent/src/main/resources/conf/portal/configuration.xml b/agent/src/main/resources/conf/portal/configuration.xml deleted file mode 100644 index 7c919c969..000000000 --- a/agent/src/main/resources/conf/portal/configuration.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/agent/src/test/java/org/gatein/sso/agent/filter/InitiateLoginFilterTest.java b/agent/src/test/java/org/gatein/sso/agent/filter/InitiateLoginFilterTest.java deleted file mode 100644 index 0b7086a48..000000000 --- a/agent/src/test/java/org/gatein/sso/agent/filter/InitiateLoginFilterTest.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.gatein.sso.agent.filter; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.startsWith; -import static org.mockito.Mockito.doCallRealMethod; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.mockito.internal.verification.VerificationModeFactory; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import org.exoplatform.commons.utils.PropertyManager; - -import junit.framework.TestCase; - -public class InitiateLoginFilterTest extends TestCase { - - public void testDoFilterNoRedirect() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - FilterChain chain = mock(FilterChain.class); - - InitiateLoginFilter initiateLoginFilter = mock(InitiateLoginFilter.class); - FilterConfig filterConfig = mock(FilterConfig.class); - ServletContext servletContext = mock(ServletContext.class); - - // When - when(response.encodeRedirectURL(any())).thenAnswer(new Answer() { - public String answer(InvocationOnMock invocation) throws Throwable { - return (String) invocation.getArguments()[0]; - } - }); - when(filterConfig.getServletContext()).thenReturn(servletContext); - when(servletContext.getServletContextName()).thenReturn("portal"); - when(servletContext.getContextPath()).thenReturn("/portal"); - when(request.getContextPath()).thenReturn("/portal"); - - doNothing().when(initiateLoginFilter).processSSOToken(request, response); - - doCallRealMethod().when(initiateLoginFilter).doFilter(request, response, chain); - doCallRealMethod().when(initiateLoginFilter).getLoginRedirectUrl(request); - - initiateLoginFilter.init(filterConfig); - initiateLoginFilter.doFilter(request, response, chain); - - // Then - verify(response, VerificationModeFactory.times(0)).sendRedirect(anyString()); - verify(chain, VerificationModeFactory.times(1)).doFilter(request, response); - } - - public void testDoFilterSendRedirectDoLogin() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - HttpSession httpSession = mock(HttpSession.class); - FilterChain chain = mock(FilterChain.class); - - InitiateLoginFilter initiateLoginFilter = mock(InitiateLoginFilter.class); - FilterConfig filterConfig = mock(FilterConfig.class); - ServletContext servletContext = mock(ServletContext.class); - - // When - when(request.getSession()).thenReturn(httpSession); - when(httpSession.getId()).thenReturn("fakeHttpSession"); - when(response.encodeRedirectURL(any())).thenAnswer(new Answer() { - public String answer(InvocationOnMock invocation) throws Throwable { - return (String) invocation.getArguments()[0]; - } - }); - when(filterConfig.getServletContext()).thenReturn(servletContext); - when(servletContext.getServletContextName()).thenReturn("portal"); - when(servletContext.getContextPath()).thenReturn("/portal"); - when(request.getContextPath()).thenReturn("/portal"); - - doNothing().when(initiateLoginFilter).processSSOToken(request, response); - doCallRealMethod().when(initiateLoginFilter).doFilter(request, response, chain); - doCallRealMethod().when(initiateLoginFilter).getLoginRedirectUrl(request); - doReturn("/portal/dologin").when(initiateLoginFilter).getInitParameter("loginUrl"); - doCallRealMethod().when(initiateLoginFilter).initImpl(); - - initiateLoginFilter.init(filterConfig); - initiateLoginFilter.doFilter(request, response, chain); - - // Then - verify(response, VerificationModeFactory.times(1)).sendRedirect(startsWith("/portal/dologin?")); - verify(chain, VerificationModeFactory.times(0)).doFilter(request, response); - } - - public void testSendRedirectSSO() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - FilterChain chain = mock(FilterChain.class); - - InitiateLoginFilter initiateLoginFilter = mock(InitiateLoginFilter.class); - FilterConfig filterConfig = mock(FilterConfig.class); - ServletContext servletContext = mock(ServletContext.class); - - // When - when(response.encodeRedirectURL(any())).thenAnswer(new Answer() { - public String answer(InvocationOnMock invocation) throws Throwable { - return (String) invocation.getArguments()[0]; - } - }); - when(filterConfig.getServletContext()).thenReturn(servletContext); - when(servletContext.getServletContextName()).thenReturn("portal"); - when(servletContext.getContextPath()).thenReturn("/portal"); - when(request.getContextPath()).thenReturn("/portal"); - doNothing().when(initiateLoginFilter).processSSOToken(request, response); - doCallRealMethod().when(initiateLoginFilter).doFilter(request, response, chain); - doCallRealMethod().when(initiateLoginFilter).getLoginRedirectUrl(request); - doReturn("/portal/dologin").when(initiateLoginFilter).getInitParameter("loginUrl"); - doCallRealMethod().when(initiateLoginFilter).initImpl(); - when(request.getAttribute(eq("abort"))).thenReturn("true"); - - // Then - initiateLoginFilter.init(filterConfig); - initiateLoginFilter.doFilter(request, response, chain); - verify(response, VerificationModeFactory.times(1)).sendRedirect(eq("/portal/sso")); - verify(chain, VerificationModeFactory.times(0)).doFilter(request, response); - } - - public void testSendRedirectSAMLSSO() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - FilterChain chain = mock(FilterChain.class); - - InitiateLoginFilter initiateLoginFilter = mock(InitiateLoginFilter.class); - FilterConfig filterConfig = mock(FilterConfig.class); - ServletContext servletContext = mock(ServletContext.class); - - // When - when(response.encodeRedirectURL(any())).thenAnswer(new Answer() { - public String answer(InvocationOnMock invocation) throws Throwable { - return (String) invocation.getArguments()[0]; - } - }); - when(filterConfig.getServletContext()).thenReturn(servletContext); - when(servletContext.getServletContextName()).thenReturn("portal"); - when(servletContext.getContextPath()).thenReturn("/portal"); - when(request.getContextPath()).thenReturn("/portal"); - - doNothing().when(initiateLoginFilter).processSSOToken(request, response); - - doCallRealMethod().when(initiateLoginFilter).doFilter(request, response, chain); - doCallRealMethod().when(initiateLoginFilter).getLoginRedirectUrl(request); - - doReturn("/portal/dologin").when(initiateLoginFilter).getInitParameter("loginUrl"); - doCallRealMethod().when(initiateLoginFilter).initImpl(); - PropertyManager.setProperty("gatein.sso.uri.suffix", "samlSSO"); - - when(response.encodeRedirectURL(any())).thenAnswer(new Answer() { - public String answer(InvocationOnMock invocation) throws Throwable { - return (String) invocation.getArguments()[0]; - } - }); - - when(request.getAttribute(eq("abort"))).thenReturn("true"); - initiateLoginFilter.init(filterConfig); - initiateLoginFilter.doFilter(request, response, chain); - - // Then - verify(response, VerificationModeFactory.times(1)).sendRedirect(eq("/portal/samlSSO")); - verify(chain, VerificationModeFactory.times(0)).doFilter(request, response); - } -} diff --git a/agent/src/test/java/org/gatein/sso/agent/opensso/TestParseSubject.java b/agent/src/test/java/org/gatein/sso/agent/opensso/TestParseSubject.java deleted file mode 100644 index 3e635e833..000000000 --- a/agent/src/test/java/org/gatein/sso/agent/opensso/TestParseSubject.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.gatein.sso.agent.opensso; - -import java.util.Properties; - -import junit.framework.TestCase; - -/** - * @author Marek Posolda - */ -public class TestParseSubject extends TestCase -{ - - private String LINUX_STRING = "userdetails.token.id=AQIC5wM2LY4SgtrcwwIrICaSkhcmXs5P-DmDBAc8itxVUt8Lo.*AAJTSQACMDE.*\nuserdetails.attribute.name=uid\nuserdetails.attribute.value=johny\nuserdetails.attribute.name=sn\nuserdetails.attribute.value=johnysn\nuserdetails.attribute.name=userpassword\nuserdetails.attribute.value={SSHA}Ug4jcPDG54L/dZGzvP6AbjjRllvXyDqK0et2Xw=="; - private String WINDOWS_STRING = "userdetails.token.id=AQIC5wM2LY4SfcwwIrICaSkhcmXs5P-DmDBAc8itxVUt8Lo.*AAJTSQACMDE.*\r\nuserdetails.attribute.name=uid\r\nuserdetails.attribute.value=root\r\nuserdetails.attribute.name=sn\r\nuserdetails.attribute.value=rootsn\r\nuserdetails.attribute.name=userpassword\r\nuserdetails.attribute.value={SSHA}Ug4jcPDG54L/dZGzvP6AbjjRllvXyDqK0et2Xw=="; - private String MAC_STRING = "userdetails.token.id=AQIC5wM2LY4SfcwwIrICaSkhcmXs5P-DmDBAc8itxVUt8Lo.*AAJTSQACMDE.*\ruserdetails.attribute.name=uid\ruserdetails.attribute.value=mary\ruserdetails.attribute.name=sn\ruserdetails.attribute.value=marysn\ruserdetails.attribute.name=userpassword\ruserdetails.attribute.value={SSHA}Ug4jcPDG54L/dZGzvP6AbjjRllvXyDqK0et2Xw=="; - - public void testParseSubject() throws Exception - { - OpenSSOAgentImpl agent = new OpenSSOAgentImpl(null); - - // Test linux properties - Properties linuxProps = agent.loadAttributes(LINUX_STRING); - assertEquals("johny", linuxProps.get("uid")); - assertEquals("johnysn", linuxProps.get("sn")); - - // Test windows properties - Properties windowsProps = agent.loadAttributes(WINDOWS_STRING); - assertEquals("root", windowsProps.get("uid")); - assertEquals("rootsn", windowsProps.get("sn")); - - // Test linux properties - Properties macProps = agent.loadAttributes(MAC_STRING); - assertEquals("mary", macProps.get("uid")); - assertEquals("marysn", macProps.get("sn")); - } - -} diff --git a/agent/src/test/java/org/gatein/sso/agent/opensso/TestParsingMessageFromCDC.java b/agent/src/test/java/org/gatein/sso/agent/opensso/TestParsingMessageFromCDC.java deleted file mode 100644 index f902539de..000000000 --- a/agent/src/test/java/org/gatein/sso/agent/opensso/TestParsingMessageFromCDC.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual contributors as indicated - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - * - */ - -package org.gatein.sso.agent.opensso; - -import junit.framework.TestCase; -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; - -/** - * @author Marek Posolda - */ -public class TestParsingMessageFromCDC extends TestCase -{ - private static Log log = ExoLogger.getLogger(TestParsingMessageFromCDC.class); - - // SSO token is not URL encoded in OpenAM - private static final String TEST_MESSAGE_OPENAM = "PGxpYjpBdXRoblJlc3BvbnNlIHhtbG5zOmxpYj0iaHR0cDovL3Byb2plY3RsaWJlcnR5Lm9yZy9zY2hlbWFzL2NvcmUvMjAwMi8xMiIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFzc2VydGlvbiIgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMDpwcm90b2NvbCIgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIFJlc3BvbnNlSUQ9InNmYWMwNTU4MmJkMmMwNzgwZTg3Yjc3YTUzOTkxNjYxOTA3ZTk1ZDdhIiAgSW5SZXNwb25zZVRvPSIxMjQiIE1ham9yVmVyc2lvbj0iMSIgTWlub3JWZXJzaW9uPSIwIiBJc3N1ZUluc3RhbnQ9IjIwMTItMDQtMTJUMDc6NDY6MTVaIj48c2FtbHA6U3RhdHVzPgo8c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0ic2FtbHA6U3VjY2VzcyI+Cjwvc2FtbHA6U3RhdHVzQ29kZT4KPC9zYW1scDpTdGF0dXM+CjxzYW1sOkFzc2VydGlvbiAgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFzc2VydGlvbiIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgIHhtbG5zOmxpYj0iaHR0cDovL3Byb2plY3RsaWJlcnR5Lm9yZy9zY2hlbWFzL2NvcmUvMjAwMi8xMiIgIGlkPSJzYTMxOWVmZTljNGQzYzUyNDQwNzRhMmFjMTg1MmY4MWJhYWNjYjE0NzAxIiBNYWpvclZlcnNpb249IjEiIE1pbm9yVmVyc2lvbj0iMCIgQXNzZXJ0aW9uSUQ9InNhMzE5ZWZlOWM0ZDNjNTI0NDA3NGEyYWMxODUyZjgxYmFhY2NiMTQ3MDEiIElzc3Vlcj0iaHR0cDovL2xvY2FsaG9zdDo4ODg4L29wZW5zc28vY2Rjc2VydmxldCIgSXNzdWVJbnN0YW50PSIyMDEyLTA0LTEyVDA3OjQ2OjE1WiIgSW5SZXNwb25zZVRvPSIxMjQiIHhzaTp0eXBlPSJsaWI6QXNzZXJ0aW9uVHlwZSI+CjxzYW1sOkNvbmRpdGlvbnMgIE5vdEJlZm9yZT0iMjAxMi0wNC0xMlQwNzo0NjoxNVoiIE5vdE9uT3JBZnRlcj0iMjAxMi0wNC0xMlQwNzo0NzoxNVoiID4KPHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbkNvbmRpdGlvbj4KPHNhbWw6QXVkaWVuY2U+aHR0cDovL2pvc3NvLTAxLmxvY2FsLm5ldHdvcms6ODA4MC9wb3J0YWwvaW5pdGlhdGVzc29sb2dpbi8/UmVhbG09Z2dhdGVpbjwvc2FtbDpBdWRpZW5jZT4KPC9zYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb25Db25kaXRpb24+Cjwvc2FtbDpDb25kaXRpb25zPgo8c2FtbDpBdXRoZW50aWNhdGlvblN0YXRlbWVudCAgQXV0aGVudGljYXRpb25NZXRob2Q9IkF1dGhlbnRpY2F0aW9uUGx1Z2luIiBBdXRoZW50aWNhdGlvbkluc3RhbnQ9IjIwMTItMDQtMTJUMDc6NDY6MTVaIiBSZWF1dGhlbnRpY2F0ZU9uT3JBZnRlcj0iMjAxMi0wNC0xMlQwNzo0NzoxNVoiIHhzaTp0eXBlPSJsaWI6QXV0aGVudGljYXRpb25TdGF0ZW1lbnRUeXBlIj48c2FtbDpTdWJqZWN0ICAgeHNpOnR5cGU9ImxpYjpTdWJqZWN0VHlwZSI+PHNhbWw6TmFtZUlkZW50aWZpZXIgTmFtZVF1YWxpZmllcj0iaHR0cDovL2xvY2FsaG9zdDo4ODg4L29wZW5zc28vY2Rjc2VydmxldCI+QVFJQzV3TTJMWTRTZmN3QU42aGppak9DUE8xdTdVdXJFbjlEdnFGWEt6d0ZzaTAuKkFBSlRTUUFDTURFLio8L3NhbWw6TmFtZUlkZW50aWZpZXI+CjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24+CjxzYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6Y206YmVhcmVyPC9zYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD4KPC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24+CjxsaWI6SURQUHJvdmlkZWROYW1lSWRlbnRpZmllciAgTmFtZVF1YWxpZmllcj0iaHR0cDovL2xvY2FsaG9zdDo4ODg4L29wZW5zc28vY2Rjc2VydmxldCIgPkFRSUM1d00yTFk0U2Zjd0FONmhqaWpPQ1BPMXU3VXVyRW45RHZxRlhLendGc2kwLipBQUpUU1FBQ01ERS4qPC9saWI6SURQUHJvdmlkZWROYW1lSWRlbnRpZmllcj4KPC9zYW1sOlN1YmplY3Q+PHNhbWw6U3ViamVjdExvY2FsaXR5ICBJUEFkZHJlc3M9IjEyNy4wLjAuMSIgRE5TQWRkcmVzcz0ibG9jYWxob3N0IiAvPjxsaWI6QXV0aG5Db250ZXh0PjxsaWI6QXV0aG5Db250ZXh0Q2xhc3NSZWY+aHR0cDovL3d3dy5wcm9qZWN0bGliZXJ0eS5vcmcvc2NoZW1hcy9hdXRoY3R4L2NsYXNzZXMvUGFzc3dvcmQ8L2xpYjpBdXRobkNvbnRleHRDbGFzc1JlZj48bGliOkF1dGhuQ29udGV4dFN0YXRlbWVudFJlZj5odHRwOi8vd3d3LnByb2plY3RsaWJlcnR5Lm9yZy9zY2hlbWFzL2F1dGhjdHgvY2xhc3Nlcy9QYXNzd29yZDwvbGliOkF1dGhuQ29udGV4dFN0YXRlbWVudFJlZj48L2xpYjpBdXRobkNvbnRleHQ+PC9zYW1sOkF1dGhlbnRpY2F0aW9uU3RhdGVtZW50Pjwvc2FtbDpBc3NlcnRpb24+CjxsaWI6UHJvdmlkZXJJRD5odHRwOi8vbG9jYWxob3N0Ojg4ODgvb3BlbnNzby9jZGNzZXJ2bGV0PC9saWI6UHJvdmlkZXJJRD48L2xpYjpBdXRoblJlc3BvbnNlPgo="; - - // SSO token is URL encoded in OpenSSO - private static final String TEST_MESSAGE_OPENSSO = "PGxpYjpBdXRoblJlc3BvbnNlIHhtbG5zOmxpYj0iaHR0cDovL3Byb2plY3RsaWJlcnR5Lm9yZy9zY2hlbWFzL2NvcmUvMjAwMi8xMiIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFzc2VydGlvbiIgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMDpwcm90b2NvbCIgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIFJlc3BvbnNlSUQ9InNmZTNjNWI5MzIwZDA5MjM5MGUxYmJjMmE0MzE4NzcwM2NkOTM0NDY1IiAgSW5SZXNwb25zZVRvPSI0NzU3MyIgTWFqb3JWZXJzaW9uPSIxIiBNaW5vclZlcnNpb249IjAiIElzc3VlSW5zdGFudD0iMjAxMi0wNC0xMlQyMjoxMTo0MloiPjxzYW1scDpTdGF0dXM+CjxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJzYW1scDpTdWNjZXNzIj4KPC9zYW1scDpTdGF0dXNDb2RlPgo8L3NhbWxwOlN0YXR1cz4KPHNhbWw6QXNzZXJ0aW9uICB4bWxuczpzYW1sPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6YXNzZXJ0aW9uIiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAgeG1sbnM6bGliPSJodHRwOi8vcHJvamVjdGxpYmVydHkub3JnL3NjaGVtYXMvY29yZS8yMDAyLzEyIiAgaWQ9InNmMzQ3NTgzODZhMWNjYjI2YmVjMzc4ZjQxM2U1ZDE1MGU4MDMzYWQyMDEiIE1ham9yVmVyc2lvbj0iMSIgTWlub3JWZXJzaW9uPSIwIiBBc3NlcnRpb25JRD0ic2YzNDc1ODM4NmExY2NiMjZiZWMzNzhmNDEzZTVkMTUwZTgwMzNhZDIwMSIgSXNzdWVyPSJodHRwOi8vbG9jYWxob3N0Ojg4ODgvb3BlbnNzby9jZGNzZXJ2bGV0IiBJc3N1ZUluc3RhbnQ9IjIwMTItMDQtMTJUMjI6MTE6NDJaIiBJblJlc3BvbnNlVG89IjQ3NTczIiB4c2k6dHlwZT0ibGliOkFzc2VydGlvblR5cGUiPgo8c2FtbDpDb25kaXRpb25zICBOb3RCZWZvcmU9IjIwMTItMDQtMTJUMjI6MTE6NDJaIiBOb3RPbk9yQWZ0ZXI9IjIwMTItMDQtMTJUMjI6MTI6NDJaIiA+CjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb25Db25kaXRpb24+CjxzYW1sOkF1ZGllbmNlPmh0dHA6Ly9qb3Nzby0wMS5sb2NhbC5uZXR3b3JrOjgwODAvcG9ydGFsL2luaXRpYXRlc3NvbG9naW4vP1JlYWxtPWdnYXRlaW48L3NhbWw6QXVkaWVuY2U+Cjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uQ29uZGl0aW9uPgo8L3NhbWw6Q29uZGl0aW9ucz4KPHNhbWw6QXV0aGVudGljYXRpb25TdGF0ZW1lbnQgIEF1dGhlbnRpY2F0aW9uTWV0aG9kPSJBdXRoZW50aWNhdGlvblBsdWdpbiIgQXV0aGVudGljYXRpb25JbnN0YW50PSIyMDEyLTA0LTEyVDIyOjExOjQyWiIgUmVhdXRoZW50aWNhdGVPbk9yQWZ0ZXI9IjIwMTItMDQtMTJUMjI6MTI6NDJaIiB4c2k6dHlwZT0ibGliOkF1dGhlbnRpY2F0aW9uU3RhdGVtZW50VHlwZSI+PHNhbWw6U3ViamVjdCAgIHhzaTp0eXBlPSJsaWI6U3ViamVjdFR5cGUiPjxzYW1sOk5hbWVJZGVudGlmaWVyIE5hbWVRdWFsaWZpZXI9Imh0dHA6Ly9sb2NhbGhvc3Q6ODg4OC9vcGVuc3NvL2NkY3NlcnZsZXQiPkFRSUM1d00yTFk0U2ZjeUVQJTJGTjVsOUljQ3F5WXhtY01yUlBMVDY3azFEZUlDTmclM0QlNDBBQUpUU1FBQ01ERSUzRCUyMzwvc2FtbDpOYW1lSWRlbnRpZmllcj4KPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbj4KPHNhbWw6Q29uZmlybWF0aW9uTWV0aG9kPnVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMDpjbTpiZWFyZXI8L3NhbWw6Q29uZmlybWF0aW9uTWV0aG9kPgo8L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj4KPGxpYjpJRFBQcm92aWRlZE5hbWVJZGVudGlmaWVyICBOYW1lUXVhbGlmaWVyPSJodHRwOi8vbG9jYWxob3N0Ojg4ODgvb3BlbnNzby9jZGNzZXJ2bGV0IiA+QVFJQzV3TTJMWTRTZmN5RVAlMkZONWw5SWNDcXlZeG1jTXJSUExUNjdrMURlSUNOZyUzRCU0MEFBSlRTUUFDTURFJTNEJTIzPC9saWI6SURQUHJvdmlkZWROYW1lSWRlbnRpZmllcj4KPC9zYW1sOlN1YmplY3Q+PHNhbWw6U3ViamVjdExvY2FsaXR5ICBJUEFkZHJlc3M9IjEyNy4wLjAuMSIgRE5TQWRkcmVzcz0ibG9jYWxob3N0IiAvPjxsaWI6QXV0aG5Db250ZXh0PjxsaWI6QXV0aG5Db250ZXh0Q2xhc3NSZWY+aHR0cDovL3d3dy5wcm9qZWN0bGliZXJ0eS5vcmcvc2NoZW1hcy9hdXRoY3R4L2NsYXNzZXMvUGFzc3dvcmQ8L2xpYjpBdXRobkNvbnRleHRDbGFzc1JlZj48bGliOkF1dGhuQ29udGV4dFN0YXRlbWVudFJlZj5odHRwOi8vd3d3LnByb2plY3RsaWJlcnR5Lm9yZy9zY2hlbWFzL2F1dGhjdHgvY2xhc3Nlcy9QYXNzd29yZDwvbGliOkF1dGhuQ29udGV4dFN0YXRlbWVudFJlZj48L2xpYjpBdXRobkNvbnRleHQ+PC9zYW1sOkF1dGhlbnRpY2F0aW9uU3RhdGVtZW50Pjwvc2FtbDpBc3NlcnRpb24+CjxsaWI6UHJvdmlkZXJJRD5odHRwOi8vbG9jYWxob3N0Ojg4ODgvb3BlbnNzby9jZGNzZXJ2bGV0PC9saWI6UHJvdmlkZXJJRD48L2xpYjpBdXRoblJlc3BvbnNlPgo="; - - - public void testParsingOpenAMMessage() throws Exception - { - parseMessageAndTest(TEST_MESSAGE_OPENAM, 124, "2012-04-12T07:46:15Z", "2012-04-12T07:47:15Z", "AQIC5wM2LY4SfcwAN6hjijOCPO1u7UurEn9DvqFXKzwFsi0.*AAJTSQACMDE.*"); - } - - public void testParsingOpenSSOMessage() throws Exception - { - parseMessageAndTest(TEST_MESSAGE_OPENSSO, 47573, "2012-04-12T22:11:42Z", "2012-04-12T22:12:42Z", "AQIC5wM2LY4SfcyEP/N5l9IcCqyYxmcMrRPLT67k1DeICNg=@AAJTSQACMDE=#"); - } - - - private void parseMessageAndTest(String inputMessage, int expectedInResponseTo, String expectedNotBefore, String expectedNotOnOrAfter, String expectedToken) throws Exception - { - log.info("Test parsing message from CDCServlet"); - - CDMessageParser messageParser = new CDMessageParser(); - String message = messageParser.decodeMessage(inputMessage); - - log.info("Message from CDCServlet is:"); - log.info(message); - - CDMessageContext messageContext = messageParser.parseMessage(inputMessage); - - assertTrue(messageContext.getSuccess()); - assertTrue(messageContext.getInResponseTo() == expectedInResponseTo); - assertEquals(messageContext.getNotBefore(), expectedNotBefore); - assertEquals(messageContext.getNotOnOrAfter(), expectedNotOnOrAfter); - assertEquals(messageContext.getSsoToken(), expectedToken); - } -} diff --git a/auth-callback/pom.xml b/auth-callback/pom.xml deleted file mode 100644 index 7812b54f2..000000000 --- a/auth-callback/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - org.exoplatform.gatein.sso - sso-parent - ../pom.xml - 6.6.x-SNAPSHOT - - - 4.0.0 - sso-auth-callback - jar - GateIn SSO - Authentication Callback - A RESTful call back service used by SSO servers to perform authentication against the Gatein instance - - - - - - org.exoplatform.ws - exo.ws.rest.core - - - org.exoplatform.core - exo.core.component.security.core - - - - org.exoplatform.gatein.wci - wci-wci - - - javax.ws.rs - jsr311-api - - - - diff --git a/auth-callback/src/main/java/org/gatein/sso/authentication/callback/AuthenticationHandler.java b/auth-callback/src/main/java/org/gatein/sso/authentication/callback/AuthenticationHandler.java deleted file mode 100644 index 1ab2d6ca3..000000000 --- a/auth-callback/src/main/java/org/gatein/sso/authentication/callback/AuthenticationHandler.java +++ /dev/null @@ -1,190 +0,0 @@ -/* -* JBoss, a division of Red Hat -* Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated -* by the @authors tag. See the copyright.txt in the distribution for a -* full listing of individual contributors. -* -* This is free software; you can redistribute it and/or modify it -* under the terms of the GNU Lesser General Public License as -* published by the Free Software Foundation; either version 2.1 of -* the License, or (at your option) any later version. -* -* This software is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this software; if not, write to the Free -* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -* 02110-1301 USA, or see the FSF site: http://www.fsf.org. -*/ -package org.gatein.sso.authentication.callback; - -import javax.security.auth.login.LoginException; - -import javax.ws.rs.Consumes; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.exoplatform.container.ExoContainer; -import org.exoplatform.container.ExoContainerContext; -import org.exoplatform.container.RootContainer; - -import org.exoplatform.container.xml.InitParams; -import org.exoplatform.services.security.Authenticator; -import org.exoplatform.services.security.Credential; -import org.exoplatform.services.security.Identity; -import org.exoplatform.services.security.PasswordCredential; -import org.exoplatform.services.security.UsernameCredential; - -import org.exoplatform.services.rest.resource.ResourceContainer; -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; - -import java.util.Collection; - -/** - * This is a RESTful component that is invoked by central SSO servers like CAS server, to invoke - * Gatein authentication related queries during their own "Authentication process" - * - * - * @author Sohil Shah - */ -@Path("/sso/authcallback") -public class AuthenticationHandler implements ResourceContainer -{ - private static final Log log = ExoLogger.getLogger(AuthenticationHandler.class); - - // If false, then rest callbacks are disabled - private final boolean callbackEnabled; - - public AuthenticationHandler(InitParams params) - { - String callbackEnabledParam = params.getValueParam("ssoCallbackEnabled").getValue(); - this.callbackEnabled = Boolean.parseBoolean(callbackEnabledParam); - } - - @GET - @Path("/auth/{1}/{2}") - @Produces( - {MediaType.TEXT_PLAIN}) - public String authenticate(@PathParam("1") String username, @PathParam("2") String password) - { - if (!callbackEnabled) - { - log.warn("SSO callbacks are disabled!"); - return "Error! SSO callbacks are disabled!"; - } - - try - { - log.debug("Handle SSO callback authentication. Username: "+username); - - Authenticator authenticator = (Authenticator) getContainer().getComponentInstanceOfType(Authenticator.class); - - Credential[] credentials = new Credential[] { new UsernameCredential(username), - new PasswordCredential(password) }; - - try - { - authenticator.validateUser(credentials); - if (log.isTraceEnabled()) - { - log.trace("Login successful for user " + username); - } - return ""+Boolean.TRUE; - } - catch(LoginException le) - { - log.debug("Login failed for user " + username); - return ""+Boolean.FALSE; - } - } - catch(Exception e) - { - log.error(this, e); - throw new RuntimeException(e); - } - } - - /** - * Obtain list of JAAS roles for some user. For example, for user root it can return String like: "users,administrators,organization" - * It's usually not needed because SSO authorization is done on portal side, but may be useful for some SSO implementations to use - * this callback and ask portal for roles. - * - * @param username - * @return {@link String} with roles in format like: "users,administrators,organization" - */ - @GET - @Path("/roles/{1}") - @Produces({MediaType.TEXT_PLAIN}) - public String getJAASRoles(@PathParam("1") String username) - { - if (!callbackEnabled) - { - log.warn("SSO callbacks are disabled!"); - return "Error! SSO callbacks are disabled!"; - } - - try - { - log.debug("Going to obtain roles for user: " + username); - - Authenticator authenticator = (Authenticator) getContainer().getComponentInstanceOfType(Authenticator.class); - Identity identity = authenticator.createIdentity(username); - Collection roles = identity.getRoles(); - - StringBuilder result = null; - for (String role : roles) - { - if (result == null) - { - result = new StringBuilder(role); - } - else - { - result.append(",").append(role); - } - } - - if (result != null) - { - return result.toString(); - } - else - { - return ""; - } - } - catch(Exception e) - { - log.error(this, e); - throw new RuntimeException(e); - } - } - - @POST - @Path("/postauth/") - @Consumes({MediaType.APPLICATION_FORM_URLENCODED}) - @Produces({MediaType.TEXT_PLAIN}) - public String authenticatePost(@FormParam("username") String username, @FormParam("password") String password) - { - return authenticate(username, password); - } - - private ExoContainer getContainer() throws Exception - { - ExoContainer container = ExoContainerContext.getCurrentContainer(); - if (container instanceof RootContainer) - { - container = RootContainer.getInstance().getPortalContainer("portal"); - } - return container; - } -} diff --git a/auth-callback/src/main/resources/conf/portal/configuration.xml b/auth-callback/src/main/resources/conf/portal/configuration.xml deleted file mode 100644 index 43b02b9fc..000000000 --- a/auth-callback/src/main/resources/conf/portal/configuration.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - org.gatein.sso.authentication.callback.AuthenticationHandler - org.gatein.sso.authentication.callback.AuthenticationHandler - - - ssoCallbackEnabled - ${gatein.sso.callback.enabled:false} - - - - - \ No newline at end of file diff --git a/common-plugin/pom.xml b/common-plugin/pom.xml deleted file mode 100644 index a022e389f..000000000 --- a/common-plugin/pom.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - sso-parent - org.exoplatform.gatein.sso - ../pom.xml - 6.6.x-SNAPSHOT - - - 4.0.0 - sso-common-plugin - jar - GateIn SSO - Common SSO authentication plugin - http://maven.apache.org - - - - org.exoplatform.kernel - exo.kernel.commons - provided - - - diff --git a/common-plugin/src/main/java/org/gatein/sso/plugin/RestCallbackCaller.java b/common-plugin/src/main/java/org/gatein/sso/plugin/RestCallbackCaller.java deleted file mode 100644 index 4f78204d2..000000000 --- a/common-plugin/src/main/java/org/gatein/sso/plugin/RestCallbackCaller.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.gatein.sso.plugin; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLEncoder; - -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; - -/** - * Object, which runs on SSO server side (CAS, OpenAM) and is used to help with connection to GateIn via REST - * - * @author Marek Posolda - */ -public class RestCallbackCaller -{ - private static final Log log = ExoLogger.getLogger(RestCallbackCaller.class); - - private static final String ENCODING_CHARSET = "UTF-8"; - - // If true, we use "https". If false, we use "http" - private final String protocol; - - // Host (Something like "localhost") - private final String host; - - // Port (Something like "8080") - private final String port; - - // Something like "portal" - private final String pathContext; - - // If true we use "POST" method. If false we use "GET" method - private final boolean isPostHttpMethod; - - public RestCallbackCaller(String protocol, - String host, - String port, - String pathContext, - String httpMethod) - { - if (host == null || port == null || pathContext == null) - { - throw new IllegalArgumentException("Host, port and context are mandatory, but some of them is not available in configuration. host=" - + host + ", port=" + port + ", context=" + pathContext); - } - - this.host = host; - this.port = port; - this.pathContext = pathContext; - - this.isPostHttpMethod = isPostHttpMethod(httpMethod); - - // Default to http if not provided - if (protocol == null) - { - protocol = "http"; - } - this.protocol = protocol; - - - log.info("RestCallbackCaller initialized: " + this); - } - - /** - * @param callbackURL expected in format like "http://www.sp.com:8080/portal" - * @param httpMethod - */ - public RestCallbackCaller(String callbackURL, String httpMethod) - { - try - { - URL url = new URL(callbackURL); - this.protocol = url.getProtocol(); - this.host = url.getHost(); - - int port = url.getPort(); - if (port == -1) { - port = 80; - } - this.port = String.valueOf(port); - - String path = url.getPath(); - if (path.startsWith("/")) { - path = path.substring(1); - } - if (path.endsWith("/")) { - path = path.substring(0, path.length() - 1); - } - this.pathContext = path; - - this.isPostHttpMethod = isPostHttpMethod(httpMethod); - } - catch (MalformedURLException mfe) - { - throw new IllegalArgumentException("Bad URL format: " + callbackURL, mfe); - } - - log.debug("RestCallbackCaller initialized: " + this); - } - - private boolean isPostHttpMethod(String httpMethod) - { - boolean isPostHttpMethod; - - // Default to GET method if not provided - if (httpMethod == null || "GET".equalsIgnoreCase(httpMethod)) - { - isPostHttpMethod = false; - } - else if ("POST".equalsIgnoreCase(httpMethod)) - { - isPostHttpMethod = true; - } - else - { - throw new IllegalArgumentException("Illegal httpMethod: " + httpMethod + ". Only GET or POST are allowed"); - } - return isPostHttpMethod; - } - - public boolean executeRemoteCall(String username, String password) throws Exception - { - try - { - HttpResponseContext httpResponse = sendPortalCallbackRequest(username, password); - - int status = httpResponse.getResponseCode(); - String response = httpResponse.getResponse(); - - switch (status) - { - case 200: - if (response.equals(Boolean.TRUE.toString())) - { - if (log.isTraceEnabled()) - { - log.trace("User " + username + " authenticated successfully via Rest callback!"); - } - return true; - } - break; - } - - log.debug("Authentication failed for user " + username + ". HTTP status: " + status + ", HTTP response: " + response); - return false; - } - catch (Exception e) - { - log.warn("Can't authenticate because of error: " + e.getMessage()); - e.printStackTrace(); - throw e; - } - } - - private HttpResponseContext sendPortalCallbackRequest(String username, String password) throws IOException - { - String requestURL = null; - String queryString = null; - - if (isPostHttpMethod) - { - StringBuilder builder = new StringBuilder(this.protocol).append("://"); - builder.append(this.host).append(":").append(this.port); - - // Don't append portal context for now. We need the request to be served by rest.war application on portal side - // because here we can't call request.getParameter("something") before request is processed by RestServlet - // builder.append("/").append(this.pathContext) - builder.append("/rest/sso/authcallback/postauth/"); - - requestURL = builder.toString(); - - queryString = new StringBuilder("username=") - .append(URLEncoder.encode(username, ENCODING_CHARSET)) - .append("&password=") - .append(URLEncoder.encode(password, ENCODING_CHARSET)) - .toString(); - } - else - { - StringBuilder builder = new StringBuilder(this.protocol).append("://"); - builder.append(this.host).append(":").append(this.port).append("/") - .append(this.pathContext).append("/rest/sso/authcallback/auth/") - .append(URLEncoder.encode(username, ENCODING_CHARSET)) - .append("/") - .append(URLEncoder.encode(password, ENCODING_CHARSET)); - requestURL = builder.toString(); - } - - if (log.isTraceEnabled()) - { - log.trace("Rest callback URL: " + requestURL + ", query string: " + queryString + ", isPostMethod: " + isPostHttpMethod); - } - - return sendHttpRequest(requestURL, queryString); - } - - private HttpResponseContext sendHttpRequest(String url, String urlParameters) throws IOException - { - Reader reader = null; - DataOutputStream wr = null; - StringBuilder result = new StringBuilder(); - - try - { - HttpURLConnection connection; - - if (isPostHttpMethod) - { - URL tempURL = new URL(url); - connection = (HttpURLConnection)tempURL.openConnection(); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - connection.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters.getBytes().length)); - } - else - { - if (urlParameters != null) - { - url = url + "?" + urlParameters; - } - - URL tempURL = new URL(url); - connection = (HttpURLConnection)tempURL.openConnection(); - } - - connection.setUseCaches (false); - connection.setDoInput(true); - - if (isPostHttpMethod) - { - connection.setDoOutput(true); - - //Send request - wr = new DataOutputStream(connection.getOutputStream ()); - wr.writeBytes(urlParameters); - wr.flush(); - } - - int statusCode = connection.getResponseCode(); - - try - { - reader = new InputStreamReader(connection.getInputStream()); - } - catch (IOException ioe) - { - reader = new InputStreamReader(connection.getErrorStream()); - } - - char[] buffer = new char[50]; - int nrOfChars; - while ((nrOfChars = reader.read(buffer)) != -1) - { - result.append(buffer, 0, nrOfChars); - } - - String response = result.toString(); - return new HttpResponseContext(statusCode, response); - } - finally - { - if (reader != null) - { - reader.close(); - } - if (wr != null) { - wr.close(); - } - } - } - - - @Override - public String toString() - { - StringBuilder builder = new StringBuilder("RestCallbackCaller [ protocol=").append(protocol) - .append(", host=").append(host) - .append(", port=").append(port) - .append(", pathContext=").append(pathContext) - .append(", isPostMethod=").append(isPostHttpMethod) - .append(" ]"); - - return builder.toString(); - } -} diff --git a/integration/pom.xml b/integration/pom.xml deleted file mode 100644 index 386e0f84f..000000000 --- a/integration/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - sso-parent - org.exoplatform.gatein.sso - ../pom.xml - 6.6.x-SNAPSHOT - - 4.0.0 - - sso-integration - jar - - GateIn SSO - Portal integration - http://maven.apache.org - - - 0.01 - - - - - org.exoplatform.gatein.sso - sso-agent - provided - - - org.apache.tomcat - tomcat-catalina - provided - - - junit - junit - test - - - diff --git a/integration/src/main/resources/conf/portal/configuration.xml b/integration/src/main/resources/conf/portal/configuration.xml deleted file mode 100644 index 7c8caa209..000000000 --- a/integration/src/main/resources/conf/portal/configuration.xml +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - diff --git a/lib/amserver.jar b/lib/amserver.jar deleted file mode 100644 index 9b26ada95..000000000 Binary files a/lib/amserver.jar and /dev/null differ diff --git a/lib/cddl.txt b/lib/cddl.txt deleted file mode 100644 index 8ee560c09..000000000 --- a/lib/cddl.txt +++ /dev/null @@ -1,340 +0,0 @@ -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 - -1. Definitions. - -1.1. Contributor means each individual or entity that creates or -contributes to the creation of Modifications. - -1.2. Contributor Version means the combination of the Original -Software, prior Modifications used by a Contributor (if any), -and the Modifications made by that particular Contributor. - -1.3. Covered Software means (a) the Original Software, or (b) -Modifications, or (c) the combination of files containing -Original Software with files containing Modifications, in each -case including portions thereof. - -1.4. Executable means the Covered Software in any form other -than Source Code. - -1.5. Initial Developer means the individual or entity that first -makes Original Software available under this License. - -1.6. Larger Workmeans a work which combines Covered Software or -portions thereof with code not governed by the terms of this -License. - -1.7. License means this document. - -1.8. Licensable means having the right to grant, to the maximum -extent possible, whether at the time of the initial grant or -subsequently acquired, any and all of the rights conveyed herein. - -1.9. Modifications means the Source Code and Executable form of -any of the following: A. Any file that results from an addition -to, deletion from or modification of the contents of a file -containing Original Software or previous Modifications; B. Any -new file that contains any part of the Original Software or -previous Modification; or C. Any new file that is contributed or -otherwise made available under the terms of this License. - -1.10. Original Software means the Source Code and Executable -form of computer software code that is originally released under -this License. - -1.11. Patent Claims means any patent claim(s), now owned or -hereafter acquired, including without limitation, method, -process, and apparatus claims, in any patent Licensable by -grantor. - -1.12. Source Code means (a) the common form of computer software -code in which modifications are made and (b) associated -documentation included in or with such code. - -1.13. You (or Your) means an individual or a legal entity -exercising rights under, and complying with all of the terms of, -this License. For legal entities, You includes any entity which -controls, is controlled by, or is under common control with You. -For purposes of this definition, control means (a) the power, -direct or indirect, to cause the direction or management of such -entity, whether by contract or otherwise, or (b) ownership of -more than fifty percent (50%) of the outstanding shares or -beneficial ownership of such entity. - -2. License Grants. - -2.1. The Initial Developer Grant. Conditioned upon Your -compliance with Section 3.1 below and subject to third party -intellectual property claims, the Initial Developer hereby -grants You a world-wide, royalty-free, non-exclusive license: - -(a) under intellectual property rights (other than patent or -trademark) Licensable by Initial Developer, to use, reproduce, -modify, display, perform, sublicense and distribute the Original -Software (or portions thereof), with or without Modifications, -and/or as part of a Larger Work; and - -(b) under Patent Claims infringed by the making, using or -selling of Original Software, to make, have made, use, practice, -sell, and offer for sale, and/or otherwise dispose of the -Original Software (or portions thereof); - -(c) The licenses granted in Sections 2.1(a) and (b) are -effective on the date Initial Developer first distributes or -otherwise makes the Original Software available to a third party -under the terms of this License; - -(d) Notwithstanding Section 2.1(b) above, no patent license is -granted: (1) for code that You delete from the Original -Software, or (2) for infringements caused by: (i) the -modification of the Original Software, or (ii) the combination -of the Original Software with other software or devices. - -2.2. Contributor Grant. Conditioned upon Your compliance with -Section 3.1 below and subject to third party intellectual -property claims, each Contributor hereby grants You a -world-wide, royalty-free, non-exclusive license: - -(a) under intellectual property rights (other than patent or -trademark) Licensable by Contributor to use, reproduce, modify, -display, perform, sublicense and distribute the Modifications -created by such Contributor (or portions thereof), either on an -unmodified basis, with other Modifications, as Covered Software -and/or as part of a Larger Work; and - -(b) under Patent Claims infringed by the making, using, or -selling of Modifications made by that Contributor either alone -and/or in combination with its Contributor Version (or portions -of such combination), to make, use, sell, offer for sale, have -made, and/or otherwise dispose of: (1) Modifications made by -that Contributor (or portions thereof); and (2) the combination -of Modifications made by that Contributor with its Contributor -Version (or portions of such combination). - -(c) The licenses granted in Sections 2.2(a) and 2.2(b) -areeffective on the date Contributor first distributes or -otherwise makes the Modifications available to a third party. - -(d) Notwithstanding Section 2.2(b) above, no patent license is -granted: (1) for any code that Contributor has deleted from the -Contributor Version; (2) for infringements caused by: (i) third -party modifications of Contributor Version, or (ii) the -combination of Modifications made by that Contributor with other -software (except as part of the Contributor Version) or other -devices; or (3) under Patent Claims infringed by Covered -Software in the absence of Modifications made by that -Contributor. - -3. Distribution Obligations. - -3.1. Availability of Source Code. Any Covered Software that You -distribute or otherwise make available in Executable form must -also be made available in Source Code form and that Source Code -form must be distributed only under the terms of this License. -You must include a copy of this License with every copy of the -Source Code form of the Covered Software You distribute or -otherwise make available. You must inform recipients of any such -Covered Software in Executable form as to how they can obtain -such Covered Software in Source Code form in a reasonable manner -on or through a medium customarily used for software exchange. - -3.2. Modifications. The Modifications that You create or to -which You contribute are governed by the terms of this License. -You represent that You believe Your Modifications are Your -original creation(s) and/or You have sufficient rights to grant -the rights conveyed by this License. - -3.3. Required Notices. You must include a notice in each of Your -Modifications that identifies You as the Contributor of the -Modification. You may not remove or alter any copyright, patent -or trademark notices contained within the Covered Software, or -any notices of licensing or any descriptive text giving -attribution to any Contributor or the Initial Developer. - -3.4. Application of Additional Terms. You may not offer or -impose any terms on any Covered Software in Source Code form -that alters or restricts the applicable version of this License -or the recipients rights hereunder. You may choose to offer, and -to charge a fee for, warranty, support, indemnity or liability -obligations to one or more recipients of Covered -Software. However, you may do so only on Your own behalf, and -not on behalf of the Initial Developer or any Contributor. You -must make it absolutely clear that any such warranty, support, -indemnity or liability obligation is offered by You alone, and -You hereby agree to indemnify the Initial Developer and every -Contributor for any liability incurred by the Initial Developer -or such Contributor as a result of warranty, support, indemnity -or liability terms You offer. - -3.5. Distribution of Executable Versions. You may distribute the -Executable form of the Covered Software under the terms of this -License or under the terms of a license of Your choice, which -may contain terms different from this License, provided that You -are in compliance with the terms of this License and that the -license for the Executable form does not attempt to limit or -alter the recipients rights in the Source Code form from the -rights set forth in this License. If You distribute the Covered -Software in Executable form under a different license, You must -make it absolutely clear that any terms which differ from this -License are offered by You alone, not by the Initial Developer -or Contributor. You hereby agree to indemnify the Initial -Developer and every Contributor for any liability incurred by -the Initial Developer or such Contributor as a result of any -such terms You offer. - -3.6. Larger Works. You may create a Larger Work by combining -Covered Software with other code not governed by the terms of -this License and distribute the Larger Work as a single product. -In such a case, You must make sure the requirements of this -License are fulfilled for the Covered Software. - -4. Versions of the License. - -4.1. New Versions. Sun Microsystems, Inc. is the initial license -steward and may publish revised and/or new versions of this -License from time to time. Each version will be given a -distinguishing version number. Except as provided in Section -4.3, no one other than the license steward has the right to -modify this License. - -4.2. Effect of New Versions. You may always continue to use, -distribute or otherwise make the Covered Software available -under the terms of the version of the License under which You -originally received the Covered Software. If the Initial -Developer includes a notice in the Original Software prohibiting -it from being distributed or otherwise made available under any -subsequent version of the License, You must distribute and make -the Covered Software available under the terms of the version of -the License under which You originally received the Covered -Software. Otherwise, You may also choose to use, distribute or -otherwise make the Covered Software available under the terms of -any subsequent version of the License published by the license -steward. - -4.3. Modified Versions. When You are an Initial Developer and -You want to create a new license for Your Original Software, You -may create and use a modified version of this License if You: -(a) rename the license and remove any references to the name of -the license steward (except to note that the license differs -from this License); and (b) otherwise make it clear that the -license contains terms which differ from this License. - -5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE IS PROVIDED UNDER -THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, -WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, -MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. -THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED -SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE -DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY -OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, -REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN -ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE -IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -6. TERMINATION. - -6.1. This License and the rights granted hereunder will -terminate automatically if You fail to comply with terms herein -and fail to cure such breach within 30 days of becoming aware of -the breach. Provisions which, by their nature, must remain in -effect beyond the termination of this License shall survive. - -6.2. If You assert a patent infringement claim (excluding -declaratory judgment actions) against Initial Developer or a -Contributor (the Initial Developer or Contributor against whom -You assert such claim is referred to as Participant) alleging -that the Participant Software (meaning the Contributor Version -where the Participant is a Contributor or the Original Software -where the Participant is the Initial Developer) directly or -indirectly infringes any patent, then any and all rights granted -directly or indirectly to You by such Participant, the Initial -Developer (if the Initial Developer is not the Participant) and -all Contributors under Sections 2.1 and/or 2.2 of this License -shall, upon 60 days notice from Participant terminate -prospectively and automatically at the expiration of such 60 day -notice period, unless if within such 60 day period You withdraw -Your claim with respect to the Participant Software against such -Participant either unilaterally or pursuant to a written -agreement with Participant. - -6.3. In the event of termination under Sections 6.1 or 6.2 -above, all end user licenses that have been validly granted by -You or any distributor hereunder prior to termination (excluding -licenses granted to You by any distributor) shall survive -termination. - -7. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO -LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR -OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER -CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY -SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY -INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY -CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST -PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR -MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, -EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY -OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO -LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH -PARTYS NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH -LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR -LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS -EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - -8. U.S. GOVERNMENT END USERS. The Covered Software is a -commercial item, as that term is defined in 48 C.F.R. 2.101 -(Oct. 1995), consisting of commercial computer software (as that -term is defined at 48 C.F.R. 252.227-7014(a)(1)) and commercial -computer software documentation as such terms are used in 48 -C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and -48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all -U.S. Government End Users acquire Covered Software with only -those rights set forth herein. This U.S. Government Rights -clause is in lieu of, and supersedes, any other FAR, DFAR, or -other clause or provision that addresses Government rights in -computer software under this License. - -9. MISCELLANEOUS. This License represents the complete agreement -concerning subject matter hereof. If any provision of this -License is held to be unenforceable, such provision shall be -reformed only to the extent necessary to make it enforceable. -This License shall be governed by the law of the jurisdiction -specified in a notice contained within the Original Software -(except to the extent applicable law, if any, provides -otherwise), excluding such jurisdictions conflict-of-law -provisions. Any litigation relating to this License shall be -subject to the jurisdiction of the courts located in the -jurisdiction and venue specified in a notice contained within -the Original Software, with the losing party responsible for -costs, including, without limitation, court costs and reasonable -attorneys fees and expenses. The application of the United -Nations Convention on Contracts for the International Sale of -Goods is expressly excluded. Any law or regulation which -provides that the language of a contract shall be construed -against the drafter shall not apply to this License. You agree -that You alone are responsible for compliance with the United -States export administration regulations (and the export control -laws and regulation of any other countries) when You use, -distribute or otherwise make available any Covered Software. - -10. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and -the Contributors, each party is responsible for claims and -damages arising, directly or indirectly, out of its utilization -of rights under this License and You agree to work with Initial -Developer and Contributors to distribute such responsibility on -an equitable basis. Nothing herein is intended or shall be -deemed to constitute any admission of liability. - ----------------------------------------------------------------- - -NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND -DISTRIBUTION LICENSE (CDDL): This code is released under the -CDDL and shall be governed by the laws of the State of -California (excluding conflict-of-law provisions). Any -litigation relating to this License shall be subject to the -jurisdiction of the Federal Courts of the Northern District of -California and the state courts of the State of California, with -venue lying in Santa Clara County, California. - ----------------------------------------------------------------- - diff --git a/lib/opensso.jar b/lib/opensso.jar deleted file mode 100644 index 332303e15..000000000 Binary files a/lib/opensso.jar and /dev/null differ diff --git a/opensso/gatein-opensso-plugin/pom.xml b/opensso/gatein-opensso-plugin/pom.xml deleted file mode 100644 index c74dcde9d..000000000 --- a/opensso/gatein-opensso-plugin/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - org.exoplatform.gatein.sso - sso-opensso-parent - ../pom.xml - 6.6.x-SNAPSHOT - - - 4.0.0 - sso-opensso-plugin - jar - GateIn SSO - OpenSSO Plugin - - - - - - - org.exoplatform.gatein.sso - sso-common-plugin - - - org.exoplatform.kernel - exo.kernel.commons - provided - - - opensso - opensso - system - ${basedir}/../../lib/opensso.jar - 8.0 - - - opensso - amserver - system - ${basedir}/../../lib/amserver.jar - 8.0 - - - - - - - diff --git a/opensso/gatein-opensso-plugin/src/main/java/org/gatein/sso/opensso/plugin/AuthenticationPlugin.java b/opensso/gatein-opensso-plugin/src/main/java/org/gatein/sso/opensso/plugin/AuthenticationPlugin.java deleted file mode 100644 index 41671c905..000000000 --- a/opensso/gatein-opensso-plugin/src/main/java/org/gatein/sso/opensso/plugin/AuthenticationPlugin.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.gatein.sso.opensso.plugin; - -import java.io.IOException; -import java.io.InputStream; -import java.security.Principal; -import java.util.Map; -import java.util.Properties; - -import javax.security.auth.Subject; -import javax.security.auth.callback.*; - -import org.gatein.sso.plugin.RestCallbackCaller; - -import com.sun.identity.authentication.spi.AMLoginModule; -import com.sun.identity.authentication.spi.AuthLoginException; -import com.sun.identity.authentication.util.ISAuthConstants; - -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; - -/** - * @author Sohil Shah - */ -public class AuthenticationPlugin extends AMLoginModule { - - private static final Log log = ExoLogger.getLogger(RestCallbackCaller.class); - - private RestCallbackCaller restCallbackCaller; - - private String username; - - public AuthenticationPlugin() { - } - - public void init(Subject subject, Map sharedState, Map options) { - InputStream is = null; - try { - // Load the GateIn properties - Properties properties = new Properties(); - is = Thread.currentThread().getContextClassLoader().getResourceAsStream("gatein.properties"); - properties.load(is); - - String gateInHost = properties.getProperty("host"); - String gateInPort = properties.getProperty("port"); - String gateInContext = properties.getProperty("context"); - String gateInProtocol = properties.getProperty("protocol"); - String gateInHttpMethod = properties.getProperty("httpMethod"); - - log.debug("GateIn Host: " + gateInHost + ", GateIn Port: " + gateInPort + ", GateIn context: " + gateInContext - + ", Protocol=" + gateInProtocol + ", http method=" + gateInHttpMethod); - this.restCallbackCaller = new RestCallbackCaller(gateInProtocol, gateInHost, gateInPort, gateInContext, gateInHttpMethod); - } catch (IOException ioe) { - log.error("Error during initialization of login module", ioe); - } finally { - if (is != null) { - try { - is.close(); - } catch (Exception e) { - } - } - } - } - - public int process(Callback[] callbacks, int state) throws AuthLoginException { - try { - String password = null; - for (int i = 0; i < callbacks.length; i++) { - Callback callback = callbacks[i]; - - if (callback instanceof NameCallback) { - this.username = ((NameCallback) callback).getName(); - } else if (callback instanceof PasswordCallback) { - password = new String(((PasswordCallback) callback).getPassword()); - } - } - - boolean success = restCallbackCaller.executeRemoteCall(this.username, password); - if (!success) { - throw new AuthLoginException("GateIn Login Callback Failed!!"); - } - - return ISAuthConstants.LOGIN_SUCCEED; - } catch (Throwable e) { - throw new AuthLoginException(e); - } - } - - public Principal getPrincipal() { - return new GateInPrincipal(this.username); - } -} diff --git a/opensso/gatein-opensso-plugin/src/main/java/org/gatein/sso/opensso/plugin/GateInPrincipal.java b/opensso/gatein-opensso-plugin/src/main/java/org/gatein/sso/opensso/plugin/GateInPrincipal.java deleted file mode 100644 index d17e066da..000000000 --- a/opensso/gatein-opensso-plugin/src/main/java/org/gatein/sso/opensso/plugin/GateInPrincipal.java +++ /dev/null @@ -1,42 +0,0 @@ -/* -* JBoss, a division of Red Hat -* Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated -* by the @authors tag. See the copyright.txt in the distribution for a -* full listing of individual contributors. -* -* This is free software; you can redistribute it and/or modify it -* under the terms of the GNU Lesser General Public License as -* published by the Free Software Foundation; either version 2.1 of -* the License, or (at your option) any later version. -* -* This software is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this software; if not, write to the Free -* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -* 02110-1301 USA, or see the FSF site: http://www.fsf.org. -*/ -package org.gatein.sso.opensso.plugin; - -import java.security.Principal; - -/** - * @author Sohil Shah - */ -public class GateInPrincipal implements Principal -{ - private String name; - - public GateInPrincipal(String name) - { - this.name = name; - } - - public String getName() - { - return this.name; - } -} diff --git a/opensso/gatein-opensso-portal/pom.xml b/opensso/gatein-opensso-portal/pom.xml deleted file mode 100644 index 60a28a7b8..000000000 --- a/opensso/gatein-opensso-portal/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - org.exoplatform.gatein.sso - sso-opensso-parent - 6.6.x-SNAPSHOT - ../pom.xml - - - 4.0.0 - sso-opensso-pkg - pom - GateIn SSO - OpenSSO - Portal packaging - - - - org.exoplatform.gatein.sso - sso-common-plugin - - - org.exoplatform.gatein.sso - sso-opensso-plugin - - - - - - - maven-assembly-plugin - - - src/main/assembly/src.xml - - - - - make-assembly - package - - single - - - - - - - - - - diff --git a/opensso/gatein-opensso-portal/src/main/assembly/src.xml b/opensso/gatein-opensso-portal/src/main/assembly/src.xml deleted file mode 100644 index 085e92bb3..000000000 --- a/opensso/gatein-opensso-portal/src/main/assembly/src.xml +++ /dev/null @@ -1,28 +0,0 @@ - - sso-opensso - - dir - - false - - - - src/main/resources - - - - - - - plugin/WEB-INF/lib - false - false - - org.exoplatform.gatein.sso:sso-common-plugin - org.exoplatform.gatein.sso:sso-opensso-plugin - - - - - diff --git a/opensso/gatein-opensso-portal/src/main/resources/plugin/WEB-INF/classes/gatein.properties b/opensso/gatein-opensso-portal/src/main/resources/plugin/WEB-INF/classes/gatein.properties deleted file mode 100644 index cbba68877..000000000 --- a/opensso/gatein-opensso-portal/src/main/resources/plugin/WEB-INF/classes/gatein.properties +++ /dev/null @@ -1,5 +0,0 @@ -host=localhost -port=8080 -context=portal -protocol=http -httpMethod=POST \ No newline at end of file diff --git a/opensso/gatein-opensso-portal/src/main/resources/plugin/config/auth/default/AuthenticationPlugin.xml b/opensso/gatein-opensso-portal/src/main/resources/plugin/config/auth/default/AuthenticationPlugin.xml deleted file mode 100644 index a19428658..000000000 --- a/opensso/gatein-opensso-portal/src/main/resources/plugin/config/auth/default/AuthenticationPlugin.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - Username - - - - - Password - - - - diff --git a/opensso/pom.xml b/opensso/pom.xml deleted file mode 100644 index 79286a61b..000000000 --- a/opensso/pom.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - 4.0.0 - org.exoplatform.gatein.sso - sso-opensso-parent - pom - - - org.exoplatform.gatein.sso - sso-parent - 6.6.x-SNAPSHOT - ../pom.xml - - - - GateIn SSO - OpenSSO - - - gatein-opensso-plugin - gatein-opensso-portal - - - diff --git a/packaging/pom.xml b/packaging/pom.xml deleted file mode 100644 index e0399f6da..000000000 --- a/packaging/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - org.exoplatform.gatein.sso - sso-parent - 6.6.x-SNAPSHOT - ../pom.xml - - - 4.0.0 - sso-packaging - pom - GateIn SSO - Packaging - - - - - maven-assembly-plugin - - false - - src/main/assembly/src.xml - - - - - make-assembly - package - - single - - - - - - - - diff --git a/packaging/src/main/assembly/src.xml b/packaging/src/main/assembly/src.xml deleted file mode 100644 index 65b06285b..000000000 --- a/packaging/src/main/assembly/src.xml +++ /dev/null @@ -1,25 +0,0 @@ - - gatein-sso - false - - - zip - - - - - ../opensso/gatein-opensso-portal/target/sso-opensso-pkg-${version}-sso-opensso/ - gatein-sso-${version}/opensso - - - ../saml/gatein-saml-portal/target/sso-saml-pkg-${version}-sso-saml/ - gatein-sso-${version}/saml - - - src/main/resources/ - gatein-sso-${version} - - - - diff --git a/packaging/src/main/resources/README b/packaging/src/main/resources/README deleted file mode 100644 index 580c71389..000000000 --- a/packaging/src/main/resources/README +++ /dev/null @@ -1,14 +0,0 @@ -GateIn - SSO Integration - -This package provides the necessary files for integration of various SSO frameworks -with GateIn portal authentication mechanism - - - OpenAM (OpenSSO) - - JOSSO - - CAS - - CAS 4 - - SPNEGO - - SAML - -Please refer to the GateIn Portal documentation for usage of the embedded files. - diff --git a/pom.xml b/pom.xml index 7722ac447..8cd7cebe6 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,6 @@ maven-parent-pom org.exoplatform 26 - org.exoplatform.gatein.sso @@ -31,19 +30,12 @@ https://github.com/meeds-io/gatein-sso HEAD - + - agent - auth-callback - common-plugin - opensso - spnego - spnegosso - saml - packaging - integration + sso-agent + sso-saml-plugin - + 6.6.x-SNAPSHOT @@ -61,38 +53,13 @@ pom import - - - - org.exoplatform.gatein.sso - sso-auth-callback - ${project.version} - + + org.exoplatform.gatein.sso sso-agent ${project.version} - - org.exoplatform.gatein.sso - sso-integration - ${project.version} - - - org.exoplatform.gatein.sso - sso-common-plugin - ${project.version} - - - org.exoplatform.gatein.sso - sso-opensso-plugin - ${project.version} - - - org.exoplatform.gatein.sso - spnego - ${project.version} - org.exoplatform.gatein.sso sso-saml-plugin @@ -100,6 +67,19 @@ + + + ${project.artifactId} + + + + org.apache.maven.plugins + maven-patch-plugin + 1.2 + + + + diff --git a/saml/gatein-saml-plugin/pom.xml b/saml/gatein-saml-plugin/pom.xml deleted file mode 100644 index 5957bff42..000000000 --- a/saml/gatein-saml-plugin/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - sso-saml-parent - org.exoplatform.gatein.sso - 6.6.x-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.exoplatform.gatein.sso - sso-saml-plugin - jar - - GateIn SSO - SAML Identity provider plugin - - - 0.07 - - - - - org.jboss.logging - jboss-logging - provided - - - org.apache.tomcat - tomcat-catalina - provided - - - org.apache.httpcomponents - httpclient - - - org.picketlink.distribution - picketlink-wildfly8 - provided - - - org.picketlink - picketlink-common - - - org.picketlink - picketlink-config - - - javax.servlet - javax.servlet-api - - - org.exoplatform.gatein.sso - sso-common-plugin - - - - org.exoplatform.gatein.wci - wci-wci - - - - org.exoplatform.gatein.sso - sso-integration - - - org.exoplatform.gatein.sso - sso-agent - - - org.exoplatform.core - exo.core.component.organization.api - - - org.picketlink - picketlink-federation - - - org.mockito - mockito-core - test - - - junit - junit - test - - - - diff --git a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/filter/PortalIDPWebBrowserSSOFilter.java b/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/filter/PortalIDPWebBrowserSSOFilter.java deleted file mode 100644 index 7848ae465..000000000 --- a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/filter/PortalIDPWebBrowserSSOFilter.java +++ /dev/null @@ -1,214 +0,0 @@ -package org.gatein.sso.saml.plugin.filter; - -import java.io.IOException; -import java.net.URLEncoder; -import java.security.Principal; - -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.apache.commons.lang.StringUtils; -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.gatein.sso.agent.filter.api.SSOInterceptor; -import org.gatein.sso.agent.filter.api.SSOInterceptorInitializationContext; -import org.picketlink.common.constants.GeneralConstants; -import org.picketlink.identity.federation.web.filters.IDPFilter; - -import org.exoplatform.container.ExoContainer; -import org.exoplatform.container.ExoContainerContext; -import org.exoplatform.container.PortalContainer; -import org.exoplatform.container.RootContainer; -import org.exoplatform.container.util.ContainerUtil; -import org.exoplatform.container.xml.InitParams; - -public class PortalIDPWebBrowserSSOFilter extends IDPFilter implements SSOInterceptor { - - public static final String ORIGINAL_HTTP_SERVLET_REQUEST_PARAM = "OriginalHttpServletRequest"; - - private static final Log log = - ExoLogger.getLogger(PortalIDPWebBrowserSSOFilter.class); - - /** - * The filter configuration - */ - protected FilterConfig config; - - /** - * The Servlet context name - */ - protected String servletContextName; - - /** - * Indicates if we need a portal environment. - */ - private volatile Boolean requirePortalEnvironment; - - private SSOInterceptorInitializationContext interceptorContext; - - /** - * {@inheritDoc} - */ - public final void init(FilterConfig config) throws ServletException { - this.config = getFilterConfig(config); - this.servletContextName = ContainerUtil.getServletContextName(config.getServletContext()); - afterInit(config); - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - HttpServletRequest httpServletRequest = (HttpServletRequest) request; - HttpServletResponse httpServletResponse = (HttpServletResponse) response; - HttpSession session = httpServletRequest.getSession(true); - - // get an authenticated user or tries to authenticate if this is a - // authentication request - Principal userPrincipal = httpServletRequest.getUserPrincipal(); - String samlRequestMessage = (String) request.getParameter(GeneralConstants.SAML_REQUEST_KEY); - - // If this is a SAML Request but no user is authenticated, then redirect to - // login page - if (userPrincipal == null && StringUtils.isNotBlank(samlRequestMessage)) { - session.setAttribute(ORIGINAL_HTTP_SERVLET_REQUEST_PARAM, httpServletRequest); - - httpServletResponse.sendRedirect("/" + servletContextName + "/dologin?initialURI=" - + URLEncoder.encode(httpServletRequest.getRequestURI(), "UTF-8")); - return; - } else { - final HttpServletRequest originalHttpServletRequest = - (HttpServletRequest) session.getAttribute(ORIGINAL_HTTP_SERVLET_REQUEST_PARAM); - if (originalHttpServletRequest != null) { - request = new SAMLHTTPRequestWrapper(httpServletRequest, originalHttpServletRequest); - session.removeAttribute(ORIGINAL_HTTP_SERVLET_REQUEST_PARAM); - } - } - - super.doFilter(request, response, chain); - } - - /** - * @return Gives the {@link ExoContainer} that fits best with the current - * context - */ - private final ExoContainer getContainer() { - ExoContainer container = ExoContainerContext.getCurrentContainer(); - if (container instanceof RootContainer) { - container = interceptorContext.getExoContainer(); - } - if (container instanceof RootContainer) { - // The top container is a RootContainer, thus we assume that we are in a - // portal mode - container = PortalContainer.getInstance(); - } - // The container is a PortalContainer or a StandaloneContainer - return container; - } - - /** - * Method is invoked if we are performing initialization through servlet api - * (web filter) - */ - private final void afterInit(FilterConfig filterConfig) throws ServletException { - this.interceptorContext = new SSOInterceptorInitializationContext(filterConfig, null, null); - log.debug("Interceptor initialized with context " + interceptorContext); - try { - initImpl(); - } catch (ServletException e) { - log.error("Error initializing SAML Filter", e); - } - } - - /** - * Method is invoked if we are performing initialization through exo kernel - */ - public final void initWithParams(InitParams params, ExoContainerContext containerContext) { - this.interceptorContext = new SSOInterceptorInitializationContext(null, params, containerContext); - this.servletContextName = containerContext.getPortalContainerName(); - log.debug("Interceptor initialized with context " + interceptorContext); - try { - initImpl(); - } catch (ServletException e) { - log.error("Error initializing SAML Filter", e); - } - } - - /** - * This method needs to be implemented by conrete filter. Filter should obtain - * it's init parameters by calling {@link #getInitParameter(String)}. This - * works in both types of initialization (Case1: Filter initialization through - * kernel, Case2: initialization through servlet API) - * - * @throws ServletException an init exception happens when calling super class init method - */ - protected void initImpl() throws ServletException { - FilterConfig filterConfig = getFilterConfig(null); - if (this.servletContextName == null) { - this.servletContextName = ContainerUtil.getServletContextName(getServletContext()); - } - filterConfig.getServletContext().setInitParameter(GeneralConstants.CONFIG_FILE, - getInitParameter(GeneralConstants.CONFIG_FILE)); - super.init(filterConfig); - } - - /** - * Read init parameter (works for both kernel initialization or Servlet API - * initialization) - * - * @param paramName parameter name - * @return parameter value - */ - protected String getInitParameter(String paramName) { - return interceptorContext.getInitParameter(paramName); - } - - /** - * Indicates if it requires that a full portal environment must be set - * - * @return true if it requires the portal environment - * false otherwise. - */ - protected boolean requirePortalEnvironment() { - if (requirePortalEnvironment == null) { - synchronized (this) { - if (requirePortalEnvironment == null) { - this.requirePortalEnvironment = PortalContainer.isPortalContainerName(servletContextName); - } - } - } - return requirePortalEnvironment.booleanValue(); - } - - /** - * @return the current {@link ServletContext} - */ - protected ServletContext getServletContext() { - if (requirePortalEnvironment()) { - ExoContainer container = getContainer(); - if (container instanceof PortalContainer) { - return ((PortalContainer) container).getPortalContext(); - } - } - if (this.config != null) { - return this.config.getServletContext(); - } - return null; - } - - private FilterConfig getFilterConfig(FilterConfig config) { - if (this.config == null) { - if (config == null) { - this.config = new SAMLFilterConfig("PortalIDPWebBrowserSSOFilter", getServletContext(), interceptorContext); - } else { - this.config = config; - } - } - return this.config; - } -} diff --git a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/listener/IDPHttpSessionListener.java b/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/listener/IDPHttpSessionListener.java deleted file mode 100644 index deec0c39e..000000000 --- a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/listener/IDPHttpSessionListener.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.gatein.sso.saml.plugin.listener; - -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.gatein.sso.integration.SSOUtils; - -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; - -/** - * Class exists to avoid dependency on picketlink module from gatein.ear and use it only during SAML2 setup - * - * @author Marek Posolda - */ -public class IDPHttpSessionListener implements HttpSessionListener -{ - private static final Log log = ExoLogger.getLogger(IDPHttpSessionListener.class); - - private static final String PROPERTY_IDP_ENABLED = "gatein.sso.idp.listener.enabled"; - - private volatile HttpSessionListener delegate; - - public void sessionDestroyed(HttpSessionEvent se) - { - if ("true".equals(SSOUtils.getSystemProperty(PROPERTY_IDP_ENABLED, "false"))) - { - HttpSessionListener delegate = getOrInitDelegate(); - delegate.sessionDestroyed(se); - } - else - { - if (log.isTraceEnabled()) - { - log.trace("Portal is not acting as SAML2 IDP. Ignore this listener"); - } - } - } - - public void sessionCreated(HttpSessionEvent se) - { - } - - private HttpSessionListener getOrInitDelegate() - { - if (delegate == null) - { - synchronized (this) - { - if (delegate == null) - { - delegate = new org.picketlink.identity.federation.web.listeners.IDPHttpSessionListener(); - } - } - } - - return delegate; - } -} diff --git a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSPFormAuthenticator.java b/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSPFormAuthenticator.java deleted file mode 100644 index 37e42368a..000000000 --- a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSPFormAuthenticator.java +++ /dev/null @@ -1,787 +0,0 @@ -package org.gatein.sso.saml.plugin.valve; - -import static org.gatein.sso.saml.plugin.valve.AbstractSAML11SPRedirectFormAuthenticator.handleSAML11UnsolicitedResponse; -import static org.picketlink.common.util.StringUtil.isNotNull; -import static org.picketlink.common.util.StringUtil.isNullOrEmpty; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Set; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Context; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.Session; -import org.apache.catalina.authenticator.Constants; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.realm.GenericPrincipal; -import org.apache.tomcat.util.descriptor.web.LoginConfig; -import org.exoplatform.container.ExoContainer; -import org.exoplatform.container.ExoContainerContext; -import org.exoplatform.container.PortalContainer; -import org.exoplatform.container.RootContainer; -import org.exoplatform.services.organization.Membership; -import org.exoplatform.services.organization.OrganizationService; -import org.exoplatform.services.security.IdentityRegistry; -import org.exoplatform.services.security.MembershipEntry; -import org.exoplatform.services.security.MembershipHashSet; -import org.exoplatform.services.security.RolesExtractor; -import org.picketlink.common.ErrorCodes; -import org.picketlink.common.constants.GeneralConstants; -import org.picketlink.common.constants.JBossSAMLConstants; -import org.picketlink.common.exceptions.ConfigurationException; -import org.picketlink.common.exceptions.ParsingException; -import org.picketlink.common.exceptions.ProcessingException; -import org.picketlink.common.exceptions.TrustKeyProcessingException; -import org.picketlink.common.exceptions.fed.AssertionExpiredException; -import org.picketlink.common.util.DocumentUtil; -import org.picketlink.common.util.StringUtil; -import org.picketlink.config.federation.AuthPropertyType; -import org.picketlink.config.federation.KeyProviderType; -import org.picketlink.identity.federation.bindings.tomcat.sp.holder.ServiceProviderSAMLContext; -import org.picketlink.identity.federation.core.audit.PicketLinkAuditEvent; -import org.picketlink.identity.federation.core.audit.PicketLinkAuditEventType; -import org.picketlink.identity.federation.core.interfaces.TrustKeyManager; -import org.picketlink.identity.federation.core.saml.v2.holders.DestinationInfoHolder; -import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler; -import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerResponse; -import org.picketlink.identity.federation.core.util.CoreConfigUtil; -import org.picketlink.identity.federation.web.core.HTTPContext; -import org.picketlink.identity.federation.web.process.ServiceProviderBaseProcessor; -import org.picketlink.identity.federation.web.process.ServiceProviderSAMLRequestProcessor; -import org.picketlink.identity.federation.web.process.ServiceProviderSAMLResponseProcessor; -import org.picketlink.identity.federation.web.util.HTTPRedirectUtil; -import org.picketlink.identity.federation.web.util.PostBindingUtil; -import org.picketlink.identity.federation.web.util.RedirectBindingUtil; -import org.picketlink.identity.federation.web.util.RedirectBindingUtil.RedirectBindingUtilDestHolder; -import org.picketlink.identity.federation.web.util.ServerDetector; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -/** - * Abstract class to be extended by Service Provider valves to handle SAML requests and responses. - * forked from org.picketlink.identity.federation.bindings.tomcat.sp.AbstractSPFormAuthenticator - * and made compatible with Tomcat 8.5 since picketlink doesn't provide such a support - */ -public abstract class AbstractSPFormAuthenticator extends BaseFormAuthenticator { - - protected boolean jbossEnv = false; - - public AbstractSPFormAuthenticator() { - super(); - ServerDetector detector = new ServerDetector(); - jbossEnv = detector.isJboss(); - } - - /* - * (non-Javadoc) - * - * @see org.picketlink.identity.federation.bindings.tomcat.sp.BaseFormAuthenticator#processStart() - */ - @Override - protected void startPicketLink() throws LifecycleException { - super.startPicketLink(); - initKeyProvider(context); - } - - /** - *

- * Send the request to the IDP. Subclasses should override this method to implement how requests must be sent to the IDP. - *

- * - * @param destination idp url - * @param samlDocument request or response document - * @param relayState used in SAML Workflow - * @param response Apache Catalina HTTP Response - * @param request Apache Catalina HTTP Request - * @param willSendRequest are we sending Request or Response to IDP - * @param destinationQueryStringWithSignature used only with Redirect binding and with signature enabled. - * @throws ProcessingException Exception to indicate a server processing error - * @throws ConfigurationException Exception indicating an issue with the configuration - * @throws IOException I/O exception - */ - protected void sendRequestToIDP(String destination, Document samlDocument, String relayState, Request request, Response response, - boolean willSendRequest, String destinationQueryStringWithSignature) throws ProcessingException, ConfigurationException, IOException { - - if (isAjaxRequest(request) && request.getUserPrincipal() == null) { - response.sendError(Response.SC_FORBIDDEN); - } else { - if (isHttpPostBinding()) { - sendHttpPostBindingRequest(destination, samlDocument, relayState, response, willSendRequest); - } else { - sendHttpRedirectRequest(destination, samlDocument, relayState, response, willSendRequest, destinationQueryStringWithSignature); - } - } - } - - /** - *

- * Sends a HTTP Redirect request to the IDP. - *

- * - * @param destination idp url - * @param samlDocument SAML request document - * @param relayState used in SAML Workflow - * @param response Apache Catalina HTTP Response - * @param willSendRequest are we sending Request or Response to IDP - * @param destinationQueryStringWithSignature used only with Redirect binding and with signature enabled. - * @throws IOException I/O exception - * @throws UnsupportedEncodingException when decoding SAML Message - * @throws ConfigurationException Exception indicating an issue with the configuration - * @throws ProcessingException Exception to indicate a server processing error - */ - protected void sendHttpRedirectRequest(String destination, Document samlDocument, String relayState, Response response, - boolean willSendRequest, String destinationQueryStringWithSignature) throws IOException, - ProcessingException, ConfigurationException { - String destinationQueryString = null; - - // We already have queryString with signature from SAML2SignatureGenerationHandler - if (destinationQueryStringWithSignature != null) { - destinationQueryString = destinationQueryStringWithSignature; - } - else { - String samlMessage = DocumentUtil.getDocumentAsString(samlDocument); - String base64Request = RedirectBindingUtil.deflateBase64URLEncode(samlMessage.getBytes("UTF-8")); - destinationQueryString = RedirectBindingUtil.getDestinationQueryString(base64Request, relayState, willSendRequest); - } - - RedirectBindingUtilDestHolder holder = new RedirectBindingUtilDestHolder(); - - holder.setDestination(destination).setDestinationQueryString(destinationQueryString); - - HTTPRedirectUtil.sendRedirectForRequestor(RedirectBindingUtil.getDestinationURL(holder), response); - } - - /** - *

- * Sends a HTTP POST request to the IDP. - *

- * - * @param destination idp url - * @param samlDocument request or response document - * @param relayState used in SAML Workflow - * @param response Apache Catalina HTTP Response - * @param willSendRequest are we sending Request or Response to IDP - * @throws ProcessingException Exception to indicate a server processing error - * @throws ConfigurationException Exception indicating an issue with the configuration - * @throws IOException I/O exception - */ - protected void sendHttpPostBindingRequest(String destination, Document samlDocument, String relayState, Response response, - boolean willSendRequest) throws ProcessingException, IOException, - ConfigurationException { - String samlMessage = PostBindingUtil.base64Encode(DocumentUtil.getDocumentAsString(samlDocument)); - - DestinationInfoHolder destinationHolder = new DestinationInfoHolder(destination, samlMessage, relayState); - - PostBindingUtil.sendPost(destinationHolder, response, willSendRequest); - } - - /** - *

- * Initialize the KeyProvider configurations. This configurations are to be used during signing and validation of SAML - * assertions. - *

- * - * @param context Apache Catalina Context - * @throws LifecycleException any exception occurred while processing key provider - */ - protected void initKeyProvider(Context context) throws LifecycleException { - if (!doSupportSignature()) { - return; - } - - KeyProviderType keyProvider = this.spConfiguration.getKeyProvider(); - - if (keyProvider == null && doSupportSignature()) - throw new LifecycleException(ErrorCodes.NULL_VALUE + "KeyProvider is null for context=" + context.getName()); - - try { - String keyManagerClassName = keyProvider.getClassName(); - if (keyManagerClassName == null) - throw new RuntimeException(ErrorCodes.NULL_VALUE + "KeyManager class name"); - - Class clazz = SecurityActions.loadClass(getClass(), keyManagerClassName); - - if (clazz == null) - throw new ClassNotFoundException(ErrorCodes.CLASS_NOT_LOADED + keyManagerClassName); - this.keyManager = (TrustKeyManager) clazz.newInstance(); - - List authProperties = CoreConfigUtil.getKeyProviderProperties(keyProvider); - - keyManager.setAuthProperties(authProperties); - keyManager.setValidatingAlias(keyProvider.getValidatingAlias()); - - String identityURL = this.spConfiguration.getIdentityURL(); - - //Special case when you need X509Data in SignedInfo - if(authProperties != null){ - for(AuthPropertyType authPropertyType: authProperties){ - String key = authPropertyType.getKey(); - if(GeneralConstants.X509CERTIFICATE.equals(key)){ - //we need X509Certificate in SignedInfo. The value is the alias name - keyManager.addAdditionalOption(GeneralConstants.X509CERTIFICATE, authPropertyType.getValue()); - break; - } - } - } - keyManager.addAdditionalOption(ServiceProviderBaseProcessor.IDP_KEY, new URL(identityURL).getHost()); - } catch (Exception e) { - logger.trustKeyManagerCreationError(e); - throw new LifecycleException(e.getLocalizedMessage()); - } - - logger.trace("Key Provider=" + keyProvider.getClassName()); - } - - @Override - protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException { - if (response instanceof Response) { - LoginConfig loginConfig = request.getContext().getLoginConfig(); - Response catalinaResponse = (Response) response; - return authenticate(request, catalinaResponse, loginConfig); - } - throw logger.samlSPResponseNotCatalinaResponseError(response); - } - - /** - * Authenticate the request - * - * @param request Apache Catalina Request - * @param response Apache Catalina Response - * @return true if authenticated, else false - * @throws IOException any I/O exception - */ - public boolean authenticate(Request request, HttpServletResponse response) throws IOException { - if (response instanceof Response) { - LoginConfig loginConfig = request.getContext().getLoginConfig(); - Response catalinaResponse = (Response) response; - return authenticate(request, catalinaResponse, loginConfig); - } - throw logger.samlSPResponseNotCatalinaResponseError(response); - } - - /* - * (non-Javadoc) - * - * @see org.apache.catalina.authenticator.FormAuthenticator#authenticate(org.apache.catalina.connector.Request, - * org.apache.catalina.connector.Response, org.apache.catalina.deploy.LoginConfig) - */ - private boolean authenticate(Request request, Response response, LoginConfig loginConfig) throws IOException { - try { - // needs to be done first, *before* accessing any parameters. super.authenticate(..) gets called to late - String characterEncoding = getCharacterEncoding(); - if (characterEncoding != null) { - request.setCharacterEncoding(characterEncoding); - } - - Session session = request.getSessionInternal(true); - - // check if this call is resulting from the redirect after successful authentication. - // if so, make the authentication successful and continue the original request - if (saveRestoreRequest && matchRequest(request)) { - logger.trace("Restoring request from session '" + session.getIdInternal() + "'"); - Principal savedPrincipal = (Principal)session.getNote(Constants.FORM_PRINCIPAL_NOTE); - register (request, response, savedPrincipal, HttpServletRequest.FORM_AUTH, (String)session.getNote(Constants.SESS_USERNAME_NOTE), (String)session.getNote(Constants.SESS_PASSWORD_NOTE)); - - // try to restore the original request (including post data, etc...) - if (restoreRequest(request, session)) { - // success! user is authenticated; continue processing original request - logger.trace("Continuing with restored request."); - return true; - } - else { - // no saved request found... - logger.trace("Restore of original request failed!"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return false; - } - } - - // Eagerly look for Local LogOut - boolean localLogout = isLocalLogout(request); - - if (localLogout) { - try { - sendToLogoutPage(request, response, session); - } catch (ServletException e) { - logger.samlLogoutError(e); - throw new IOException(e); - } - return false; - } - - String samlRequest = request.getParameter(GeneralConstants.SAML_REQUEST_KEY); - String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); - - Principal principal = request.getUserPrincipal(); - - // If we have already authenticated the user and there is no request from IDP or logout from user - if (principal != null && !(isGlobalLogout(request) || isNotNull(samlRequest) || isNotNull(samlResponse))) - return true; - - // General User Request - if (!isNotNull(samlRequest) && !isNotNull(samlResponse)) { - return generalUserRequest(request, response, loginConfig); - } - - // Handle a SAML Response from IDP - if (isNotNull(samlResponse)) { - return handleSAMLResponse(request, response, loginConfig); - } - - // Handle SAML Requests from IDP - if (isNotNull(samlRequest)) { - return handleSAMLRequest(request, response, loginConfig); - }// end if - - return localAuthentication(request, response, loginConfig); - } catch (IOException e) { - if (StringUtil.isNotNull(spConfiguration.getErrorPage())) { - try { - request.getRequestDispatcher(spConfiguration.getErrorPage()).forward(request.getRequest(), response); - } catch (ServletException e1) { - logger.samlErrorPageForwardError(spConfiguration.getErrorPage(), e1); - } - return false; - } else { - throw e; - } - } - } - - /** - *

- * Indicates if the current request is a GlobalLogout request. - *

- * - * @param request Apache Catalina Request - * @return true if this is a global SAML logout - */ - private boolean isGlobalLogout(Request request) { - String gloStr = request.getParameter(GeneralConstants.GLOBAL_LOGOUT); - return isNotNull(gloStr) && "true".equalsIgnoreCase(gloStr); - } - - /** - *

- * Indicates if the current request is a LocalLogout request. - *

- * - * @param request Apache Catalina Request - * @return true if this is a local SAML logout - */ - private boolean isLocalLogout(Request request) { - try { - if (request.getCharacterEncoding()==null) { - request.setCharacterEncoding("UTF-8"); - } - } catch (UnsupportedEncodingException e) { - logger.error("Request have no encoding, and we are unable to set it to UTF-8"); - logger.error(e); - } - String lloStr = request.getParameter(GeneralConstants.LOCAL_LOGOUT); - return isNotNull(lloStr) && "true".equalsIgnoreCase(lloStr); - } - - /** - * Handle the IDP Request - * - * @param request Apache Catalina Request - * @param response Apache Catalina Response - * @param loginConfig Apache Catalina Login Config - * @return true if processed by SAML Workflow - * @throws IOException any I/O error while authenticating - */ - private boolean handleSAMLRequest(Request request, Response response, LoginConfig loginConfig) throws IOException { - String samlRequest = request.getParameter(GeneralConstants.SAML_REQUEST_KEY); - HTTPContext httpContext = new HTTPContext(request, response, context.getServletContext()); - Set handlers = chain.handlers(); - - try { - ServiceProviderSAMLRequestProcessor requestProcessor = new ServiceProviderSAMLRequestProcessor( - request.getMethod().equals("POST"), this.serviceURL, this.picketLinkConfiguration); - requestProcessor.setTrustKeyManager(keyManager); - boolean result = requestProcessor.process(samlRequest, httpContext, handlers, chainLock); - - if (enableAudit) { - PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent("Info"); - auditEvent.setType(PicketLinkAuditEventType.REQUEST_FROM_IDP); - auditEvent.setWhoIsAuditing(getContextPath()); - auditHelper.audit(auditEvent); - } - - // If response is already commited, we need to stop with processing of HTTP request - if (response.isCommitted() || response.isAppCommitted()) - return false; - - if (result) - return result; - } catch (Exception e) { - logger.samlSPHandleRequestError(e); - throw logger.samlSPProcessingExceptionError(e); - } - - return localAuthentication(request, response, loginConfig); - } - - private Document toSAMLResponseDocument(String samlResponse, boolean isPostBinding) throws ParsingException { - InputStream dataStream = null; - - if (isPostBinding) { - // deal with SAML response from IDP - dataStream = PostBindingUtil.base64DecodeAsStream(samlResponse); - } else { - // deal with SAML response from IDP - dataStream = RedirectBindingUtil.base64DeflateDecode(samlResponse); - } - - try { - return DocumentUtil.getDocument(dataStream); - } catch (Exception e) { - logger.samlResponseFromIDPParsingFailed(); - throw new ParsingException("", e); - } - } - - /** - * Handle IDP Response - * - * @param request Apache Catalina Request - * @param response Apache Catalina Response - * @param loginConfig Apache Catalina Login Config - * @return true if logged in in SAML SP side - * @throws IOException any I/O error in authentication process - */ - private boolean handleSAMLResponse(Request request, Response response, LoginConfig loginConfig) throws IOException { - if (!super.validate(request)) { - throw new IOException(ErrorCodes.VALIDATION_CHECK_FAILED); - } - - String samlVersion = getSAMLVersion(request); - - if (!JBossSAMLConstants.VERSION_2_0.get().equals(samlVersion)) { - return handleSAML11UnsolicitedResponse(request, response, loginConfig, this); - } - - return handleSAML2Response(request, response, loginConfig); - } - - private boolean handleSAML2Response(Request request, Response response, LoginConfig loginConfig) throws IOException { - Session session = request.getSessionInternal(true); - String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); - HTTPContext httpContext = new HTTPContext(request, response, context.getServletContext()); - Set handlers = chain.handlers(); - - Principal principal = request.getUserPrincipal(); - - boolean willSendRequest;// deal with SAML response from IDP - - try { - ServiceProviderSAMLResponseProcessor responseProcessor = new ServiceProviderSAMLResponseProcessor(request.getMethod().equals("POST"), serviceURL, this.picketLinkConfiguration); - if(auditHelper != null){ - responseProcessor.setAuditHelper(auditHelper); - } - - responseProcessor.setTrustKeyManager(keyManager); - - SAML2HandlerResponse saml2HandlerResponse = responseProcessor.process(samlResponse, httpContext, handlers, - chainLock); - - Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); - String relayState = saml2HandlerResponse.getRelayState(); - - String destination = saml2HandlerResponse.getDestination(); - - willSendRequest = saml2HandlerResponse.getSendRequest(); - - String destinationQueryStringWithSignature = saml2HandlerResponse.getDestinationQueryStringWithSignature(); - - if (destination != null && samlResponseDocument != null) { - sendRequestToIDP(destination, samlResponseDocument, relayState, request, response, willSendRequest, destinationQueryStringWithSignature); - } else { - // See if the session has been invalidated - - boolean sessionValidity = session.isValid(); - - if (!sessionValidity) { - sendToLogoutPage(request, response, session); - return false; - } - - // We got a response with the principal - List roles = saml2HandlerResponse.getRoles(); - - if (principal == null) { - principal = (Principal) session.getSession().getAttribute(GeneralConstants.PRINCIPAL_ID); - } - - String username = principal.getName(); - String password = ServiceProviderSAMLContext.EMPTY_PASSWORD; - - roles.addAll(extractGateinRoles(username)); - if (logger.isTraceEnabled()) { - logger.trace("Roles determined for username=" + username + "=" + Arrays.toString(roles.toArray())); - } - - // Map to JBoss specific principal - if ((new ServerDetector()).isJboss() || jbossEnv) { - // Push a context - ServiceProviderSAMLContext.push(username, roles); - principal = context.getRealm().authenticate(username, password); - ServiceProviderSAMLContext.clear(); - } else { - // tomcat env - principal = getGenericPrincipal(request, username, roles); - } - - session.setNote(Constants.SESS_USERNAME_NOTE, username); - session.setNote(Constants.SESS_PASSWORD_NOTE, password); - request.setUserPrincipal(principal); - - if (enableAudit) { - PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent("Info"); - auditEvent.setType(PicketLinkAuditEventType.RESPONSE_FROM_IDP); - auditEvent.setSubjectName(username); - auditEvent.setWhoIsAuditing(getContextPath()); - auditHelper.audit(auditEvent); - } - - // Redirect the user to the originally requested URL - if (saveRestoreRequest) { - // Store the authenticated principal in the session. - session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal); - - // Redirect to the original URL. Note that this will trigger the - // authenticator again, but on resubmission we will look in the - // session notes to retrieve the authenticated principal and - // prevent reauthentication - String requestURI = savedRequestURL(session); - - if (requestURI != null) { - logger.trace("Redirecting back to original Request URI: " + requestURI); - response.sendRedirect(response.encodeRedirectURL(requestURI)); - } - } - - register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password); - return true; - } - } catch (ProcessingException pe) { - Throwable t = pe.getCause(); - if (t != null && t instanceof AssertionExpiredException) { - logger.error("Assertion has expired. Asking IDP for reissue"); - if (enableAudit) { - PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent("Info"); - auditEvent.setType(PicketLinkAuditEventType.EXPIRED_ASSERTION); - auditEvent.setAssertionID(((AssertionExpiredException) t).getId()); - auditHelper.audit(auditEvent); - } - // Just issue a fresh request back to IDP - return generalUserRequest(request, response, loginConfig); - } - logger.samlSPHandleRequestError(pe); - throw logger.samlSPProcessingExceptionError(pe); - } catch (Exception e) { - logger.samlSPHandleRequestError(e); - throw logger.samlSPProcessingExceptionError(e); - } - - return localAuthentication(request, response, loginConfig); - } - - private String getSAMLVersion(Request request) { - String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); - String version; - - try { - Document samlDocument = toSAMLResponseDocument(samlResponse, "POST".equalsIgnoreCase(request.getMethod())); - Element element = samlDocument.getDocumentElement(); - - // let's try SAML 2.0 Version attribute first - version = element.getAttribute("Version"); - - if (isNullOrEmpty(version)) { - // fallback to SAML 1.1 Minor and Major attributes - String minorVersion = element.getAttribute("MinorVersion"); - String majorVersion = element.getAttribute("MajorVersion"); - - version = minorVersion + "." + majorVersion; - } - } catch (Exception e) { - throw new RuntimeException("Could not extract version from SAML Response.", e); - } - - return version; - } - - protected boolean isPOSTBindingResponse() { - return spConfiguration.isIdpUsesPostBinding(); - } - - - /* - * (non-Javadoc) - * - * @see org.picketlink.identity.federation.bindings.tomcat.sp.BaseFormAuthenticator#getBinding() - */ - @Override - protected String getBinding() { - return spConfiguration.getBindingType(); - } - - /** - * Handle the user invocation for the first time - * - * @param request Apache Catalina Request - * @param response Apache Catalina Response - * @param loginConfig Apache Catalina Login Config - * @return true if logged in in SAML SP side - * @throws IOException any I/O error in authentication process - */ - private boolean generalUserRequest(Request request, Response response, LoginConfig loginConfig) throws IOException { - Session session = request.getSessionInternal(true); - boolean willSendRequest = false; - HTTPContext httpContext = new HTTPContext(request, response, context.getServletContext()); - Set handlers = chain.handlers(); - - boolean postBinding = spConfiguration.getBindingType().equals("POST"); - - // Neither saml request nor response from IDP - // So this is a user request - SAML2HandlerResponse saml2HandlerResponse = null; - try { - ServiceProviderBaseProcessor baseProcessor = new ServiceProviderBaseProcessor(postBinding, serviceURL, this.picketLinkConfiguration); - if (issuerID != null) - baseProcessor.setIssuer(issuerID); - - // If the user has a different desired idp - String idp = (String) request.getAttribute(org.picketlink.identity.federation.web.constants.GeneralConstants.DESIRED_IDP); - if (StringUtil.isNotNull(idp)) { - baseProcessor.setIdentityURL(idp); - } else { - baseProcessor.setIdentityURL(identityURL); - } - baseProcessor.setAuditHelper(auditHelper); - - saml2HandlerResponse = baseProcessor.process(httpContext, handlers, chainLock); - } catch (ProcessingException pe) { - logger.samlSPHandleRequestError(pe); - throw new RuntimeException(pe); - } catch (ParsingException pe) { - logger.samlSPHandleRequestError(pe); - throw new RuntimeException(pe); - } catch (ConfigurationException pe) { - logger.samlSPHandleRequestError(pe); - throw new RuntimeException(pe); - } - - willSendRequest = saml2HandlerResponse.getSendRequest(); - - Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); - String relayState = saml2HandlerResponse.getRelayState(); - - String destination = saml2HandlerResponse.getDestination(); - String destinationQueryStringWithSignature = saml2HandlerResponse.getDestinationQueryStringWithSignature(); - - if (destination != null && samlResponseDocument != null) { - try { - if (saveRestoreRequest && !isGlobalLogout(request)) { - this.saveRequest(request, session); - } - if (enableAudit) { - PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent("Info"); - auditEvent.setType(PicketLinkAuditEventType.REQUEST_TO_IDP); - auditEvent.setWhoIsAuditing(getContextPath()); - auditHelper.audit(auditEvent); - } - sendRequestToIDP(destination, samlResponseDocument, relayState, request, response, willSendRequest, destinationQueryStringWithSignature); - return false; - } catch (Exception e) { - logger.samlSPHandleRequestError(e); - throw logger.samlSPProcessingExceptionError(e); - } - } - - return localAuthentication(request, response, loginConfig); - } - - /** - * Extract Gatein roles to put in Principal - * @param userId - * @return - */ - private List extractGateinRoles(String userId) { - OrganizationService organizationService = - PortalContainer.getInstance().getComponentInstanceOfType(OrganizationService.class); - RolesExtractor rolesExtractor=PortalContainer.getInstance().getComponentInstanceOfType(RolesExtractor.class); - List result = new ArrayList<>(); - Set entries = new MembershipHashSet(); - Collection memberships; - try { - memberships = organizationService.getMembershipHandler().findMembershipsByUser(userId); - } catch (Exception e) { - memberships = null; - } - if (memberships != null) { - for (Membership membership : memberships) - entries.add(new MembershipEntry(membership.getGroupId(), membership.getMembershipType())); - } - result.addAll(rolesExtractor.extractRoles(userId, entries)); - return result; - } - - /** - *

- * Indicates if the SP is configure with HTTP POST Binding. - *

- * - * @return true if post binding - */ - protected boolean isHttpPostBinding() { - return getBinding().equalsIgnoreCase("POST"); - } - - public Context getContext() { - return (Context) getContainer(); - } - - @Override - public boolean restoreRequest(Request request, Session session) throws IOException { - return super.restoreRequest(request, session); - } - - /** - * Subclasses need to return the context path - * based on the capability of their servlet api - * - * @return Servlet Context Path - */ - protected abstract String getContextPath(); - - protected Principal getGenericPrincipal(Request request, String username, List roles){ - //sometimes, IDP send username in assertion with capitals letters, or with inconsistent format. - //this option allows to force the username in lower case, just before creating the principal, - //so that, all operations in exo side will use a consistant format. - String forceLowerCase = System.getProperty("gatein.sso.saml.username.forcelowercase","false"); - if(forceLowerCase.equalsIgnoreCase("true")) { - username=username.toLowerCase(); - } - return new GenericPrincipal(username, null, roles); - } - - private boolean isAjaxRequest(Request request) { - String requestedWithHeader = request.getHeader(GeneralConstants.HTTP_HEADER_X_REQUESTED_WITH); - return requestedWithHeader != null && "XMLHttpRequest".equalsIgnoreCase(requestedWithHeader); - } -} diff --git a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/BaseFormAuthenticator.java b/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/BaseFormAuthenticator.java deleted file mode 100644 index 8bcc5a4cd..000000000 --- a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/BaseFormAuthenticator.java +++ /dev/null @@ -1,623 +0,0 @@ -package org.gatein.sso.saml.plugin.valve; - -import static org.picketlink.common.constants.GeneralConstants.CONFIG_FILE_LOCATION; -import static org.picketlink.common.util.StringUtil.isNullOrEmpty; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.crypto.dsig.CanonicalizationMethod; - -import org.apache.catalina.Context; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.Session; -import org.apache.catalina.authenticator.FormAuthenticator; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.tomcat.util.descriptor.web.LoginConfig; -import org.picketlink.common.ErrorCodes; -import org.picketlink.common.PicketLinkLogger; -import org.picketlink.common.PicketLinkLoggerFactory; -import org.picketlink.common.constants.GeneralConstants; -import org.picketlink.common.constants.JBossSAMLURIConstants; -import org.picketlink.common.exceptions.ConfigurationException; -import org.picketlink.common.exceptions.ParsingException; -import org.picketlink.common.exceptions.ProcessingException; -import org.picketlink.common.util.DocumentUtil; -import org.picketlink.common.util.StringUtil; -import org.picketlink.common.util.SystemPropertiesUtil; -import org.picketlink.config.federation.PicketLinkType; -import org.picketlink.config.federation.SPType; -import org.picketlink.config.federation.handler.Handlers; -import org.picketlink.identity.federation.api.saml.v2.metadata.MetaDataExtractor; -import org.picketlink.identity.federation.core.audit.PicketLinkAuditHelper; -import org.picketlink.identity.federation.core.interfaces.TrustKeyManager; -import org.picketlink.identity.federation.core.parsers.saml.SAMLParser; -import org.picketlink.identity.federation.core.saml.v2.factories.SAML2HandlerChainFactory; -import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerChainConfig; -import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler; -import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerChain; -import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerChainConfig; -import org.picketlink.identity.federation.core.saml.v2.util.HandlerUtil; -import org.picketlink.identity.federation.core.util.CoreConfigUtil; -import org.picketlink.identity.federation.core.util.XMLSignatureUtil; -import org.picketlink.identity.federation.saml.v2.metadata.EndpointType; -import org.picketlink.identity.federation.saml.v2.metadata.EntitiesDescriptorType; -import org.picketlink.identity.federation.saml.v2.metadata.EntityDescriptorType; -import org.picketlink.identity.federation.saml.v2.metadata.IDPSSODescriptorType; -import org.picketlink.identity.federation.saml.v2.metadata.KeyDescriptorType; -import org.picketlink.identity.federation.web.config.AbstractSAMLConfigurationProvider; -import org.picketlink.identity.federation.web.util.ConfigurationUtil; -import org.picketlink.identity.federation.web.util.SAMLConfigurationProvider; -import org.w3c.dom.Document; - -/** - * Base Class for Service Provider Form Authenticators - * forked from org.picketlink.identity.federation.bindings.tomcat.sp.BaseFormAuthenticator - * and made compatible with Tomcat 8.5 since picketlink doesn't provide such a support - */ -public abstract class BaseFormAuthenticator extends FormAuthenticator { - protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); - - protected boolean enableAudit = false; - protected PicketLinkAuditHelper auditHelper = null; - - protected TrustKeyManager keyManager; - - protected SPType spConfiguration = null; - - protected PicketLinkType picketLinkConfiguration = null; - - protected String serviceURL = null; - - protected String identityURL = null; - - protected String issuerID = null; - - protected String configFile; - - /** - * If the service provider is configured with an IDP metadata file, then this certificate can be picked up from the metadata - */ - protected transient X509Certificate idpCertificate = null; - - protected transient SAML2HandlerChain chain = null; - - protected transient String samlHandlerChainClass = null; - - protected Map chainConfigOptions = new HashMap(); - - // Whether the authenticator has to to save and restore request - protected boolean saveRestoreRequest = true; - - /** - * A Lock for Handler operations in the chain - */ - protected Lock chainLock = new ReentrantLock(); - - protected String canonicalizationMethod = CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS; - - /** - * The user can inject a fully qualified name of a {@link SAMLConfigurationProvider} - */ - protected SAMLConfigurationProvider configProvider = null; - - protected int timerInterval = -1; - - protected Timer timer = null; - - public BaseFormAuthenticator() { - super(); - } - - protected String idpAddress = null; - - /** - * If the request.getRemoteAddr is not exactly the IDP address that you have keyed in your deployment descriptor for - * keystore alias, you can set it here explicitly - * - * @param idpAddress IP address of IDP - */ - public void setIdpAddress(String idpAddress) { - this.idpAddress = idpAddress; - } - - /** - * Get the name of the configuration file - * @return SAML config file path - */ - public String getConfigFile() { - return configFile; - } - - /** - * Set the name of the configuration file - * @param configFile set config file path - */ - public void setConfigFile(String configFile) { - this.configFile = configFile; - } - - /** - * Set the SAML Handler Chain Class fqn - * @param samlHandlerChainClass FQN of SAML Handler Chain - */ - public void setSamlHandlerChainClass(String samlHandlerChainClass) { - this.samlHandlerChainClass = samlHandlerChainClass; - } - - /** - * Set the service URL - * @param serviceURL Service URL - */ - public void setServiceURL(String serviceURL) { - this.serviceURL = serviceURL; - } - - /** - * Set whether the authenticator saves/restores the request - * during form authentication - * @param saveRestoreRequest saves/restores the request during authentication if true - */ - public void setSaveRestoreRequest(boolean saveRestoreRequest) { - this.saveRestoreRequest = saveRestoreRequest; - } - - /** - * Set the {@link SAMLConfigurationProvider} fqn - * @param cp fqn of a {@link SAMLConfigurationProvider} - */ - public void setConfigProvider(String cp) { - if (cp == null) - throw new IllegalStateException(ErrorCodes.NULL_ARGUMENT + cp); - Class clazz = SecurityActions.loadClass(getClass(), cp); - if (clazz == null) - throw new RuntimeException(ErrorCodes.CLASS_NOT_LOADED + cp); - try { - configProvider = (SAMLConfigurationProvider) clazz.newInstance(); - } catch (Exception e) { - throw new RuntimeException(ErrorCodes.CANNOT_CREATE_INSTANCE + cp + ":" + e.getMessage()); - } - } - - /** - * Set an instance of the {@link SAMLConfigurationProvider} - * @param configProvider SAML IDP/SP config provider - */ - public void setConfigProvider(SAMLConfigurationProvider configProvider) { - this.configProvider = configProvider; - } - - /** - * Get the {@link SPType} - * @return SAML SP configuration - */ - public SPType getConfiguration() { - return spConfiguration; - } - - /** - * Set a separate issuer id - * - * @param issuerID id of the issuer - */ - public void setIssuerID(String issuerID) { - this.issuerID = issuerID; - } - - /** - * Set the logout page - * @param logOutPage logout page URL - */ - public void setLogOutPage(String logOutPage) { - logger.warn("Option logOutPage is now configured with the PicketLinkSP element."); - - } - - /** - * Set the Timer Value to reload the configuration - * @param value an integer value that represents timer value (in miliseconds) - */ - public void setTimerInterval(String value){ - if(StringUtil.isNotNull(value)){ - timerInterval = Integer.parseInt(value); - } - } - - /** - * Perform validation os the request object - * - * @param request Apache Catalina Request - * @return true if request contains a SAML Response parameter - */ - protected boolean validate(Request request) { - return request.getParameter("SAMLResponse") != null; - } - - /** - * Get the Identity URL - * - * @return Identity URL - */ - public String getIdentityURL() { - return identityURL; - } - - /** - * Get the {@link X509Certificate} of the IDP if provided via the IDP metadata file - * - * @return {@link X509Certificate} or null - */ - public X509Certificate getIdpCertificate() { - return idpCertificate; - } - - /** - * Fall back on local authentication at the service provider side - * - * @param request Apache Catalina Request - * @param response Apache Catalina Response - * @param loginConfig Apache Catalina Login Config - * @return true if authenticated - * @throws IOException any I/O error during authentication - */ - protected boolean localAuthentication(Request request, Response response, LoginConfig loginConfig) throws IOException { - if (request.getUserPrincipal() == null) { - logger.samlSPFallingBackToLocalFormAuthentication();// fallback - try { - return super.authenticate(request, response.getResponse()); - } catch (NoSuchMethodError e) { - // Use Reflection - try { - Method method = super.getClass().getMethod("authenticate", - new Class[] { HttpServletRequest.class, HttpServletResponse.class, LoginConfig.class }); - return (Boolean) method.invoke(this, new Object[] { request.getRequest(), response.getResponse(), - loginConfig }); - } catch (Exception ex) { - throw logger.unableLocalAuthentication(ex); - } - } - } else - return true; - } - - /** - * Return the SAML Binding that this authenticator supports - * - * @return supported SAML Binding - */ - protected abstract String getBinding(); - - /** - * Attempt to process a metadata file available locally - * - * @param idpMetadataFile path of configuration file of IDP Metadata - */ - protected void processIDPMetadataFile(String idpMetadataFile) { - ServletContext servletContext = context.getServletContext(); - InputStream is = servletContext.getResourceAsStream(idpMetadataFile); - if (is == null) - return; - - Object metadata = null; - try { - Document samlDocument = DocumentUtil.getDocument(is); - SAMLParser parser = new SAMLParser(); - metadata = parser.parse(DocumentUtil.getNodeAsStream(samlDocument)); - } catch (Exception e) { - throw new RuntimeException(e); - } - IDPSSODescriptorType idpSSO = null; - if (metadata instanceof EntitiesDescriptorType) { - EntitiesDescriptorType entities = (EntitiesDescriptorType) metadata; - idpSSO = handleMetadata(entities); - } else { - idpSSO = handleMetadata((EntityDescriptorType) metadata); - } - if (idpSSO == null) { - logger.samlSPUnableToGetIDPDescriptorFromMetadata(); - return; - } - List endpoints = idpSSO.getSingleSignOnService(); - for (EndpointType endpoint : endpoints) { - String endpointBinding = endpoint.getBinding().toString(); - if (endpointBinding.contains("HTTP-POST")) - endpointBinding = "POST"; - else if (endpointBinding.contains("HTTP-Redirect")) - endpointBinding = "REDIRECT"; - if (getBinding().equals(endpointBinding)) { - identityURL = endpoint.getLocation().toString(); - break; - } - } - List keyDescriptors = idpSSO.getKeyDescriptor(); - if (keyDescriptors.size() > 0) { - this.idpCertificate = MetaDataExtractor.getCertificate(keyDescriptors.get(0)); - } - } - - /** - * Process the configuration from the configuration file - */ - @SuppressWarnings("deprecation") - protected void processConfiguration() { - ServletContext servletContext = context.getServletContext(); - InputStream is = null; - - if (isNullOrEmpty(this.configFile)) { - this.configFile = CONFIG_FILE_LOCATION; - is = servletContext.getResourceAsStream(this.configFile); - } else { - try { - is = new FileInputStream(this.configFile); - } catch (FileNotFoundException e) { - throw logger.samlIDPConfigurationError(e); - } - } - - try { - // Work on the IDP Configuration - if (configProvider != null) { - try { - if (is == null) { - // Try the older version - is = servletContext.getResourceAsStream(GeneralConstants.DEPRECATED_CONFIG_FILE_LOCATION); - - // Additionally parse the deprecated config file - if (is != null && configProvider instanceof AbstractSAMLConfigurationProvider) { - ((AbstractSAMLConfigurationProvider) configProvider).setConfigFile(is); - } - } else { - // Additionally parse the consolidated config file - if (is != null && configProvider instanceof AbstractSAMLConfigurationProvider) { - ((AbstractSAMLConfigurationProvider) configProvider).setConsolidatedConfigFile(is); - } - } - - picketLinkConfiguration = configProvider.getPicketLinkConfiguration(); - spConfiguration = configProvider.getSPConfiguration(); - } catch (ProcessingException e) { - throw logger.samlSPConfigurationError(e); - } catch (ParsingException e) { - throw logger.samlSPConfigurationError(e); - } - } else { - if (is != null) { - try { - picketLinkConfiguration = ConfigurationUtil.getConfiguration(is); - spConfiguration = (SPType) picketLinkConfiguration.getIdpOrSP(); - } catch (ParsingException e) { - logger.trace(e); - throw logger.samlSPConfigurationError(e); - } - } else { - is = servletContext.getResourceAsStream(GeneralConstants.DEPRECATED_CONFIG_FILE_LOCATION); - if (is == null) - throw logger.configurationFileMissing(configFile); - spConfiguration = ConfigurationUtil.getSPConfiguration(is); - } - } - - if (this.picketLinkConfiguration != null) { - enableAudit = picketLinkConfiguration.isEnableAudit(); - - //See if we have the system property enabled - if(!enableAudit){ - String sysProp = SecurityActions.getSystemProperty(GeneralConstants.AUDIT_ENABLE, "NULL"); - if(!"NULL".equals(sysProp)){ - enableAudit = Boolean.parseBoolean(sysProp); - } - } - - if (enableAudit) { - if (auditHelper == null) { - String securityDomainName = PicketLinkAuditHelper.getSecurityDomainName(servletContext); - - auditHelper = new PicketLinkAuditHelper(securityDomainName); - } - } - } - - if (StringUtil.isNotNull(spConfiguration.getIdpMetadataFile())) { - processIDPMetadataFile(spConfiguration.getIdpMetadataFile()); - } else { - this.identityURL = spConfiguration.getIdentityURL(); - } - this.serviceURL = spConfiguration.getServiceURL(); - this.canonicalizationMethod = spConfiguration.getCanonicalizationMethod(); - - logger.samlSPSettingCanonicalizationMethod(canonicalizationMethod); - XMLSignatureUtil.setCanonicalizationMethodType(canonicalizationMethod); - - logger.trace("Identity Provider URL=" + this.identityURL); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - protected IDPSSODescriptorType handleMetadata(EntitiesDescriptorType entities) { - IDPSSODescriptorType idpSSO = null; - - List entityDescs = entities.getEntityDescriptor(); - for (Object entityDescriptor : entityDescs) { - if (entityDescriptor instanceof EntitiesDescriptorType) { - idpSSO = getIDPSSODescriptor(entities); - } else - idpSSO = handleMetadata((EntityDescriptorType) entityDescriptor); - if (idpSSO != null) - break; - } - return idpSSO; - } - - protected IDPSSODescriptorType handleMetadata(EntityDescriptorType entityDescriptor) { - return CoreConfigUtil.getIDPDescriptor(entityDescriptor); - } - - protected IDPSSODescriptorType getIDPSSODescriptor(EntitiesDescriptorType entities) { - List entityDescs = entities.getEntityDescriptor(); - for (Object entityDescriptor : entityDescs) { - - if (entityDescriptor instanceof EntitiesDescriptorType) { - return getIDPSSODescriptor((EntitiesDescriptorType) entityDescriptor); - } - return CoreConfigUtil.getIDPDescriptor((EntityDescriptorType) entityDescriptor); - } - return null; - } - - protected void initializeHandlerChain() throws ConfigurationException, ProcessingException { - populateChainConfig(); - SAML2HandlerChainConfig handlerChainConfig = new DefaultSAML2HandlerChainConfig(chainConfigOptions); - - Set samlHandlers = chain.handlers(); - - for (SAML2Handler handler : samlHandlers) { - handler.initChainConfig(handlerChainConfig); - } - } - - protected void populateChainConfig() throws ConfigurationException, ProcessingException { - chainConfigOptions.put(GeneralConstants.CONFIGURATION, spConfiguration); - chainConfigOptions.put(GeneralConstants.ROLE_VALIDATOR_IGNORE, "false"); // No validator as tomcat realm does validn - - if (doSupportSignature()) { - chainConfigOptions.put(GeneralConstants.KEYPAIR, keyManager.getSigningKeyPair()); - //If there is a need for X509Data in signedinfo - String certificateAlias = (String)keyManager.getAdditionalOption(GeneralConstants.X509CERTIFICATE); - if(certificateAlias != null){ - chainConfigOptions.put(GeneralConstants.X509CERTIFICATE, keyManager.getCertificate(certificateAlias)); - } - } - } - - protected void sendToLogoutPage(Request request, Response response, Session session) throws IOException, ServletException { - // we are invalidated. - RequestDispatcher dispatch = context.getServletContext().getRequestDispatcher(this.getConfiguration().getLogOutPage()); - if (dispatch == null) - logger.samlSPCouldNotDispatchToLogoutPage(this.getConfiguration().getLogOutPage()); - else { - logger.trace("Forwarding request to logOutPage: " + this.getConfiguration().getLogOutPage()); - session.expire(); - try { - dispatch.forward(request, response); - } catch (Exception e) { - // JBAS5.1 and 6 quirkiness - dispatch.forward(request.getRequest(), response); - } - } - } - - // Mock test purpose - public void testStart() throws LifecycleException { - this.saveRestoreRequest = false; - if (context == null) - throw new RuntimeException("Catalina Context not set up"); - startPicketLink(); - } - - protected void startPicketLink() throws LifecycleException { - SystemPropertiesUtil.ensure(); - Handlers handlers = null; - - //Introduce a timer to reload configuration if desired - if(timerInterval > 0 ){ - if(timer == null){ - timer = new Timer(); - } - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - //Clear the configuration - picketLinkConfiguration = null; - spConfiguration = null; - - processConfiguration(); - try { - initKeyProvider(context); - } catch (LifecycleException e) { - logger.trace(e.getMessage()); - } - } - }, timerInterval, timerInterval); - } - - // Get the chain from config - if (StringUtil.isNullOrEmpty(samlHandlerChainClass)) { - chain = SAML2HandlerChainFactory.createChain(); - } else { - try { - chain = SAML2HandlerChainFactory.createChain(this.samlHandlerChainClass); - } catch (ProcessingException e1) { - throw new LifecycleException(e1); - } - } - - ServletContext servletContext = context.getServletContext(); - - this.processConfiguration(); - - try { - if (picketLinkConfiguration != null) { - handlers = picketLinkConfiguration.getHandlers(); - } else { - // Get the handlers - String handlerConfigFileName = GeneralConstants.HANDLER_CONFIG_FILE_LOCATION; - handlers = ConfigurationUtil.getHandlers(servletContext.getResourceAsStream(handlerConfigFileName)); - } - - chain.addAll(HandlerUtil.getHandlers(handlers)); - - this.initKeyProvider(context); - this.populateChainConfig(); - this.initializeHandlerChain(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - if (this.picketLinkConfiguration == null) { - this.picketLinkConfiguration = new PicketLinkType(); - - this.picketLinkConfiguration.setIdpOrSP(getConfiguration()); - this.picketLinkConfiguration.setHandlers(handlers); - } - } - - /** - *

- * Indicates if digital signatures/validation of SAML assertions are enabled. Subclasses that supports signature should - * override this method. - *

- * - * @return true if SP Configuration supports signature - */ - protected boolean doSupportSignature() { - if (spConfiguration != null) { - return spConfiguration.isSupportsSignature(); - } - return false; - } - - protected abstract void initKeyProvider(Context context) throws LifecycleException; - - public void setAuditHelper(PicketLinkAuditHelper auditHelper) { - this.auditHelper = auditHelper; - } -} diff --git a/saml/gatein-saml-plugin/src/test/java/org/gatein/sso/saml/plugin/filter/PortalIDPWebBrowserSSOFilterTest.java b/saml/gatein-saml-plugin/src/test/java/org/gatein/sso/saml/plugin/filter/PortalIDPWebBrowserSSOFilterTest.java deleted file mode 100644 index 85b298ac0..000000000 --- a/saml/gatein-saml-plugin/src/test/java/org/gatein/sso/saml/plugin/filter/PortalIDPWebBrowserSSOFilterTest.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.gatein.sso.saml.plugin.filter; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.startsWith; -import static org.mockito.Mockito.doCallRealMethod; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.mockito.internal.verification.VerificationModeFactory; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.picketlink.common.constants.GeneralConstants; -import org.picketlink.identity.federation.web.filters.IDPFilter; - -import junit.framework.TestCase; - -public class PortalIDPWebBrowserSSOFilterTest extends TestCase { - - public void testLoginRedirect() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - HttpSession httpSession = mock(HttpSession.class); - FilterChain chain = mock(FilterChain.class); - - FilterConfig filterConfig = mock(FilterConfig.class); - ServletContext servletContext = mock(ServletContext.class); - - PortalIDPWebBrowserSSOFilter idpWebBrowserSSOFilter = mock(PortalIDPWebBrowserSSOFilter.class); - - // When - when(response.encodeRedirectURL(any())).thenAnswer(new Answer() { - public String answer(InvocationOnMock invocation) throws Throwable { - return (String) invocation.getArguments()[0]; - } - }); - when(request.getSession()).thenReturn(httpSession); - when(request.getSession(anyBoolean())).thenReturn(httpSession); - when(request.getParameter(GeneralConstants.SAML_REQUEST_KEY)).thenReturn("SOME SAML REQUEST"); - when(request.getRequestURI()).thenReturn("/portal"); - when(httpSession.getId()).thenReturn("fakeHttpSession"); - when(filterConfig.getServletContext()).thenReturn(servletContext); - when(servletContext.getServletContextName()).thenReturn("portal"); - when(servletContext.getContextPath()).thenReturn("/portal"); - when(request.getContextPath()).thenReturn("/portal"); - - doNothing().when(((IDPFilter)idpWebBrowserSSOFilter)).doFilter(request, response, chain); - doCallRealMethod().when(idpWebBrowserSSOFilter).doFilter(request, response, chain); - - idpWebBrowserSSOFilter.init(filterConfig); - idpWebBrowserSSOFilter.doFilter(request, response, chain); - // Then - verify(response, VerificationModeFactory.times(1)).sendRedirect(startsWith("/portal/dologin?initialURI=")); - verify(chain, VerificationModeFactory.times(0)).doFilter(request, response); - } - - public void testSAMLLogin() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletRequest originalRequest = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - HttpSession httpSession = mock(HttpSession.class); - FilterChain chain = mock(FilterChain.class); - - FilterConfig filterConfig = mock(FilterConfig.class); - ServletContext servletContext = mock(ServletContext.class); - - PortalIDPWebBrowserSSOFilter idpWebBrowserSSOFilter = mock(PortalIDPWebBrowserSSOFilter.class); - - // When - when(response.encodeRedirectURL(any())).thenAnswer(new Answer() { - public String answer(InvocationOnMock invocation) throws Throwable { - return (String) invocation.getArguments()[0]; - } - }); - when(request.getSession()).thenReturn(httpSession); - when(request.getSession(anyBoolean())).thenReturn(httpSession); - when(httpSession.getAttribute(PortalIDPWebBrowserSSOFilter.ORIGINAL_HTTP_SERVLET_REQUEST_PARAM)).thenReturn(originalRequest); - when(request.getRequestURI()).thenReturn("/portal"); - when(httpSession.getId()).thenReturn("fakeHttpSession"); - when(filterConfig.getServletContext()).thenReturn(servletContext); - when(servletContext.getServletContextName()).thenReturn("portal"); - when(servletContext.getContextPath()).thenReturn("/portal"); - when(request.getContextPath()).thenReturn("/portal"); - when(idpWebBrowserSSOFilter.getInitParameter(GeneralConstants.ROLES)).thenReturn("users"); - - doNothing().when(((IDPFilter)idpWebBrowserSSOFilter)).doFilter(request, response, chain); - doCallRealMethod().when(idpWebBrowserSSOFilter).doFilter(request, response, chain); - - idpWebBrowserSSOFilter.init(filterConfig); - idpWebBrowserSSOFilter.doFilter(request, response, chain); - - // Then - verify(response, VerificationModeFactory.times(0)).sendRedirect(any()); - verify(chain, VerificationModeFactory.times(0)).doFilter(request, response); - verify(httpSession, VerificationModeFactory.times(1)).removeAttribute(PortalIDPWebBrowserSSOFilter.ORIGINAL_HTTP_SERVLET_REQUEST_PARAM); - } -} diff --git a/saml/gatein-saml-portal/pom.xml b/saml/gatein-saml-portal/pom.xml deleted file mode 100644 index c5f8e5d29..000000000 --- a/saml/gatein-saml-portal/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - sso-saml-parent - org.exoplatform.gatein.sso - 6.6.x-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.exoplatform.gatein.sso - sso-saml-pkg - pom - - GateIn SSO - SAML - Portal packaging - - - - - - org.exoplatform.gatein.sso - sso-common-plugin - - - org.exoplatform.gatein.sso - sso-saml-plugin - - - - - - - - maven-assembly-plugin - - - src/main/assembly/src.xml - - - - - make-assembly - package - - single - - - - - - - - diff --git a/saml/gatein-saml-portal/src/main/assembly/src.xml b/saml/gatein-saml-portal/src/main/assembly/src.xml deleted file mode 100644 index eacae708f..000000000 --- a/saml/gatein-saml-portal/src/main/assembly/src.xml +++ /dev/null @@ -1,28 +0,0 @@ - - sso-saml - - dir - - false - - - - src/main/resources/idp-sig.war - idp-sig.war - - - - - - idp-sig.war/WEB-INF/lib - false - false - - org.exoplatform.gatein.sso:sso-common-plugin - org.exoplatform.gatein.sso:sso-saml-plugin - - - - - diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/META-INF/MANIFEST.MF b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/META-INF/MANIFEST.MF deleted file mode 100644 index 50e874b2e..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/META-INF/MANIFEST.MF +++ /dev/null @@ -1,6 +0,0 @@ -Manifest-Version: 1.0 -Built-By: pedroigor -Build-Jdk: 1.7.0_05-icedtea -Created-By: Apache Maven 3.0.4 -Archiver-Version: Plexus Archiver - diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/META-INF/context.xml b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/META-INF/context.xml deleted file mode 100644 index 07d3f891e..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/META-INF/context.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/META-INF/jboss-deployment-structure.xml b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/META-INF/jboss-deployment-structure.xml deleted file mode 100644 index 312ce3b9e..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/META-INF/jboss-deployment-structure.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/classes/jbid_test_keystore.jks b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/classes/jbid_test_keystore.jks deleted file mode 100644 index 95c597b5b..000000000 Binary files a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/classes/jbid_test_keystore.jks and /dev/null differ diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/jboss-web.xml b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/jboss-web.xml deleted file mode 100644 index 45876ded4..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/jboss-web.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - idp - - - idp-sig - diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/picketlink.xml b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/picketlink.xml deleted file mode 100644 index 2d1bc2669..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/picketlink.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - ${idp-sig.url::http://localhost:8080/idp-sig/} - - ${sp.domains} - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/web.xml b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/web.xml deleted file mode 100644 index bec5e4f3b..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/WEB-INF/web.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - PicketLink Identity Provider - - PicketLink Identity Provider With a Basic Configuration - - - org.picketlink.identity.federation.web.listeners.IDPHttpSessionListener - - - - - IDPFilter - org.picketlink.identity.federation.web.filters.IDPFilter - - - - IDPFilter - /* - - - - - - Images - /images/* - - - CSS - /css/* - - - - - - - Manager command - /* - - - users - - - - - - FORM - PicketLink IDP Application - - /jsp/login.jsp - /jsp/login-error.jsp - - - - - - users - - diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/css/idp.css b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/css/idp.css deleted file mode 100644 index ba621a610..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/css/idp.css +++ /dev/null @@ -1,78 +0,0 @@ -/* - ~ JBoss, Home of Professional Open Source. - ~ Copyright (c) 2011, Red Hat, Inc., and individual contributors - ~ as indicated by the @author tags. See the copyright.txt file in the - ~ distribution for a full listing of individual contributors. - ~ - ~ This is free software; you can redistribute it and/or modify it - ~ under the terms of the GNU Lesser General Public License as - ~ published by the Free Software Foundation; either version 2.1 of - ~ the License, or (at your option) any later version. - ~ - ~ This software is distributed in the hope that it will be useful, - ~ but WITHOUT ANY WARRANTY; without even the implied warranty of - ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - ~ Lesser General Public License for more details. - ~ - ~ You should have received a copy of the GNU Lesser General Public - ~ License along with this software; if not, write to the Free - ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org. -*/ -body { - background: url(../images/rh_bg.png) repeat-x scroll 0 0 #F3F3F3; - color: #555555; - font: 12px/1.4 "Lucida Sans Unicode", "Lucida Grande", sans-serif; -} - -.loginBox { - position:absolute; - top: 50%; - left: 50%; - width:30em; - height:18em; - margin-top: -9em; /*set to a negative number 1/2 of your height*/ - margin-left: -15em; /*set to a negative number 1/2 of your width*/ - border: 1px solid #ccc; - background-color: #f3f3f3; -} - -.wrapper { - margin-left: auto; - margin-right: auto; - width: 50em; - text-align: left; -} - -a { - text-decoration: none; - color: #5e8a9a; -} - -h1 { - padding-top: 20px; - color: #7b1e1e; -} - -a:hover { - text-decoration: underline; - color: #8ec6d9; -} - -.content { - margin-left: 230px; -} - -.dualbrand { - padding-top: 20px; -} - -.as7 { - float: left; - margin-left: 10px; -} - -.note { - font-size: 8pt; - color: #aaaaaa; -} \ No newline at end of file diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/favicon.ico b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/favicon.ico deleted file mode 100644 index c31d0fa86..000000000 Binary files a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/favicon.ico and /dev/null differ diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/hosted/index.jsp b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/hosted/index.jsp deleted file mode 100644 index 56f24ac48..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/hosted/index.jsp +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Welcome to PicketLink Identity Provider - - - - - -

- Welcome to the PicketLink Identity Provider ! -

-

-

    -
  • SAML 2 Unsolicited Response: Sales SAML 2.0 (make sure you have deployed the sales-post-sig application)
  • -
-

- - - diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/images/bkg.gif b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/images/bkg.gif deleted file mode 100644 index 523877c08..000000000 Binary files a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/images/bkg.gif and /dev/null differ diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/images/picketlink-banner-1180px.png b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/images/picketlink-banner-1180px.png deleted file mode 100644 index 2509ff448..000000000 Binary files a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/images/picketlink-banner-1180px.png and /dev/null differ diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/images/rh_bg.png b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/images/rh_bg.png deleted file mode 100644 index b0e6a006d..000000000 Binary files a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/images/rh_bg.png and /dev/null differ diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/index.jsp b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/index.jsp deleted file mode 100644 index a17ba4d54..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/index.jsp +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Welcome to PicketLink Identity Provider - - - - - -

- Welcome to the PicketLink Identity Provider ! -

-

-

    -
  • SAML 2 Unsolicited Response: Sales SAML 2.0 (make sure you have deployed the sales-post-sig application)
  • -
-

- - - \ No newline at end of file diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/jsp/error.jsp b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/jsp/error.jsp deleted file mode 100644 index 43bb87450..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/jsp/error.jsp +++ /dev/null @@ -1,12 +0,0 @@ - Error! - - - - The username and password you supplied are not valid. -

-Click here -to retry login - - - - diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/jsp/login-error.jsp b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/jsp/login-error.jsp deleted file mode 100644 index c933f8064..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/jsp/login-error.jsp +++ /dev/null @@ -1,61 +0,0 @@ - - - - - -Welcome to JBoss Application Server 7 - - - - - -
-
-
-

- Welcome to the PicketLink Identity Provider -

-

Login failed, please try again.

-
- -
-

-
-

-

-
-

-
- -
-
-
-
- - \ No newline at end of file diff --git a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/jsp/login.jsp b/saml/gatein-saml-portal/src/main/resources/idp-sig.war/jsp/login.jsp deleted file mode 100644 index e41a550d6..000000000 --- a/saml/gatein-saml-portal/src/main/resources/idp-sig.war/jsp/login.jsp +++ /dev/null @@ -1,61 +0,0 @@ - - - - - -Welcome to JBoss Application Server 7 - - - - - -
-
-
-

- Welcome to the PicketLink Identity Provider -

-

Please login to proceed.

-
- -
-

-
-

-

-
-

-
- -
-
-
-
- - \ No newline at end of file diff --git a/saml/pom.xml b/saml/pom.xml deleted file mode 100644 index e58ac99bb..000000000 --- a/saml/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - org.exoplatform.gatein.sso - sso-parent - 6.6.x-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.exoplatform.gatein.sso - sso-saml-parent - pom - - GateIn SSO - SAML - - - gatein-saml-plugin - gatein-saml-portal - - - diff --git a/spnego/pom.xml b/spnego/pom.xml deleted file mode 100644 index ab86d8dec..000000000 --- a/spnego/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - org.exoplatform.gatein.sso - sso-parent - ../pom.xml - 6.6.x-SNAPSHOT - - - 4.0.0 - spnego - jar - GateIn SPNEGO LoginModule based on JBoss Negotiation - - - - org.exoplatform.core - exo.core.component.organization.api - - - org.jboss.security - jboss-negotiation-spnego - - - org.exoplatform.gatein.sso - sso-agent - - - - - - - - - - - run-its - - - - org.apache.maven.plugins - maven-surefire-plugin - - true - - - - - - - - diff --git a/spnego/src/main/java/org/gatein/sso/spnego/SPNEGOLoginModule.java b/spnego/src/main/java/org/gatein/sso/spnego/SPNEGOLoginModule.java deleted file mode 100644 index 7a17903ca..000000000 --- a/spnego/src/main/java/org/gatein/sso/spnego/SPNEGOLoginModule.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2011, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.gatein.sso.spnego; - -import org.exoplatform.services.security.jaas.UserPrincipal; -import org.jboss.security.negotiation.common.NegotiationContext; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; -import java.security.Principal; -import java.util.Map; -import java.util.Set; - -/** - * Modified version of {@link org.jboss.security.negotiation.spnego.SPNEGOLoginModule} customized for portal purposes - * - * @author Marek Posolda - */ -public class SPNEGOLoginModule extends org.jboss.security.negotiation.spnego.SPNEGOLoginModule -{ - private String usernamePasswordDomain; - - // TODO: Workaround. Remove once getIdentityFromSubject method will be added to superclass. - @Override - public void initialize(final Subject subject, final CallbackHandler callbackHandler, final Map sharedState, - final Map options) - { - super.initialize(subject, callbackHandler, sharedState, options); - usernamePasswordDomain = (String) options.get("usernamePasswordDomain"); - } - - // TODO: Workaround. Remove once getIdentityFromSubject method will be added to superclass. - @Override - protected Object innerLogin() throws LoginException - { - NegotiationContext negotiationContext = NegotiationContext.getCurrentNegotiationContext(); - - if (negotiationContext == null) - { - if (usernamePasswordDomain == null) - { - throw new LoginException("No NegotiationContext and no usernamePasswordDomain defined."); - } - - return usernamePasswordLogin(); - } - else - { - return super.innerLogin(); - } - } - - // TODO: Workaround. Remove once getIdentityFromSubject method will be added to superclass. - private Object usernamePasswordLogin() throws LoginException - { - log.debug("Falling back to username/password authentication"); - - LoginContext lc = new LoginContext(usernamePasswordDomain, callbackHandler); - lc.login(); - - Subject userSubject = lc.getSubject(); - - Principal identity = getIdentityFromSubject(userSubject); - setIdentity(identity); - - return Boolean.TRUE; - } - - - /** - * Obtaining identity from subject. We need to find instance of {@link UserPrincipal} - * , which is added here during FORM authentication. - * - * @param userSubject subject from FORM authentication - * @return identity - * @throws javax.security.auth.login.LoginException - */ - protected Principal getIdentityFromSubject(Subject userSubject) throws LoginException - { - Set principals = userSubject.getPrincipals(UserPrincipal.class); - if (principals.isEmpty()) - { - throw new LoginException("No UserPrincipals returned after login."); - } - else if (principals.size() > 1) - { - log.warn("Multiple UserPrincipals returned, using first principal in set."); - } - - Principal identity = (Principal) principals.iterator().next(); - return identity; - } -} diff --git a/spnegosso/README.md b/spnegosso/README.md deleted file mode 100644 index 50b4ad5c9..000000000 --- a/spnegosso/README.md +++ /dev/null @@ -1,43 +0,0 @@ -This is other spnego implementation beside https://github.com/gatein/gatein-sso/tree/master/spnego -We introduce new spnego implementation because existing implementation dose not work on gatein tomcat packaging. -This implementation work well on both jboss and tomcat packaging. - -###Build and configure - -1. Configure SPNEGO Server - You configure SPNEGO server follow the guideline at gatein document: https://docs.jboss.org/author/display/GTNPORTAL37/SPNEGO - -2. Build and deploy spnegosso - - Use maven to build gatein-spnego project - - Copy spnegosso-${VERSION}.jar to $GATEIN_TOMCAT/lib folder - -3. Configure gatein - - Append this login module configuration into $GATEIN_HOME/conf/jaas.conf -``` -spnego-server { - com.sun.security.auth.module.Krb5LoginModule required - storeKey=true - doNotPrompt=true - useKeyTab=true - keyTab="/etc/krb5.keytab" - principal="HTTP/server.local.network@LOCAL.NETWORK" - useFirstPass=true - debug=true - isInitiator=false; -}; -``` - - - Change SSO section in the file $GATEIN_HOME/gatein/conf/configuration.properties to be like this: -``` -gatein.sso.enabled=true -gatein.sso.filter.spnego.enabled=true -gatein.sso.callback.enabled=false -gatein.sso.skip.jsp.redirection=false -gatein.sso.login.module.enabled=true -gatein.sso.login.module.class=org.gatein.security.sso.spnego.SPNEGOSSOLoginModule -gatein.sso.filter.login.sso.url=/@@portal.container.name@@/spnegosso -gatein.sso.filter.initiatelogin.enabled=false -gatein.sso.valve.enabled=false -gatein.sso.filter.logout.enabled=false -``` - diff --git a/spnegosso/pom.xml b/spnegosso/pom.xml deleted file mode 100644 index 61a1fef89..000000000 --- a/spnegosso/pom.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - 4.0.0 - - - org.exoplatform.gatein.sso - sso-parent - ../pom.xml - 6.6.x-SNAPSHOT - - spnegosso - - - - javax.servlet - javax.servlet-api - - - org.exoplatform.gatein.sso - sso-agent - - - org.gatein.common - common-common - - - - diff --git a/spnegosso/src/main/java/org/gatein/security/sso/spnego/SPNEGOSSOFilter.java b/spnegosso/src/main/java/org/gatein/security/sso/spnego/SPNEGOSSOFilter.java deleted file mode 100644 index 2985c0c51..000000000 --- a/spnegosso/src/main/java/org/gatein/security/sso/spnego/SPNEGOSSOFilter.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2012 eXo Platform SAS. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.gatein.security.sso.spnego; - -import java.io.IOException; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.UUID; -import javax.security.auth.Subject; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; -import javax.servlet.FilterChain; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.gatein.common.util.Base64; -import org.gatein.sso.agent.filter.api.AbstractSSOInterceptor; -import org.ietf.jgss.GSSContext; -import org.ietf.jgss.GSSCredential; -import org.ietf.jgss.GSSException; -import org.ietf.jgss.GSSManager; -import org.ietf.jgss.Oid; - -public class SPNEGOSSOFilter extends AbstractSSOInterceptor { - private static final Log log = ExoLogger.getLogger(AbstractSSOInterceptor.class); - - private static final GSSManager MANAGER = GSSManager.getInstance(); - - private LoginContext loginContext; - private String[] patterns = {"/login", "/spnegosso"}; - private String loginServletPath = "/login"; - private String securityDomain = "spnego-server"; - - public SPNEGOSSOFilter() {} - - @Override - protected void initImpl() { - String patternParam = this.getInitParameter("patterns"); - if(patternParam != null && !patternParam.isEmpty()) { - this.patterns = patternParam.split(","); - } - - String loginServlet = this.getInitParameter("loginServletPath"); - if(loginServlet != null && !loginServlet.isEmpty()) { - this.loginServletPath = loginServlet; - } - - String domain = this.getInitParameter("securityDomain"); - if(domain != null && !domain.isEmpty()) { - this.securityDomain = domain; - } - - try { - this.loginContext = new LoginContext(this.securityDomain); - } catch (LoginException ex) { - log.warn("Exception while init LoginContext, so SPNEGO SSO will not work", ex); - } - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - final HttpServletRequest req = (HttpServletRequest)request; - final HttpServletResponse resp = (HttpServletResponse)response; - - //. Check if this is not spnego login request - if(!isSpnegoLoginRequest(req)) { - chain.doFilter(request, response); - return; - } - - SPNEGOSSOContext.setCurrentRequest(req); - final String contextPath = req.getContextPath(); - final String loginURI = contextPath + this.loginServletPath; - final String requestURI = req.getRequestURI(); - String username = req.getParameter("username"); - final String remoteUser = req.getRemoteUser(); - - if(username != null || remoteUser != null) { - if(!loginURI.equalsIgnoreCase(requestURI)) { - // Redirect to /login if current request is /spnegosso to avoid error 404 - // when user access to /spnegosso?username=username or when loggedIn user access to /spengosso - StringBuilder login = new StringBuilder(loginURI); - if(req.getQueryString() != null) { - login.append("?").append(req.getQueryString()); - } - resp.sendRedirect(login.toString()); - } else { - chain.doFilter(req, resp); - } - return; - } - - String principal = null; - final String auth = req.getHeader("Authorization"); - if(auth != null) { - try { - principal = this.login(req, resp, auth); - } catch (Exception ex) { - log.error("Exception occur when trying to login with SPNEGO", ex); - } - } - - if(principal != null && !principal.isEmpty()) { - username = principal.substring(0, principal.indexOf('@')); - // We don't need user password when he login using SSO (SPNEGO) - // But LoginServlet require password is not empty to call login action instead of display input form - // So, we need to generate a random password - String password = UUID.randomUUID().toString(); - - HttpSession session = req.getSession(); - session.setAttribute("SPNEGO_PRINCIPAL", username); - - StringBuilder login = new StringBuilder(loginURI) - .append("?username=") - .append(username) - .append("&password=") - .append(password); - String initURL = req.getParameter("initialURI"); - if(initURL != null) { - login.append("&initialURI=").append(initURL); - } - - resp.sendRedirect(login.toString()); - } else { - if(!loginURI.equals(requestURI)) { - RequestDispatcher dispatcher = req.getRequestDispatcher("/login"); - dispatcher.include(req, resp); - } else { - chain.doFilter(req, resp); - } - resp.setHeader("WWW-Authenticate", "Negotiate"); - resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - } - } - - private boolean isSpnegoLoginRequest(HttpServletRequest request) { - final String uri = request.getRequestURI(); - final String context = request.getContextPath(); - for(String pattern : this.patterns) { - if(uri.equals(context.concat(pattern))) { - return true; - } - } - return false; - } - - private String login(HttpServletRequest req, HttpServletResponse resp, String auth) throws Exception { - if(this.loginContext == null) { - return null; - } - this.loginContext.login(); - - final String principal; - final String tok = auth.substring("Negotiate".length() + 1); - final byte[] gss = Base64.decode(tok); - - GSSContext context = null; - byte[] token = null; - context = MANAGER.createContext(getServerCredential(loginContext.getSubject())); - token = context.acceptSecContext(gss, 0, gss.length); - - if (null == token) { - return null; - } - - resp.setHeader("WWW-Authenticate", "Negotiate" + ' ' + Base64.encodeBytes(token)); - - if (!context.isEstablished()) { - resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - return null; - } - - principal = context.getSrcName().toString(); - context.dispose(); - - this.loginContext.logout(); - - return principal; - } - - - /** - * Returns the {@link org.ietf.jgss.GSSCredential} the server uses for pre-authentication. - * - * @param subject account server uses for pre-authentication - * @return credential that allows server to authenticate clients - * @throws java.security.PrivilegedActionException - */ - static GSSCredential getServerCredential(final Subject subject) - throws PrivilegedActionException { - - final PrivilegedExceptionAction action = - new PrivilegedExceptionAction() { - public GSSCredential run() throws GSSException { - return MANAGER.createCredential( - null - , GSSCredential.INDEFINITE_LIFETIME - , getOid() - , GSSCredential.ACCEPT_ONLY); - } - }; - return Subject.doAs(subject, action); - } - - /** - * Returns the Universal Object Identifier representation of - * the SPNEGO mechanism. - * - * @return Object Identifier of the GSS-API mechanism - */ - private static Oid getOid() { - Oid oid = null; - try { - oid = new Oid("1.3.6.1.5.5.2"); - } catch (GSSException gsse) { - gsse.printStackTrace(); - } - return oid; - } - - @Override - public void destroy() {} -} diff --git a/spnegosso/src/main/java/org/gatein/security/sso/spnego/SPNEGOSSOLoginModule.java b/spnegosso/src/main/java/org/gatein/security/sso/spnego/SPNEGOSSOLoginModule.java deleted file mode 100644 index 0227c18ab..000000000 --- a/spnegosso/src/main/java/org/gatein/security/sso/spnego/SPNEGOSSOLoginModule.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2012 eXo Platform SAS. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.gatein.security.sso.spnego; - -import javax.security.auth.login.LoginException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import org.exoplatform.container.ExoContainer; -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.exoplatform.services.security.Authenticator; -import org.exoplatform.services.security.Identity; -import org.exoplatform.services.security.UsernameCredential; -import org.exoplatform.services.security.jaas.AbstractLoginModule; - -public class SPNEGOSSOLoginModule extends AbstractLoginModule { - private static final Log log = ExoLogger.getLogger(SPNEGOSSOLoginModule.class); - - public static final String OPTION_ENABLE_FALLBACK_FORM_AUTHENTICATION = "enableFormAuthentication"; - - @Override - protected Log getLogger() { - return log; - } - - @Override - public boolean login() throws LoginException { - try { - ExoContainer container = getContainer(); - - HttpServletRequest servletRequest = SPNEGOSSOContext.getCurrentRequest(); - if (servletRequest == null) { - log.debug("HttpServletRequest is null. SPNEGOLoginModule will be ignored."); - return false; - } - - HttpSession session = servletRequest.getSession(); - String username = (String)session.getAttribute("SPNEGO_PRINCIPAL"); - if(username != null) { - establishSecurityContext(container, username); - if (log.isTraceEnabled()) { - log.trace("Successfully established security context for user " + username); - } - return true; - } - - } catch (Exception ex) { - log.error("Exception when trying to login with SPNEGO", ex); - } - - // Disable fallback to FORM authentication - if("false".equalsIgnoreCase((String)this.options.get(OPTION_ENABLE_FALLBACK_FORM_AUTHENTICATION))) { - throw new LoginException("FORM authentication was disabled by SPNEGO login module."); - } - - return false; - } - - @Override - public boolean commit() throws LoginException { - return true; - } - - @Override - public boolean abort() throws LoginException { - return true; - } - - @Override - public boolean logout() throws LoginException { - return true; - } - - protected void establishSecurityContext(ExoContainer container, String username) throws Exception { - Authenticator authenticator = container.getComponentInstanceOfType(Authenticator.class); - - if (authenticator == null) { - throw new LoginException("No Authenticator component found, check your configuration"); - } - - Identity identity = authenticator.createIdentity(username); - - sharedState.put("exo.security.identity", identity); - sharedState.put("javax.security.auth.login.name", username); - subject.getPublicCredentials().add(new UsernameCredential(username)); - } -} diff --git a/spnegosso/src/main/resources/conf/portal/configuration.xml b/spnegosso/src/main/resources/conf/portal/configuration.xml deleted file mode 100644 index 6ac3b3280..000000000 --- a/spnegosso/src/main/resources/conf/portal/configuration.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - org.gatein.sso.integration.SSOFilterIntegrator - - SSOFilterIntegratorPlugin - addPlugin - org.gatein.sso.integration.SSOFilterIntegratorPlugin - - - filterClass - org.gatein.security.sso.spnego.SPNEGOSSOFilter - - - enabled - ${gatein.sso.filter.spnego.enabled:false} - - - filterMapping - /* - - - - patterns - ${gatein.sso.filter.spnego.pattern:/login,/spnegosso} - - - loginServletPath - ${gatein.sso.filter.spnego.loginServletPath:/login} - - - securityDomain - ${gatein.sso.filter.spnego.securityDomain:spnego-server} - - - - - diff --git a/sso-agent/pom.xml b/sso-agent/pom.xml new file mode 100644 index 000000000..1c88dbf75 --- /dev/null +++ b/sso-agent/pom.xml @@ -0,0 +1,61 @@ + + + org.exoplatform.gatein.sso + sso-parent + 6.6.x-SNAPSHOT + + + 4.0.0 + sso-agent + jar + GateIn SSO - Agent + + + 0.01 + + + + + + org.apache.tomcat + tomcat-catalina + provided + + + org.exoplatform.core + exo.core.component.organization.api + provided + + + org.exoplatform.gatein.wci + wci-wci + provided + + + org.exoplatform.ws + exo.ws.rest.core + provided + + + org.gatein.common + common-common + provided + + + org.apache.httpcomponents + httpclient + provided + + + org.mockito + mockito-core + test + + + junit + junit + test + + + + diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java b/sso-agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java similarity index 90% rename from agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java rename to sso-agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java index ef0563dc8..d81dd2677 100644 --- a/agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java +++ b/sso-agent/src/main/java/org/gatein/sso/agent/filter/LoginRedirectFilter.java @@ -27,12 +27,12 @@ import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; /** diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/api/AbstractSSOInterceptor.java b/sso-agent/src/main/java/org/gatein/sso/agent/filter/api/AbstractSSOInterceptor.java similarity index 98% rename from agent/src/main/java/org/gatein/sso/agent/filter/api/AbstractSSOInterceptor.java rename to sso-agent/src/main/java/org/gatein/sso/agent/filter/api/AbstractSSOInterceptor.java index 735c93c43..304167ab8 100644 --- a/agent/src/main/java/org/gatein/sso/agent/filter/api/AbstractSSOInterceptor.java +++ b/sso-agent/src/main/java/org/gatein/sso/agent/filter/api/AbstractSSOInterceptor.java @@ -30,8 +30,8 @@ import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; /** * Base {@link SSOInterceptor} which adds possibility to be initialized either through Servlet API or through eXo kernel diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptor.java b/sso-agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptor.java similarity index 97% rename from agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptor.java rename to sso-agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptor.java index 72117cee0..0ea02e424 100644 --- a/agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptor.java +++ b/sso-agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptor.java @@ -26,7 +26,7 @@ import org.exoplatform.container.ExoContainerContext; import org.exoplatform.container.xml.InitParams; -import javax.servlet.Filter; +import jakarta.servlet.Filter; /** * SSOInterceptor is actually filter, which can be configured through exo kernel diff --git a/agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptorInitializationContext.java b/sso-agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptorInitializationContext.java similarity index 98% rename from agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptorInitializationContext.java rename to sso-agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptorInitializationContext.java index fce90064d..1004ecba9 100644 --- a/agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptorInitializationContext.java +++ b/sso-agent/src/main/java/org/gatein/sso/agent/filter/api/SSOInterceptorInitializationContext.java @@ -29,7 +29,7 @@ import org.exoplatform.container.xml.InitParams; import org.exoplatform.container.xml.ValueParam; -import javax.servlet.FilterConfig; +import jakarta.servlet.FilterConfig; /** * Context, which encapsulates all initialization configuration about {@link SSOInterceptor} and is able to recognize diff --git a/sso-agent/src/main/java/org/gatein/sso/agent/login/SSOLoginModule.java b/sso-agent/src/main/java/org/gatein/sso/agent/login/SSOLoginModule.java new file mode 100644 index 000000000..f51a5e516 --- /dev/null +++ b/sso-agent/src/main/java/org/gatein/sso/agent/login/SSOLoginModule.java @@ -0,0 +1,151 @@ +/* + * JBoss, a division of Red Hat + * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.gatein.sso.agent.login; + +import java.lang.reflect.Method; + +import javax.security.auth.login.LoginException; + +import org.gatein.sso.agent.tomcat.ServletAccess; +import org.gatein.wci.security.Credentials; + +import org.exoplatform.services.log.ExoLogger; +import org.exoplatform.services.log.Log; +import org.exoplatform.services.security.Authenticator; +import org.exoplatform.services.security.Identity; +import org.exoplatform.services.security.UsernameCredential; +import org.exoplatform.services.security.jaas.AbstractLoginModule; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * @author Sohil Shah + */ +public final class SSOLoginModule extends AbstractLoginModule { + + private static final Log log = ExoLogger.getLogger(SSOLoginModule.class); + + public static final String AUTHENTICATED_CREDENTIALS = "authenticatedCredentials"; + + /** JACC get context method. */ + private static Method getContextMethod; + + static { + try { + Class policyContextClass = Thread.currentThread().getContextClassLoader().loadClass("javax.security.jacc.PolicyContext"); + getContextMethod = policyContextClass.getDeclaredMethod("getContext", String.class); + } catch (ClassNotFoundException ignore) { + log.debug("JACC not found ignoring it", ignore); + } catch (Exception e) { + log.error("Could not obtain JACC get context method", e); + } + } + + public boolean login() throws LoginException { + try { + // Check credentials stored and propagated in session. + String username = null; + HttpServletRequest request = getCurrentHttpServletRequest(); + + if (request == null) { + log.debug("HttpServletRequest is null. SSOLoginModule will be ignored."); + return false; + } + + Credentials credsFromSession = (Credentials) request.getSession().getAttribute(AUTHENTICATED_CREDENTIALS); + if (credsFromSession != null) { + username = credsFromSession.getUsername(); + if (log.isTraceEnabled()) { + log.trace("Found credentials in session. Username: " + username); + } + } + + if (username == null) { + // SSO token could not be validated...hence a user id cannot be found + log.debug("SSOLogin Failed. Credential Not Found!!"); + return false; + } + + // Perform authentication by setting up the proper Application State + Authenticator authenticator = (Authenticator) getContainer() + .getComponentInstanceOfType(Authenticator.class); + + if (authenticator == null) { + throw new LoginException( + "No Authenticator component found, check your configuration"); + } + + Identity identity = authenticator.createIdentity(username); + + sharedState.put("exo.security.identity", identity); + sharedState.put("javax.security.auth.login.name", username); + subject.getPublicCredentials().add(new UsernameCredential(username)); + + return true; + } catch (final Throwable e) { + throw new LoginException(e.getMessage()); + } + } + + public boolean logout() throws LoginException { + return true; + } + + public boolean abort() throws LoginException { + return true; + } + + public boolean commit() throws LoginException { + return true; + } + + @Override + protected Log getLogger() { + return log; + } + + protected HttpServletRequest getCurrentHttpServletRequest() { + HttpServletRequest request = null; + + // JBoss way + if (getContextMethod != null) { + try { + request = (HttpServletRequest) getContextMethod.invoke(null, "jakarta.servlet.http.HttpServletRequest"); + } catch (Throwable e) { + log.error("LoginModule error. Turn off session credentials checking with proper configuration option of " + + "LoginModule set to false"); + log.error(this, e); + } + } + // Tomcat way (Assumed that ServletAccessValve has been configured in + // context.xml) + else { + request = ServletAccess.getRequest(); + } + + if (log.isTraceEnabled()) { + log.trace("Returning HttpServletRequest " + request); + } + + return request; + } +} diff --git a/agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccess.java b/sso-agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccess.java similarity index 95% rename from agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccess.java rename to sso-agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccess.java index 15c909732..c21c51ffc 100644 --- a/agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccess.java +++ b/sso-agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccess.java @@ -22,8 +22,8 @@ package org.gatein.sso.agent.tomcat; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; /** * @author Marek Posolda diff --git a/agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccessValve.java b/sso-agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccessValve.java similarity index 92% rename from agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccessValve.java rename to sso-agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccessValve.java index 60c3a6157..675698c6e 100644 --- a/agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccessValve.java +++ b/sso-agent/src/main/java/org/gatein/sso/agent/tomcat/ServletAccessValve.java @@ -28,11 +28,11 @@ import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; -import javax.servlet.ServletException; +import jakarta.servlet.ServletException; import java.io.IOException; /** - * Valve for adding {@link javax.servlet.http.HttpServletRequest} and {@link javax.servlet.http.HttpServletResponse} into threadLocal + * Valve for adding {@link jakarta.servlet.http.HttpServletRequest} and {@link jakarta.servlet.http.HttpServletResponse} into threadLocal * so that it can be accessed from Login Modules during authentication. * * @author Marek Posolda diff --git a/integration/src/main/java/org/gatein/sso/integration/SSODelegateFilter.java b/sso-agent/src/main/java/org/gatein/sso/integration/SSODelegateFilter.java similarity index 95% rename from integration/src/main/java/org/gatein/sso/integration/SSODelegateFilter.java rename to sso-agent/src/main/java/org/gatein/sso/integration/SSODelegateFilter.java index 4107bab19..158980534 100644 --- a/integration/src/main/java/org/gatein/sso/integration/SSODelegateFilter.java +++ b/sso-agent/src/main/java/org/gatein/sso/integration/SSODelegateFilter.java @@ -28,11 +28,11 @@ import org.exoplatform.services.log.Log; import org.gatein.sso.agent.filter.api.SSOInterceptor; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Iterator; import java.util.Map; diff --git a/integration/src/main/java/org/gatein/sso/integration/SSODelegateLoginModule.java b/sso-agent/src/main/java/org/gatein/sso/integration/SSODelegateLoginModule.java similarity index 100% rename from integration/src/main/java/org/gatein/sso/integration/SSODelegateLoginModule.java rename to sso-agent/src/main/java/org/gatein/sso/integration/SSODelegateLoginModule.java diff --git a/integration/src/main/java/org/gatein/sso/integration/SSODelegateValve.java b/sso-agent/src/main/java/org/gatein/sso/integration/SSODelegateValve.java similarity index 98% rename from integration/src/main/java/org/gatein/sso/integration/SSODelegateValve.java rename to sso-agent/src/main/java/org/gatein/sso/integration/SSODelegateValve.java index 138999a33..c72eaa110 100644 --- a/integration/src/main/java/org/gatein/sso/integration/SSODelegateValve.java +++ b/sso-agent/src/main/java/org/gatein/sso/integration/SSODelegateValve.java @@ -29,7 +29,7 @@ import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.ObjectName; -import javax.servlet.ServletException; +import jakarta.servlet.ServletException; import org.apache.catalina.Contained; import org.apache.catalina.Container; @@ -47,7 +47,7 @@ * Delegates work to another valve configured through option 'delegateValveClassName'. It's possible to disable * delegation by boolean parameter 'ssoDelegationEnabled'. * - * Actually delegation will be enabled only for SSO scenario, which require integration with Tomcat valves (SAML, SPNEGO) + * Actually delegation will be enabled only for SSO scenario, which require integration with Tomcat valves (SAML) * * @author Marek Posolda */ @@ -64,7 +64,7 @@ public class SSODelegateValve implements Valve, Contained, MBeanRegistration, Li private String delegateValveClassName; // Delegate valve is not null only if we are in SSO mode and delegation is enabled - // Delegate will be either SAML or SPNEGO valve + // Delegate will be either SAML valve private Valve delegate; // This is not null only if delegation is disabled diff --git a/integration/src/main/java/org/gatein/sso/integration/SSOFilterIntegrator.java b/sso-agent/src/main/java/org/gatein/sso/integration/SSOFilterIntegrator.java similarity index 97% rename from integration/src/main/java/org/gatein/sso/integration/SSOFilterIntegrator.java rename to sso-agent/src/main/java/org/gatein/sso/integration/SSOFilterIntegrator.java index 764d296b3..b77483b50 100644 --- a/integration/src/main/java/org/gatein/sso/integration/SSOFilterIntegrator.java +++ b/sso-agent/src/main/java/org/gatein/sso/integration/SSOFilterIntegrator.java @@ -1,41 +1,41 @@ -/* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.gatein.sso.integration; - -import org.gatein.sso.agent.filter.api.SSOInterceptor; - -import java.util.Map; - -/** - * Kernel component, which holds references to all configured {@link org.gatein.sso.agent.filter.api.SSOInterceptor} - * instances - * - * @author Marek Posolda - */ -public interface SSOFilterIntegrator -{ - - public Map getSSOInterceptors(); - -} +/* + * JBoss, a division of Red Hat + * Copyright 2012, Red Hat Middleware, LLC, and individual + * contributors as indicated by the @authors tag. See the + * copyright.txt in the distribution for a full listing of + * individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.gatein.sso.integration; + +import org.gatein.sso.agent.filter.api.SSOInterceptor; + +import java.util.Map; + +/** + * Kernel component, which holds references to all configured {@link org.gatein.sso.agent.filter.api.SSOInterceptor} + * instances + * + * @author Marek Posolda + */ +public interface SSOFilterIntegrator +{ + + public Map getSSOInterceptors(); + +} diff --git a/integration/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorImpl.java b/sso-agent/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorImpl.java similarity index 100% rename from integration/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorImpl.java rename to sso-agent/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorImpl.java diff --git a/integration/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorPlugin.java b/sso-agent/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorPlugin.java similarity index 99% rename from integration/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorPlugin.java rename to sso-agent/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorPlugin.java index ab02e356b..d926c0be5 100644 --- a/integration/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorPlugin.java +++ b/sso-agent/src/main/java/org/gatein/sso/integration/SSOFilterIntegratorPlugin.java @@ -37,8 +37,7 @@ * * @author Marek Posolda */ -public class SSOFilterIntegratorPlugin extends BaseComponentPlugin -{ +public class SSOFilterIntegratorPlugin extends BaseComponentPlugin { private final SSOInterceptor filter; private final boolean enabled; private final String filterMapping; diff --git a/integration/src/main/java/org/gatein/sso/integration/SSOUtils.java b/sso-agent/src/main/java/org/gatein/sso/integration/SSOUtils.java similarity index 100% rename from integration/src/main/java/org/gatein/sso/integration/SSOUtils.java rename to sso-agent/src/main/java/org/gatein/sso/integration/SSOUtils.java diff --git a/integration/src/test/java/org/gatein/sso/integration/SSODelegateFilterTest.java b/sso-agent/src/test/java/org/gatein/sso/integration/SSODelegateFilterTest.java similarity index 100% rename from integration/src/test/java/org/gatein/sso/integration/SSODelegateFilterTest.java rename to sso-agent/src/test/java/org/gatein/sso/integration/SSODelegateFilterTest.java diff --git a/sso-saml-plugin/pom.xml b/sso-saml-plugin/pom.xml new file mode 100644 index 000000000..85956e6ff --- /dev/null +++ b/sso-saml-plugin/pom.xml @@ -0,0 +1,434 @@ + + + org.exoplatform.gatein.sso + sso-parent + 6.6.x-SNAPSHOT + + + 4.0.0 + sso-saml-plugin + jar + + GateIn SSO - SAML Identity provider plugin + + + 2.5.5.Final + 4.0.20.Final + 1.5.1 + 2.0.8.Final + 2.0.4 + 2.0.3.GA + + 1.0.0.Final + 1.0.1.Final + 1.0.1.Final + 2.0.3.Final + 1.0.2.Final + + 0 + true + + + + + + + org.picketlink + picketlink-parent + ${org.picketlink.federation.version} + import + pom + + + org.picketlink + picketlink-jbas-common + ${org.picketlink.federation.version} + sources + + + org.picketlink + picketlink-common + sources + ${org.picketlink.federation.version} + + + * + * + + + + + org.picketlink + picketlink-config + sources + ${org.picketlink.federation.version} + + + * + * + + + + + org.picketlink + picketlink-federation + sources + ${org.picketlink.federation.version} + + + * + * + + + + + org.picketbox + picketbox + sources + ${org.picketbox.version} + + + * + * + + + + + + + org.jboss + jbossxb + ${org.jboss.jbossxb.version} + + + org.jboss.security + jbosssx + ${org.jboss.security.jbosssx.version} + + + org.jboss.security + jbossxacml + ${org.jboss.security.jbossxacml.version} + + + org.jboss.spec.javax.resource + jboss-connector-api_1.7_spec + ${org.jboss.spec.javax.resource.version} + + + org.jboss.spec.javax.security.jacc + jboss-jacc-api_1.5_spec + ${org.jboss.spec.javax.security.jacc.version} + + + org.jboss.spec.javax.servlet + jboss-servlet-api_3.1_spec + + + + + org.jboss.spec.javax.security.auth.message + jboss-jaspi-api_1.0_spec + ${org.jboss.spec.javax.security.auth.message.version} + + + org.jboss.spec.javax.xml.ws + jboss-jaxws-api_2.2_spec + ${org.jboss.spec.javax.xml.ws.version} + + + org.jboss.spec.javax.xml.soap + jboss-saaj-api_1.4_spec + ${org.jboss.spec.javax.xml.soap.version} + + + org.apache.santuario + xmlsec + ${org.apache.santuario.version} + + + javax.servlet + servlet-api + + + + + + + + + + ${project.groupId} + sso-agent + + + + org.apache.tomcat + tomcat-catalina + + + + org.picketlink + picketlink-common + sources + + + org.picketlink + picketlink-config + sources + + + org.picketlink + picketlink-federation + sources + + + org.picketlink + picketlink-jbas-common + sources + + + org.picketbox + picketbox + sources + + + + org.exoplatform.ws + exo.ws.rest.core + provided + + + org.hibernate + hibernate-core + provided + + + javax.annotation + jsr250-api + + + javax.enterprise + cdi-api + + + + org.jboss.spec.javax.resource + jboss-connector-api_1.7_spec + + + org.jboss.spec.javax.security.jacc + jboss-jacc-api_1.5_spec + + + org.jboss.spec.javax.security.auth.message + jboss-jaspi-api_1.0_spec + + + org.jboss.spec.javax.xml.ws + jboss-jaxws-api_2.2_spec + + + org.jboss.spec.javax.xml.soap + jboss-saaj-api_1.4_spec + + + + org.jboss.logging + jboss-logging + + + org.jboss + jbossxb + + + org.jboss.security + jbossxacml + + + org.jboss.security + jbosssx + + + org.apache.santuario + xmlsec + + + + org.picketlink + picketlink-idm-impl + + + + org.apache.tomcat + tomcat-catalina + provided + + + + org.exoplatform.gatein.wci + wci-wci + + + org.exoplatform.ws + exo.ws.rest.core + + + org.exoplatform.core + exo.core.component.security.core + + + org.exoplatform.core + exo.core.component.organization.api + + + org.apache.httpcomponents + httpclient + + + org.mockito + mockito-core + test + + + junit + junit + test + + + + + ${project.artifactId} + + + src/main/java + + + src/main/resources + + + target/picketlink + + + + + src/test/java + + + src/test/resources + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack + generate-sources + + unpack + + + + + org.picketlink + picketlink-common + sources + false + + + org.picketlink + picketlink-config + sources + ${org.picketlink.federation.version} + false + + + org.picketlink + picketlink-federation + sources + ${org.picketlink.federation.version} + false + + + org.picketlink + picketlink-jbas-common + sources + ${org.picketlink.federation.version} + false + + + org.picketbox + picketbox + sources + ${org.picketbox.version} + false + + + ${project.build.directory}/picketlink + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + generate-sources + + add-source + + + + ${project.build.directory}/picketlink + + + + + + + org.apache.maven.plugins + maven-patch-plugin + 1.2 + + ${project.build.directory} + + + + java.security.acl.Group-patch + + + ${basedir}/src/main/patches/java.security.acl.Group.patch + + ${project.build.directory}/java.security.acl.Group-patches-applied.txt + skip + + process-resources + + apply + + + + javax.servlet-patch + + ${basedir}/src/main/patches/javax.servlet.patch + + ${project.build.directory}/javax.servlet-patches-applied.txt + + process-resources + + apply + + + + + + + + diff --git a/agent/src/main/java/org/gatein/sso/agent/login/SAML2IntegrationLoginModule.java b/sso-saml-plugin/src/main/java/org/gatein/sso/agent/login/SAML2IntegrationLoginModule.java similarity index 93% rename from agent/src/main/java/org/gatein/sso/agent/login/SAML2IntegrationLoginModule.java rename to sso-saml-plugin/src/main/java/org/gatein/sso/agent/login/SAML2IntegrationLoginModule.java index 7d1c2cfb7..b0622cd5f 100644 --- a/agent/src/main/java/org/gatein/sso/agent/login/SAML2IntegrationLoginModule.java +++ b/sso-saml-plugin/src/main/java/org/gatein/sso/agent/login/SAML2IntegrationLoginModule.java @@ -20,23 +20,26 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ - package org.gatein.sso.agent.login; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.login.LoginException; + +import org.picketlink.identity.federation.bindings.jboss.auth.SAML2LoginModule; + import org.exoplatform.container.ExoContainer; import org.exoplatform.container.ExoContainerContext; import org.exoplatform.container.PortalContainer; import org.exoplatform.container.RootContainer; +import org.exoplatform.services.log.ExoLogger; +import org.exoplatform.services.log.Log; import org.exoplatform.services.security.Authenticator; import org.exoplatform.services.security.Identity; import org.exoplatform.services.security.UsernameCredential; -import org.picketlink.identity.federation.bindings.jboss.auth.SAML2LoginModule; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; -import java.security.Principal; -import java.util.Map; /** * Login module for integration with GateIn. It's running on GateIn (SAML SP) side. @@ -57,6 +60,8 @@ public class SAML2IntegrationLoginModule extends SAML2LoginModule // Default value is false, so we are preferring delegation to JbossLoginModule and using roles from portal DB. private static final String OPTION_USE_SAML_ROLES = "useSAMLRoles"; + private static final Log log = ExoLogger.getLogger(SAML2IntegrationLoginModule.class); + private static final String[] ALL_VALID_OPTIONS = { OPTION_PORTAL_CONTAINER_NAME, @@ -88,13 +93,11 @@ public void initialize(Subject subject, CallbackHandler callbackHandler, Map arg0) { } @Override - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, String arg1) { + public jakarta.servlet.ServletRegistration.Dynamic addServlet(String arg0, String arg1) { return delegate.addServlet(arg0, arg1); } @Override - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, Servlet arg1) { + public jakarta.servlet.ServletRegistration.Dynamic addServlet(String arg0, Servlet arg1) { return delegate.addServlet(arg0, arg1); } @Override - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, Class arg1) { + public jakarta.servlet.ServletRegistration.Dynamic addServlet(String arg0, Class arg1) { return delegate.addServlet(arg0, arg1); } @@ -222,7 +222,7 @@ public InputStream getResourceAsStream(String arg0) { return fsResource.openStream(); } } catch (IOException e) { - log.warn("Error occurred when retieving file" + arg0, e); + LOG.warn("Error occurred when retieving file" + arg0, e); } } return delegate.getResourceAsStream(arg0); @@ -238,23 +238,11 @@ public String getServerInfo() { return delegate.getServerInfo(); } - @SuppressWarnings("deprecation") - @Override - public Servlet getServlet(String arg0) throws ServletException { - return delegate.getServlet(arg0); - } - @Override public String getServletContextName() { return delegate.getServletContextName(); } - @SuppressWarnings("deprecation") - @Override - public Enumeration getServletNames() { - return delegate.getServletNames(); - } - @Override public ServletRegistration getServletRegistration(String arg0) { return delegate.getServletRegistration(arg0); @@ -265,12 +253,6 @@ public ServletRegistration getServletRegistration(String arg0) { return delegate.getServletRegistrations(); } - @SuppressWarnings("deprecation") - @Override - public Enumeration getServlets() { - return delegate.getServlets(); - } - @Override public SessionCookieConfig getSessionCookieConfig() { return delegate.getSessionCookieConfig(); @@ -281,12 +263,6 @@ public void log(String arg0) { delegate.log(arg0); } - @SuppressWarnings("deprecation") - @Override - public void log(Exception arg0, String arg1) { - delegate.log(arg0, arg1); - } - @Override public void log(String arg0, Throwable arg1) { delegate.log(arg0, arg1); @@ -339,7 +315,7 @@ public String getVirtualServerName() { } @Override - public javax.servlet.ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { + public jakarta.servlet.ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { return delegate.addJspFile(servletName, jspFile); } diff --git a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSAML11SPRedirectFormAuthenticator.java b/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSAML11SPRedirectFormAuthenticator.java similarity index 98% rename from saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSAML11SPRedirectFormAuthenticator.java rename to sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSAML11SPRedirectFormAuthenticator.java index b2505b45e..ca62df499 100644 --- a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSAML11SPRedirectFormAuthenticator.java +++ b/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSAML11SPRedirectFormAuthenticator.java @@ -8,8 +8,8 @@ import java.util.ArrayList; import java.util.List; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.apache.catalina.LifecycleException; import org.apache.catalina.Session; diff --git a/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSPFormAuthenticator.java b/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSPFormAuthenticator.java new file mode 100644 index 000000000..c177f8ceb --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/AbstractSPFormAuthenticator.java @@ -0,0 +1,853 @@ +package org.gatein.sso.saml.plugin.valve; + +import static org.gatein.sso.saml.plugin.valve.AbstractSAML11SPRedirectFormAuthenticator.handleSAML11UnsolicitedResponse; +import static org.picketlink.common.util.StringUtil.isNotNull; +import static org.picketlink.common.util.StringUtil.isNullOrEmpty; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.Constants; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.realm.GenericPrincipal; +import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.picketlink.common.ErrorCodes; +import org.picketlink.common.constants.GeneralConstants; +import org.picketlink.common.constants.JBossSAMLConstants; +import org.picketlink.common.exceptions.ConfigurationException; +import org.picketlink.common.exceptions.ParsingException; +import org.picketlink.common.exceptions.ProcessingException; +import org.picketlink.common.exceptions.fed.AssertionExpiredException; +import org.picketlink.common.util.DocumentUtil; +import org.picketlink.common.util.StringUtil; +import org.picketlink.config.federation.AuthPropertyType; +import org.picketlink.config.federation.KeyProviderType; +import org.picketlink.identity.federation.bindings.tomcat.sp.holder.ServiceProviderSAMLContext; +import org.picketlink.identity.federation.core.audit.PicketLinkAuditEvent; +import org.picketlink.identity.federation.core.audit.PicketLinkAuditEventType; +import org.picketlink.identity.federation.core.interfaces.TrustKeyManager; +import org.picketlink.identity.federation.core.saml.v2.holders.DestinationInfoHolder; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerResponse; +import org.picketlink.identity.federation.core.util.CoreConfigUtil; +import org.picketlink.identity.federation.web.core.HTTPContext; +import org.picketlink.identity.federation.web.process.ServiceProviderBaseProcessor; +import org.picketlink.identity.federation.web.process.ServiceProviderSAMLRequestProcessor; +import org.picketlink.identity.federation.web.process.ServiceProviderSAMLResponseProcessor; +import org.picketlink.identity.federation.web.util.HTTPRedirectUtil; +import org.picketlink.identity.federation.web.util.PostBindingUtil; +import org.picketlink.identity.federation.web.util.RedirectBindingUtil; +import org.picketlink.identity.federation.web.util.RedirectBindingUtil.RedirectBindingUtilDestHolder; +import org.picketlink.identity.federation.web.util.ServerDetector; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.exoplatform.container.PortalContainer; +import org.exoplatform.services.organization.Membership; +import org.exoplatform.services.organization.OrganizationService; +import org.exoplatform.services.security.MembershipEntry; +import org.exoplatform.services.security.MembershipHashSet; +import org.exoplatform.services.security.RolesExtractor; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Abstract class to be extended by Service Provider valves to handle SAML + * requests and responses. forked from + * org.picketlink.identity.federation.bindings.tomcat.sp.AbstractSPFormAuthenticator + * and made compatible with Tomcat 8.5 since picketlink doesn't provide such a + * support + */ +public abstract class AbstractSPFormAuthenticator extends BaseFormAuthenticator { + private static final String FORM_PRINCIPAL_NOTE = "org.apache.catalina.authenticator.PRINCIPAL"; + + protected boolean jbossEnv = false; + + AbstractSPFormAuthenticator() { + super(); + ServerDetector detector = new ServerDetector(); + jbossEnv = detector.isJboss(); + } + + /* + * (non-Javadoc) + * @see + * org.picketlink.identity.federation.bindings.tomcat.sp.BaseFormAuthenticator + * #processStart() + */ + @Override + protected void startPicketLink() throws LifecycleException { + super.startPicketLink(); + initKeyProvider(context); + } + + /** + *

+ * Send the request to the IDP. Subclasses should override this method to + * implement how requests must be sent to the IDP. + *

+ * + * @param destination idp url + * @param samlDocument request or response document + * @param relayState used in SAML Workflow + * @param response Apache Catalina HTTP Response + * @param request Apache Catalina HTTP Request + * @param willSendRequest are we sending Request or Response to IDP + * @param destinationQueryStringWithSignature used only with Redirect binding + * and with signature enabled. + * @throws ProcessingException Exception to indicate a server processing error + * @throws ConfigurationException Exception indicating an issue with the + * configuration + * @throws IOException I/O exception + */ + protected void sendRequestToIDP(String destination, + Document samlDocument, + String relayState, + Request request, + Response response, + boolean willSendRequest, + String destinationQueryStringWithSignature) throws ProcessingException, + ConfigurationException, + IOException { + + if (isAjaxRequest(request) && request.getUserPrincipal() == null) { + response.sendError(Response.SC_FORBIDDEN); + } else { + if (isHttpPostBinding()) { + sendHttpPostBindingRequest(destination, samlDocument, relayState, response, willSendRequest); + } else { + sendHttpRedirectRequest(destination, + samlDocument, + relayState, + response, + willSendRequest, + destinationQueryStringWithSignature); + } + } + } + + /** + *

+ * Sends a HTTP Redirect request to the IDP. + *

+ * + * @param destination idp url + * @param samlDocument SAML request document + * @param relayState used in SAML Workflow + * @param response Apache Catalina HTTP Response + * @param willSendRequest are we sending Request or Response to IDP + * @param destinationQueryStringWithSignature used only with Redirect binding + * and with signature enabled. + * @throws IOException I/O exception + * @throws UnsupportedEncodingException when decoding SAML Message + * @throws ConfigurationException Exception indicating an issue with the + * configuration + * @throws ProcessingException Exception to indicate a server processing error + */ + protected void sendHttpRedirectRequest(String destination, + Document samlDocument, + String relayState, + Response response, + boolean willSendRequest, + String destinationQueryStringWithSignature) throws IOException, + ProcessingException, + ConfigurationException { + String destinationQueryString = null; + + // We already have queryString with signature from + // SAML2SignatureGenerationHandler + if (destinationQueryStringWithSignature != null) { + destinationQueryString = destinationQueryStringWithSignature; + } else { + String samlMessage = DocumentUtil.getDocumentAsString(samlDocument); + String base64Request = RedirectBindingUtil.deflateBase64URLEncode(samlMessage.getBytes("UTF-8")); + destinationQueryString = RedirectBindingUtil.getDestinationQueryString(base64Request, relayState, willSendRequest); + } + + RedirectBindingUtilDestHolder holder = new RedirectBindingUtilDestHolder(); + + holder.setDestination(destination).setDestinationQueryString(destinationQueryString); + + HTTPRedirectUtil.sendRedirectForRequestor(RedirectBindingUtil.getDestinationURL(holder), response); + } + + /** + *

+ * Sends a HTTP POST request to the IDP. + *

+ * + * @param destination idp url + * @param samlDocument request or response document + * @param relayState used in SAML Workflow + * @param response Apache Catalina HTTP Response + * @param willSendRequest are we sending Request or Response to IDP + * @throws ProcessingException Exception to indicate a server processing error + * @throws ConfigurationException Exception indicating an issue with the + * configuration + * @throws IOException I/O exception + */ + protected void sendHttpPostBindingRequest(String destination, + Document samlDocument, + String relayState, + Response response, + boolean willSendRequest) throws ProcessingException, + IOException, + ConfigurationException { + String samlMessage = PostBindingUtil.base64Encode(DocumentUtil.getDocumentAsString(samlDocument)); + + DestinationInfoHolder destinationHolder = new DestinationInfoHolder(destination, samlMessage, relayState); + + PostBindingUtil.sendPost(destinationHolder, response, willSendRequest); + } + + /** + *

+ * Initialize the KeyProvider configurations. This configurations are to be + * used during signing and validation of SAML assertions. + *

+ * + * @param context Apache Catalina Context + * @throws LifecycleException any exception occurred while processing key + * provider + */ + protected void initKeyProvider(Context context) throws LifecycleException { + if (!doSupportSignature()) { + return; + } + + KeyProviderType keyProvider = this.spConfiguration.getKeyProvider(); + + if (keyProvider == null && doSupportSignature()) + throw new LifecycleException(ErrorCodes.NULL_VALUE + "KeyProvider is null for context=" + context.getName()); + + try { + String keyManagerClassName = keyProvider.getClassName(); + if (keyManagerClassName == null) + throw new RuntimeException(ErrorCodes.NULL_VALUE + "KeyManager class name"); + + Class clazz = SecurityActions.loadClass(getClass(), keyManagerClassName); + + if (clazz == null) + throw new ClassNotFoundException(ErrorCodes.CLASS_NOT_LOADED + keyManagerClassName); + this.keyManager = (TrustKeyManager) clazz.newInstance(); + + List authProperties = CoreConfigUtil.getKeyProviderProperties(keyProvider); + + keyManager.setAuthProperties(authProperties); + keyManager.setValidatingAlias(keyProvider.getValidatingAlias()); + + String identityURL = this.spConfiguration.getIdentityURL(); + + // Special case when you need X509Data in SignedInfo + if (authProperties != null) { + for (AuthPropertyType authPropertyType : authProperties) { + String key = authPropertyType.getKey(); + if (GeneralConstants.X509CERTIFICATE.equals(key)) { + // we need X509Certificate in SignedInfo. The value is the alias + // name + keyManager.addAdditionalOption(GeneralConstants.X509CERTIFICATE, authPropertyType.getValue()); + break; + } + } + } + keyManager.addAdditionalOption(ServiceProviderBaseProcessor.IDP_KEY, new URL(identityURL).getHost()); + } catch (Exception e) { + logger.trustKeyManagerCreationError(e); + throw new LifecycleException(e.getLocalizedMessage()); + } + + logger.trace("Key Provider=" + keyProvider.getClassName()); + } + + @Override + protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException { + if (response instanceof Response) { + LoginConfig loginConfig = request.getContext().getLoginConfig(); + Response catalinaResponse = (Response) response; + return authenticate(request, catalinaResponse, loginConfig); + } + throw logger.samlSPResponseNotCatalinaResponseError(response); + } + + /** + * Authenticate the request + * + * @param request Apache Catalina Request + * @param response Apache Catalina Response + * @return true if authenticated, else false + * @throws IOException any I/O exception + */ + public boolean authenticate(Request request, HttpServletResponse response) throws IOException { + if (response instanceof Response) { + LoginConfig loginConfig = request.getContext().getLoginConfig(); + Response catalinaResponse = (Response) response; + return authenticate(request, catalinaResponse, loginConfig); + } + throw logger.samlSPResponseNotCatalinaResponseError(response); + } + + /* + * (non-Javadoc) + * @see + * org.apache.catalina.authenticator.FormAuthenticator#authenticate(org.apache + * .catalina.connector.Request, org.apache.catalina.connector.Response, + * org.apache.catalina.deploy.LoginConfig) + */ + private boolean authenticate(Request request, Response response, LoginConfig loginConfig) throws IOException { + try { + // needs to be done first, *before* accessing any parameters. + // super.authenticate(..) gets called to late + String characterEncoding = getCharacterEncoding(); + if (characterEncoding != null) { + request.setCharacterEncoding(characterEncoding); + } + + Session session = request.getSessionInternal(true); + + // check if this call is resulting from the redirect after successful + // authentication. + // if so, make the authentication successful and continue the original + // request + if (saveRestoreRequest && matchRequest(request)) { + logger.trace("Restoring request from session '" + session.getIdInternal() + "'"); + Principal savedPrincipal = (Principal) session.getNote(FORM_PRINCIPAL_NOTE); + register(request, + response, + savedPrincipal, + HttpServletRequest.FORM_AUTH, + (String) session.getNote(Constants.SESS_USERNAME_NOTE), + (String) session.getNote(Constants.SESS_PASSWORD_NOTE)); + + // try to restore the original request (including post data, etc...) + if (restoreRequest(request, session)) { + // success! user is authenticated; continue processing original + // request + logger.trace("Continuing with restored request."); + return true; + } else { + // no saved request found... + logger.trace("Restore of original request failed!"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return false; + } + } + + // Eagerly look for Local LogOut + boolean localLogout = isLocalLogout(request); + + if (localLogout) { + try { + sendToLogoutPage(request, response, session); + } catch (ServletException e) { + logger.samlLogoutError(e); + throw new IOException(e); + } + return false; + } + + String samlRequest = request.getParameter(GeneralConstants.SAML_REQUEST_KEY); + String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); + + Principal principal = request.getUserPrincipal(); + + // If we have already authenticated the user and there is no request from + // IDP or logout from user + if (principal != null && !(isGlobalLogout(request) || isNotNull(samlRequest) || isNotNull(samlResponse))) + return true; + + // General User Request + if (!isNotNull(samlRequest) && !isNotNull(samlResponse)) { + return generalUserRequest(request, response, loginConfig); + } + + // Handle a SAML Response from IDP + if (isNotNull(samlResponse)) { + return handleSAMLResponse(request, response, loginConfig); + } + + // Handle SAML Requests from IDP + if (isNotNull(samlRequest)) { + return handleSAMLRequest(request, response, loginConfig); + } // end if + + return localAuthentication(request, response, loginConfig); + } catch (IOException e) { + if (StringUtil.isNotNull(spConfiguration.getErrorPage())) { + try { + request.getRequestDispatcher(spConfiguration.getErrorPage()).forward(request.getRequest(), response); + } catch (ServletException e1) { + logger.samlErrorPageForwardError(spConfiguration.getErrorPage(), e1); + } + return false; + } else { + throw e; + } + } + } + + /** + *

+ * Indicates if the current request is a GlobalLogout request. + *

+ * + * @param request Apache Catalina Request + * @return true if this is a global SAML logout + */ + private boolean isGlobalLogout(Request request) { + String gloStr = request.getParameter(GeneralConstants.GLOBAL_LOGOUT); + return isNotNull(gloStr) && "true".equalsIgnoreCase(gloStr); + } + + /** + *

+ * Indicates if the current request is a LocalLogout request. + *

+ * + * @param request Apache Catalina Request + * @return true if this is a local SAML logout + */ + private boolean isLocalLogout(Request request) { + try { + if (request.getCharacterEncoding() == null) { + request.setCharacterEncoding("UTF-8"); + } + } catch (UnsupportedEncodingException e) { + logger.error("Request have no encoding, and we are unable to set it to UTF-8"); + logger.error(e); + } + String lloStr = request.getParameter(GeneralConstants.LOCAL_LOGOUT); + return isNotNull(lloStr) && "true".equalsIgnoreCase(lloStr); + } + + /** + * Handle the IDP Request + * + * @param request Apache Catalina Request + * @param response Apache Catalina Response + * @param loginConfig Apache Catalina Login Config + * @return true if processed by SAML Workflow + * @throws IOException any I/O error while authenticating + */ + private boolean handleSAMLRequest(Request request, Response response, LoginConfig loginConfig) throws IOException { + String samlRequest = request.getParameter(GeneralConstants.SAML_REQUEST_KEY); + HTTPContext httpContext = new HTTPContext(request, response, context.getServletContext()); + Set handlers = chain.handlers(); + + try { + ServiceProviderSAMLRequestProcessor requestProcessor = new ServiceProviderSAMLRequestProcessor( + request.getMethod() + .equals("POST"), + this.serviceURL, + this.picketLinkConfiguration); + requestProcessor.setTrustKeyManager(keyManager); + boolean result = requestProcessor.process(samlRequest, httpContext, handlers, chainLock); + + if (enableAudit) { + PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent("Info"); + auditEvent.setType(PicketLinkAuditEventType.REQUEST_FROM_IDP); + auditEvent.setWhoIsAuditing(getContextPath()); + auditHelper.audit(auditEvent); + } + + // If response is already commited, we need to stop with processing of + // HTTP request + if (response.isCommitted() || response.isAppCommitted()) + return false; + + if (result) + return result; + } catch (Exception e) { + logger.samlSPHandleRequestError(e); + throw logger.samlSPProcessingExceptionError(e); + } + + return localAuthentication(request, response, loginConfig); + } + + private Document toSAMLResponseDocument(String samlResponse, boolean isPostBinding) throws ParsingException { + InputStream dataStream = null; + + if (isPostBinding) { + // deal with SAML response from IDP + dataStream = PostBindingUtil.base64DecodeAsStream(samlResponse); + } else { + // deal with SAML response from IDP + dataStream = RedirectBindingUtil.base64DeflateDecode(samlResponse); + } + + try { + return DocumentUtil.getDocument(dataStream); + } catch (Exception e) { + logger.samlResponseFromIDPParsingFailed(); + throw new ParsingException("", e); + } + } + + /** + * Handle IDP Response + * + * @param request Apache Catalina Request + * @param response Apache Catalina Response + * @param loginConfig Apache Catalina Login Config + * @return true if logged in in SAML SP side + * @throws IOException any I/O error in authentication process + */ + private boolean handleSAMLResponse(Request request, Response response, LoginConfig loginConfig) throws IOException { + if (!super.validate(request)) { + throw new IOException(ErrorCodes.VALIDATION_CHECK_FAILED); + } + + String samlVersion = getSAMLVersion(request); + + if (!JBossSAMLConstants.VERSION_2_0.get().equals(samlVersion)) { + return handleSAML11UnsolicitedResponse(request, response, loginConfig, this); + } + + return handleSAML2Response(request, response, loginConfig); + } + + private boolean handleSAML2Response(Request request, Response response, LoginConfig loginConfig) throws IOException { + Session session = request.getSessionInternal(true); + String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); + HTTPContext httpContext = new HTTPContext(request, response, context.getServletContext()); + Set handlers = chain.handlers(); + + Principal principal = request.getUserPrincipal(); + + boolean willSendRequest;// deal with SAML response from IDP + + try { + ServiceProviderSAMLResponseProcessor responseProcessor = + new ServiceProviderSAMLResponseProcessor(request.getMethod() + .equals("POST"), + serviceURL, + this.picketLinkConfiguration); + if (auditHelper != null) { + responseProcessor.setAuditHelper(auditHelper); + } + + responseProcessor.setTrustKeyManager(keyManager); + + SAML2HandlerResponse saml2HandlerResponse = responseProcessor.process(samlResponse, + httpContext, + handlers, + chainLock); + + Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); + String relayState = saml2HandlerResponse.getRelayState(); + + String destination = saml2HandlerResponse.getDestination(); + + willSendRequest = saml2HandlerResponse.getSendRequest(); + + String destinationQueryStringWithSignature = saml2HandlerResponse.getDestinationQueryStringWithSignature(); + + if (destination != null && samlResponseDocument != null) { + sendRequestToIDP(destination, + samlResponseDocument, + relayState, + request, + response, + willSendRequest, + destinationQueryStringWithSignature); + } else { + // See if the session has been invalidated + + boolean sessionValidity = session.isValid(); + + if (!sessionValidity) { + sendToLogoutPage(request, response, session); + return false; + } + + // We got a response with the principal + List roles = saml2HandlerResponse.getRoles(); + + if (principal == null) { + principal = (Principal) session.getSession().getAttribute(GeneralConstants.PRINCIPAL_ID); + } + + String username = principal.getName(); + String password = ServiceProviderSAMLContext.EMPTY_PASSWORD; + + roles.addAll(extractGateinRoles(username)); + if (logger.isTraceEnabled()) { + logger.trace("Roles determined for username=" + username + "=" + Arrays.toString(roles.toArray())); + } + + // Map to JBoss specific principal + if ((new ServerDetector()).isJboss() || jbossEnv) { + // Push a context + ServiceProviderSAMLContext.push(username, roles); + principal = context.getRealm().authenticate(username, password); + ServiceProviderSAMLContext.clear(); + } else { + // tomcat env + principal = getGenericPrincipal(request, username, roles); + } + + session.setNote(Constants.SESS_USERNAME_NOTE, username); + session.setNote(Constants.SESS_PASSWORD_NOTE, password); + request.setUserPrincipal(principal); + + if (enableAudit) { + PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent("Info"); + auditEvent.setType(PicketLinkAuditEventType.RESPONSE_FROM_IDP); + auditEvent.setSubjectName(username); + auditEvent.setWhoIsAuditing(getContextPath()); + auditHelper.audit(auditEvent); + } + + // Redirect the user to the originally requested URL + if (saveRestoreRequest) { + // Store the authenticated principal in the session. + session.setNote(FORM_PRINCIPAL_NOTE, principal); + + // Redirect to the original URL. Note that this will trigger the + // authenticator again, but on resubmission we will look in the + // session notes to retrieve the authenticated principal and + // prevent reauthentication + String requestURI = savedRequestURL(session); + + if (requestURI != null) { + logger.trace("Redirecting back to original Request URI: " + requestURI); + response.sendRedirect(response.encodeRedirectURL(requestURI)); + } + } + + register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password); + return true; + } + } catch (ProcessingException pe) { + Throwable t = pe.getCause(); + if (t != null && t instanceof AssertionExpiredException) { + logger.error("Assertion has expired. Asking IDP for reissue"); + if (enableAudit) { + PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent("Info"); + auditEvent.setType(PicketLinkAuditEventType.EXPIRED_ASSERTION); + auditEvent.setAssertionID(((AssertionExpiredException) t).getId()); + auditHelper.audit(auditEvent); + } + // Just issue a fresh request back to IDP + return generalUserRequest(request, response, loginConfig); + } + logger.samlSPHandleRequestError(pe); + throw logger.samlSPProcessingExceptionError(pe); + } catch (Exception e) { + logger.samlSPHandleRequestError(e); + throw logger.samlSPProcessingExceptionError(e); + } + + return localAuthentication(request, response, loginConfig); + } + + private String getSAMLVersion(Request request) { + String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); + String version; + + try { + Document samlDocument = toSAMLResponseDocument(samlResponse, "POST".equalsIgnoreCase(request.getMethod())); + Element element = samlDocument.getDocumentElement(); + + // let's try SAML 2.0 Version attribute first + version = element.getAttribute("Version"); + + if (isNullOrEmpty(version)) { + // fallback to SAML 1.1 Minor and Major attributes + String minorVersion = element.getAttribute("MinorVersion"); + String majorVersion = element.getAttribute("MajorVersion"); + + version = minorVersion + "." + majorVersion; + } + } catch (Exception e) { + throw new RuntimeException("Could not extract version from SAML Response.", e); + } + + return version; + } + + protected boolean isPOSTBindingResponse() { + return spConfiguration.isIdpUsesPostBinding(); + } + + /* + * (non-Javadoc) + * @see + * org.picketlink.identity.federation.bindings.tomcat.sp.BaseFormAuthenticator + * #getBinding() + */ + @Override + protected String getBinding() { + return spConfiguration.getBindingType(); + } + + /** + * Handle the user invocation for the first time + * + * @param request Apache Catalina Request + * @param response Apache Catalina Response + * @param loginConfig Apache Catalina Login Config + * @return true if logged in in SAML SP side + * @throws IOException any I/O error in authentication process + */ + private boolean generalUserRequest(Request request, Response response, LoginConfig loginConfig) throws IOException { + Session session = request.getSessionInternal(true); + boolean willSendRequest = false; + HTTPContext httpContext = new HTTPContext(request, response, context.getServletContext()); + Set handlers = chain.handlers(); + + boolean postBinding = spConfiguration.getBindingType().equals("POST"); + + // Neither saml request nor response from IDP + // So this is a user request + SAML2HandlerResponse saml2HandlerResponse = null; + try { + ServiceProviderBaseProcessor baseProcessor = new ServiceProviderBaseProcessor(postBinding, + serviceURL, + this.picketLinkConfiguration); + if (issuerID != null) + baseProcessor.setIssuer(issuerID); + + // If the user has a different desired idp + String idp = (String) request.getAttribute(org.picketlink.identity.federation.web.constants.GeneralConstants.DESIRED_IDP); + if (StringUtil.isNotNull(idp)) { + baseProcessor.setIdentityURL(idp); + } else { + baseProcessor.setIdentityURL(identityURL); + } + baseProcessor.setAuditHelper(auditHelper); + + saml2HandlerResponse = baseProcessor.process(httpContext, handlers, chainLock); + } catch (ProcessingException pe) { + logger.samlSPHandleRequestError(pe); + throw new RuntimeException(pe); + } catch (ParsingException pe) { + logger.samlSPHandleRequestError(pe); + throw new RuntimeException(pe); + } catch (ConfigurationException pe) { + logger.samlSPHandleRequestError(pe); + throw new RuntimeException(pe); + } + + willSendRequest = saml2HandlerResponse.getSendRequest(); + + Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); + String relayState = saml2HandlerResponse.getRelayState(); + + String destination = saml2HandlerResponse.getDestination(); + String destinationQueryStringWithSignature = saml2HandlerResponse.getDestinationQueryStringWithSignature(); + + if (destination != null && samlResponseDocument != null) { + try { + if (saveRestoreRequest && !isGlobalLogout(request)) { + this.saveRequest(request, session); + } + if (enableAudit) { + PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent("Info"); + auditEvent.setType(PicketLinkAuditEventType.REQUEST_TO_IDP); + auditEvent.setWhoIsAuditing(getContextPath()); + auditHelper.audit(auditEvent); + } + sendRequestToIDP(destination, + samlResponseDocument, + relayState, + request, + response, + willSendRequest, + destinationQueryStringWithSignature); + return false; + } catch (Exception e) { + logger.samlSPHandleRequestError(e); + throw logger.samlSPProcessingExceptionError(e); + } + } + + return localAuthentication(request, response, loginConfig); + } + + /** + * Extract Gatein roles to put in Principal + * + * @param userId + * @return + */ + private List extractGateinRoles(String userId) { + OrganizationService organizationService = + PortalContainer.getInstance().getComponentInstanceOfType(OrganizationService.class); + RolesExtractor rolesExtractor = PortalContainer.getInstance().getComponentInstanceOfType(RolesExtractor.class); + List result = new ArrayList<>(); + Set entries = new MembershipHashSet(); + Collection memberships; + try { + memberships = organizationService.getMembershipHandler().findMembershipsByUser(userId); + } catch (Exception e) { + memberships = null; + } + if (memberships != null) { + for (Membership membership : memberships) + entries.add(new MembershipEntry(membership.getGroupId(), membership.getMembershipType())); + } + result.addAll(rolesExtractor.extractRoles(userId, entries)); + return result; + } + + /** + *

+ * Indicates if the SP is configure with HTTP POST Binding. + *

+ * + * @return true if post binding + */ + protected boolean isHttpPostBinding() { + return getBinding().equalsIgnoreCase("POST"); + } + + public Context getContext() { + return (Context) getContainer(); + } + + @Override + public boolean restoreRequest(Request request, Session session) throws IOException { + return super.restoreRequest(request, session); + } + + /** + * Subclasses need to return the context path based on the capability of their + * servlet api + * + * @return Servlet Context Path + */ + protected abstract String getContextPath(); + + protected Principal getGenericPrincipal(Request request, String username, List roles) { + // sometimes, IDP send username in assertion with capitals letters, or with + // inconsistent format. + // this option allows to force the username in lower case, just before + // creating the principal, + // so that, all operations in exo side will use a consistant format. + String forceLowerCase = System.getProperty("gatein.sso.saml.username.forcelowercase", "false"); + if (forceLowerCase.equalsIgnoreCase("true")) { + username = username.toLowerCase(); + } + return new GenericPrincipal(username, null, roles); + } + + private boolean isAjaxRequest(Request request) { + String requestedWithHeader = request.getHeader(GeneralConstants.HTTP_HEADER_X_REQUESTED_WITH); + return requestedWithHeader != null && "XMLHttpRequest".equalsIgnoreCase(requestedWithHeader); + } +} diff --git a/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/BaseFormAuthenticator.java b/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/BaseFormAuthenticator.java new file mode 100644 index 000000000..eb8571056 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/BaseFormAuthenticator.java @@ -0,0 +1,675 @@ +package org.gatein.sso.saml.plugin.valve; + +import static org.picketlink.common.constants.GeneralConstants.CONFIG_FILE_LOCATION; +import static org.picketlink.common.util.StringUtil.isNullOrEmpty; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import javax.xml.crypto.dsig.CanonicalizationMethod; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.FormAuthenticator; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.gatein.sso.saml.plugin.filter.SAMLSPServletContextWrapper; +import org.picketlink.common.ErrorCodes; +import org.picketlink.common.PicketLinkLogger; +import org.picketlink.common.PicketLinkLoggerFactory; +import org.picketlink.common.constants.GeneralConstants; +import org.picketlink.common.constants.JBossSAMLURIConstants; +import org.picketlink.common.exceptions.ConfigurationException; +import org.picketlink.common.exceptions.ParsingException; +import org.picketlink.common.exceptions.ProcessingException; +import org.picketlink.common.util.DocumentUtil; +import org.picketlink.common.util.StringUtil; +import org.picketlink.common.util.SystemPropertiesUtil; +import org.picketlink.config.federation.PicketLinkType; +import org.picketlink.config.federation.SPType; +import org.picketlink.config.federation.handler.Handlers; +import org.picketlink.identity.federation.api.saml.v2.metadata.MetaDataExtractor; +import org.picketlink.identity.federation.core.audit.PicketLinkAuditHelper; +import org.picketlink.identity.federation.core.interfaces.TrustKeyManager; +import org.picketlink.identity.federation.core.parsers.saml.SAMLParser; +import org.picketlink.identity.federation.core.saml.v2.factories.SAML2HandlerChainFactory; +import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerChainConfig; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerChain; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerChainConfig; +import org.picketlink.identity.federation.core.saml.v2.util.HandlerUtil; +import org.picketlink.identity.federation.core.util.CoreConfigUtil; +import org.picketlink.identity.federation.core.util.XMLSignatureUtil; +import org.picketlink.identity.federation.saml.v2.metadata.EndpointType; +import org.picketlink.identity.federation.saml.v2.metadata.EntitiesDescriptorType; +import org.picketlink.identity.federation.saml.v2.metadata.EntityDescriptorType; +import org.picketlink.identity.federation.saml.v2.metadata.IDPSSODescriptorType; +import org.picketlink.identity.federation.saml.v2.metadata.KeyDescriptorType; +import org.picketlink.identity.federation.web.config.AbstractSAMLConfigurationProvider; +import org.picketlink.identity.federation.web.util.ConfigurationUtil; +import org.picketlink.identity.federation.web.util.SAMLConfigurationProvider; +import org.w3c.dom.Document; + +import org.exoplatform.commons.utils.PropertyManager; +import org.exoplatform.container.xml.Deserializer; + +/** + * Base Class for Service Provider Form Authenticators forked from + * org.picketlink.identity.federation.bindings.tomcat.sp.BaseFormAuthenticator + * and made compatible with Tomcat 8.5 since picketlink doesn't provide such a + * support + */ +public abstract class BaseFormAuthenticator extends FormAuthenticator { + protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); + + protected boolean enableAudit = false; + + protected PicketLinkAuditHelper auditHelper = null; + + protected TrustKeyManager keyManager; + + protected SPType spConfiguration = null; + + protected PicketLinkType picketLinkConfiguration = null; + + protected String serviceURL = null; + + protected String identityURL = null; + + protected String issuerID = null; + + protected String configFile; + + /** + * If the service provider is configured with an IDP metadata file, then this + * certificate can be picked up from the metadata + */ + protected transient X509Certificate idpCertificate = null; + + protected transient SAML2HandlerChain chain = null; + + protected transient String samlHandlerChainClass = null; + + protected Map chainConfigOptions = new HashMap(); + + // Whether the authenticator has to to save and restore request + protected boolean saveRestoreRequest = true; + + /** + * A Lock for Handler operations in the chain + */ + protected Lock chainLock = new ReentrantLock(); + + protected String canonicalizationMethod = CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS; + + /** + * The user can inject a fully qualified name of a + * {@link SAMLConfigurationProvider} + */ + protected SAMLConfigurationProvider configProvider = null; + + protected int timerInterval = -1; + + protected Timer timer = null; + + public BaseFormAuthenticator() { + super(); + } + + protected String idpAddress = null; + + /** + * If the request.getRemoteAddr is not exactly the IDP address that you have + * keyed in your deployment descriptor for keystore alias, you can set it here + * explicitly + * + * @param idpAddress IP address of IDP + */ + public void setIdpAddress(String idpAddress) { + this.idpAddress = idpAddress; + } + + /** + * Get the name of the configuration file + * + * @return SAML config file path + */ + public String getConfigFile() { + return configFile; + } + + /** + * Set the name of the configuration file + * + * @param configFile set config file path + */ + public void setConfigFile(String configFile) { + this.configFile = configFile; + } + + /** + * Set the SAML Handler Chain Class fqn + * + * @param samlHandlerChainClass FQN of SAML Handler Chain + */ + public void setSamlHandlerChainClass(String samlHandlerChainClass) { + this.samlHandlerChainClass = samlHandlerChainClass; + } + + /** + * Set the service URL + * + * @param serviceURL Service URL + */ + public void setServiceURL(String serviceURL) { + this.serviceURL = serviceURL; + } + + /** + * Set whether the authenticator saves/restores the request during form + * authentication + * + * @param saveRestoreRequest saves/restores the request during authentication + * if true + */ + public void setSaveRestoreRequest(boolean saveRestoreRequest) { + this.saveRestoreRequest = saveRestoreRequest; + } + + /** + * Set the {@link SAMLConfigurationProvider} fqn + * + * @param cp fqn of a {@link SAMLConfigurationProvider} + */ + public void setConfigProvider(String cp) { + if (cp == null) + throw new IllegalStateException(ErrorCodes.NULL_ARGUMENT + cp); + Class clazz = SecurityActions.loadClass(getClass(), cp); + if (clazz == null) + throw new RuntimeException(ErrorCodes.CLASS_NOT_LOADED + cp); + try { + configProvider = (SAMLConfigurationProvider) clazz.newInstance(); + } catch (Exception e) { + throw new RuntimeException(ErrorCodes.CANNOT_CREATE_INSTANCE + cp + ":" + e.getMessage()); + } + } + + /** + * Set an instance of the {@link SAMLConfigurationProvider} + * + * @param configProvider SAML IDP/SP config provider + */ + public void setConfigProvider(SAMLConfigurationProvider configProvider) { + this.configProvider = configProvider; + } + + /** + * Get the {@link SPType} + * + * @return SAML SP configuration + */ + public SPType getConfiguration() { + return spConfiguration; + } + + /** + * Set a separate issuer id + * + * @param issuerID id of the issuer + */ + public void setIssuerID(String issuerID) { + this.issuerID = issuerID; + } + + /** + * Set the logout page + * + * @param logOutPage logout page URL + */ + public void setLogOutPage(String logOutPage) { + logger.warn("Option logOutPage is now configured with the PicketLinkSP element."); + + } + + /** + * Set the Timer Value to reload the configuration + * + * @param value an integer value that represents timer value (in miliseconds) + */ + public void setTimerInterval(String value) { + if (StringUtil.isNotNull(value)) { + timerInterval = Integer.parseInt(value); + } + } + + /** + * Perform validation os the request object + * + * @param request Apache Catalina Request + * @return true if request contains a SAML Response parameter + */ + protected boolean validate(Request request) { + return request.getParameter("SAMLResponse") != null; + } + + /** + * Get the Identity URL + * + * @return Identity URL + */ + public String getIdentityURL() { + return identityURL; + } + + /** + * Get the {@link X509Certificate} of the IDP if provided via the IDP metadata + * file + * + * @return {@link X509Certificate} or null + */ + public X509Certificate getIdpCertificate() { + return idpCertificate; + } + + /** + * Fall back on local authentication at the service provider side + * + * @param request Apache Catalina Request + * @param response Apache Catalina Response + * @param loginConfig Apache Catalina Login Config + * @return true if authenticated + * @throws IOException any I/O error during authentication + */ + protected boolean localAuthentication(Request request, Response response, LoginConfig loginConfig) throws IOException { + if (request.getUserPrincipal() == null) { + logger.samlSPFallingBackToLocalFormAuthentication();// fallback + try { + return super.authenticate(request, response.getResponse()); + } catch (NoSuchMethodError e) { + // Use Reflection + try { + Method method = super.getClass().getMethod("authenticate", + new Class[] { HttpServletRequest.class, HttpServletResponse.class, + LoginConfig.class }); + return (Boolean) method.invoke(this, + new Object[] { request.getRequest(), response.getResponse(), + loginConfig }); + } catch (Exception ex) { + throw logger.unableLocalAuthentication(ex); + } + } + } else + return true; + } + + /** + * Return the SAML Binding that this authenticator supports + * + * @return supported SAML Binding + */ + protected abstract String getBinding(); + + /** + * Attempt to process a metadata file available locally + * + * @param idpMetadataFile path of configuration file of IDP Metadata + */ + protected void processIDPMetadataFile(String idpMetadataFile) { + ServletContext servletContext = context.getServletContext(); + InputStream is = servletContext.getResourceAsStream(idpMetadataFile); + if (is == null) + return; + + Object metadata = null; + try { + Document samlDocument = DocumentUtil.getDocument(is); + SAMLParser parser = new SAMLParser(); + metadata = parser.parse(DocumentUtil.getNodeAsStream(samlDocument)); + } catch (Exception e) { + throw new RuntimeException(e); + } + IDPSSODescriptorType idpSSO = null; + if (metadata instanceof EntitiesDescriptorType) { + EntitiesDescriptorType entities = (EntitiesDescriptorType) metadata; + idpSSO = handleMetadata(entities); + } else { + idpSSO = handleMetadata((EntityDescriptorType) metadata); + } + if (idpSSO == null) { + logger.samlSPUnableToGetIDPDescriptorFromMetadata(); + return; + } + List endpoints = idpSSO.getSingleSignOnService(); + for (EndpointType endpoint : endpoints) { + String endpointBinding = endpoint.getBinding().toString(); + if (endpointBinding.contains("HTTP-POST")) + endpointBinding = "POST"; + else if (endpointBinding.contains("HTTP-Redirect")) + endpointBinding = "REDIRECT"; + if (getBinding().equals(endpointBinding)) { + identityURL = endpoint.getLocation().toString(); + break; + } + } + List keyDescriptors = idpSSO.getKeyDescriptor(); + if (keyDescriptors.size() > 0) { + this.idpCertificate = MetaDataExtractor.getCertificate(keyDescriptors.get(0)); + } + } + + /** + * Process the configuration from the configuration file + */ + @SuppressWarnings("deprecation") + protected void processConfiguration() { + ServletContext servletContext = context.getServletContext(); + InputStream is = null; + try { + if (isNullOrEmpty(this.configFile)) { + this.configFile = PropertyManager.getProperty("gatein.sso.saml.config.file"); + if (StringUtils.contains(this.configFile, "$")) { + this.configFile = Deserializer.resolveString(this.configFile); + } + if (StringUtils.isBlank(this.configFile)) { + this.configFile = CONFIG_FILE_LOCATION; + } + if (Files.exists(Paths.get(this.configFile))) { + is = new FileInputStream(this.configFile); + } else { + this.configFile = SAMLSPServletContextWrapper.FILE_PREFIX + this.configFile; + is = servletContext.getResourceAsStream(this.configFile); + } + } else { + try { + is = new FileInputStream(this.configFile); + } catch (FileNotFoundException e) { + throw logger.samlIDPConfigurationError(e); + } + } + + // Work on the IDP Configuration + if (configProvider != null) { + try { + if (is == null) { + // Try the older version + is = servletContext.getResourceAsStream(GeneralConstants.DEPRECATED_CONFIG_FILE_LOCATION); + + // Additionally parse the deprecated config file + if (is != null && configProvider instanceof AbstractSAMLConfigurationProvider) { + ((AbstractSAMLConfigurationProvider) configProvider).setConfigFile(is); + } + } else { + // Additionally parse the consolidated config file + if (is != null && configProvider instanceof AbstractSAMLConfigurationProvider) { + ((AbstractSAMLConfigurationProvider) configProvider).setConsolidatedConfigFile(is); + } + } + + picketLinkConfiguration = configProvider.getPicketLinkConfiguration(); + spConfiguration = configProvider.getSPConfiguration(); + } catch (ProcessingException e) { + throw logger.samlSPConfigurationError(e); + } catch (ParsingException e) { + throw logger.samlSPConfigurationError(e); + } + } else { + if (is != null) { + try { + picketLinkConfiguration = ConfigurationUtil.getConfiguration(is); + spConfiguration = (SPType) picketLinkConfiguration.getIdpOrSP(); + } catch (ParsingException e) { + logger.trace(e); + throw logger.samlSPConfigurationError(e); + } + } else { + is = servletContext.getResourceAsStream(GeneralConstants.DEPRECATED_CONFIG_FILE_LOCATION); + if (is == null) + throw logger.configurationFileMissing(configFile); + spConfiguration = ConfigurationUtil.getSPConfiguration(is); + } + } + + if (this.picketLinkConfiguration != null) { + enableAudit = picketLinkConfiguration.isEnableAudit(); + + // See if we have the system property enabled + if (!enableAudit) { + String sysProp = SecurityActions.getSystemProperty(GeneralConstants.AUDIT_ENABLE, "NULL"); + if (!"NULL".equals(sysProp)) { + enableAudit = Boolean.parseBoolean(sysProp); + } + } + + if (enableAudit) { + if (auditHelper == null) { + String securityDomainName = PicketLinkAuditHelper.getSecurityDomainName(servletContext); + + auditHelper = new PicketLinkAuditHelper(securityDomainName); + } + } + } + + if (StringUtil.isNotNull(spConfiguration.getIdpMetadataFile())) { + processIDPMetadataFile(spConfiguration.getIdpMetadataFile()); + } else { + this.identityURL = spConfiguration.getIdentityURL(); + } + this.serviceURL = spConfiguration.getServiceURL(); + this.canonicalizationMethod = spConfiguration.getCanonicalizationMethod(); + + logger.samlSPSettingCanonicalizationMethod(canonicalizationMethod); + XMLSignatureUtil.setCanonicalizationMethodType(canonicalizationMethod); + + logger.trace("Identity Provider URL=" + this.identityURL); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + logger.trace("Can't close Input Stream", e); + } + } + } + } + + protected IDPSSODescriptorType handleMetadata(EntitiesDescriptorType entities) { + IDPSSODescriptorType idpSSO = null; + + List entityDescs = entities.getEntityDescriptor(); + for (Object entityDescriptor : entityDescs) { + if (entityDescriptor instanceof EntitiesDescriptorType) { + idpSSO = getIDPSSODescriptor(entities); + } else + idpSSO = handleMetadata((EntityDescriptorType) entityDescriptor); + if (idpSSO != null) + break; + } + return idpSSO; + } + + protected IDPSSODescriptorType handleMetadata(EntityDescriptorType entityDescriptor) { + return CoreConfigUtil.getIDPDescriptor(entityDescriptor); + } + + protected IDPSSODescriptorType getIDPSSODescriptor(EntitiesDescriptorType entities) { + List entityDescs = entities.getEntityDescriptor(); + for (Object entityDescriptor : entityDescs) { + + if (entityDescriptor instanceof EntitiesDescriptorType) { + return getIDPSSODescriptor((EntitiesDescriptorType) entityDescriptor); + } + return CoreConfigUtil.getIDPDescriptor((EntityDescriptorType) entityDescriptor); + } + return null; + } + + protected void initializeHandlerChain() throws ConfigurationException, ProcessingException { + populateChainConfig(); + SAML2HandlerChainConfig handlerChainConfig = new DefaultSAML2HandlerChainConfig(chainConfigOptions); + + Set samlHandlers = chain.handlers(); + + for (SAML2Handler handler : samlHandlers) { + handler.initChainConfig(handlerChainConfig); + } + } + + protected void populateChainConfig() throws ConfigurationException, ProcessingException { + chainConfigOptions.put(GeneralConstants.CONFIGURATION, spConfiguration); + chainConfigOptions.put(GeneralConstants.ROLE_VALIDATOR_IGNORE, "false"); // No + // validator + // as + // tomcat + // realm + // does + // validn + + if (doSupportSignature()) { + chainConfigOptions.put(GeneralConstants.KEYPAIR, keyManager.getSigningKeyPair()); + // If there is a need for X509Data in signedinfo + String certificateAlias = (String) keyManager.getAdditionalOption(GeneralConstants.X509CERTIFICATE); + if (certificateAlias != null) { + chainConfigOptions.put(GeneralConstants.X509CERTIFICATE, keyManager.getCertificate(certificateAlias)); + } + } + } + + protected void sendToLogoutPage(Request request, Response response, Session session) throws IOException, ServletException { + // we are invalidated. + RequestDispatcher dispatch = context.getServletContext().getRequestDispatcher(this.getConfiguration().getLogOutPage()); + if (dispatch == null) + logger.samlSPCouldNotDispatchToLogoutPage(this.getConfiguration().getLogOutPage()); + else { + logger.trace("Forwarding request to logOutPage: " + this.getConfiguration().getLogOutPage()); + session.expire(); + try { + dispatch.forward(request, response); + } catch (Exception e) { + // JBAS5.1 and 6 quirkiness + dispatch.forward(request.getRequest(), response); + } + } + } + + // Mock test purpose + public void testStart() throws LifecycleException { + this.saveRestoreRequest = false; + if (context == null) + throw new RuntimeException("Catalina Context not set up"); + startPicketLink(); + } + + protected void startPicketLink() throws LifecycleException { + SystemPropertiesUtil.ensure(); + Handlers handlers = null; + + // Introduce a timer to reload configuration if desired + if (timerInterval > 0) { + if (timer == null) { + timer = new Timer(); + } + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + // Clear the configuration + picketLinkConfiguration = null; + spConfiguration = null; + + processConfiguration(); + try { + initKeyProvider(context); + } catch (LifecycleException e) { + logger.trace(e.getMessage()); + } + } + }, timerInterval, timerInterval); + } + + // Get the chain from config + if (StringUtil.isNullOrEmpty(samlHandlerChainClass)) { + chain = SAML2HandlerChainFactory.createChain(); + } else { + try { + chain = SAML2HandlerChainFactory.createChain(this.samlHandlerChainClass); + } catch (ProcessingException e1) { + throw new LifecycleException(e1); + } + } + + ServletContext servletContext = context.getServletContext(); + + this.processConfiguration(); + + try { + if (picketLinkConfiguration != null) { + handlers = picketLinkConfiguration.getHandlers(); + } else { + // Get the handlers + String handlerConfigFileName = GeneralConstants.HANDLER_CONFIG_FILE_LOCATION; + handlers = ConfigurationUtil.getHandlers(servletContext.getResourceAsStream(handlerConfigFileName)); + } + + chain.addAll(HandlerUtil.getHandlers(handlers)); + + this.initKeyProvider(context); + this.populateChainConfig(); + this.initializeHandlerChain(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + if (this.picketLinkConfiguration == null) { + this.picketLinkConfiguration = new PicketLinkType(); + + this.picketLinkConfiguration.setIdpOrSP(getConfiguration()); + this.picketLinkConfiguration.setHandlers(handlers); + } + } + + /** + *

+ * Indicates if digital signatures/validation of SAML assertions are enabled. + * Subclasses that supports signature should override this method. + *

+ * + * @return true if SP Configuration supports signature + */ + protected boolean doSupportSignature() { + if (spConfiguration != null) { + return spConfiguration.isSupportsSignature(); + } + return false; + } + + protected abstract void initKeyProvider(Context context) throws LifecycleException; + + public void setAuditHelper(PicketLinkAuditHelper auditHelper) { + this.auditHelper = auditHelper; + } +} diff --git a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/SecurityActions.java b/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/SecurityActions.java similarity index 100% rename from saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/SecurityActions.java rename to sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/SecurityActions.java diff --git a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/ServiceProviderAuthenticator.java b/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/ServiceProviderAuthenticator.java similarity index 65% rename from saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/ServiceProviderAuthenticator.java rename to sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/ServiceProviderAuthenticator.java index ae8afcacd..e5314939f 100644 --- a/saml/gatein-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/ServiceProviderAuthenticator.java +++ b/sso-saml-plugin/src/main/java/org/gatein/sso/saml/plugin/valve/ServiceProviderAuthenticator.java @@ -2,12 +2,6 @@ import org.apache.catalina.LifecycleException; - -/** - * Unified Service Provider Authenticator - * Forked from org.picketlink.identity.federation.bindings.tomcat.sp.ServiceProviderAuthenticator - * and made compatible with Tomcat 8.5 since picketlink doesn't provide such a support - */ public class ServiceProviderAuthenticator extends AbstractSPFormAuthenticator { @Override diff --git a/sso-saml-plugin/src/main/java/org/jboss/security/Group.java b/sso-saml-plugin/src/main/java/org/jboss/security/Group.java new file mode 100644 index 000000000..d0de68131 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/jboss/security/Group.java @@ -0,0 +1,16 @@ +package org.jboss.security; + +import java.security.Principal; +import java.util.Enumeration; + +public interface Group extends Principal { + + public boolean addMember(Principal user); + + public boolean removeMember(Principal user); + + public boolean isMember(Principal member); + + public Enumeration members(); + +} diff --git a/spnegosso/src/main/java/org/gatein/security/sso/spnego/SPNEGOSSOContext.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/servlets/SOAPSAMLXACMLServlet.java similarity index 55% rename from spnegosso/src/main/java/org/gatein/security/sso/spnego/SPNEGOSSOContext.java rename to sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/servlets/SOAPSAMLXACMLServlet.java index ef93badc6..4c4058324 100644 --- a/spnegosso/src/main/java/org/gatein/security/sso/spnego/SPNEGOSSOContext.java +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/servlets/SOAPSAMLXACMLServlet.java @@ -1,5 +1,8 @@ /* - * Copyright (C) 2012 eXo Platform SAS. + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as @@ -16,17 +19,14 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.gatein.security.sso.spnego; +package org.picketlink.identity.federation.bindings.servlets; -import javax.servlet.http.HttpServletRequest; - -public class SPNEGOSSOContext { - private static ThreadLocal currentRequest = new ThreadLocal(); - - public static void setCurrentRequest(HttpServletRequest req) { - currentRequest.set(req); - } - public static HttpServletRequest getCurrentRequest() { - return currentRequest.get(); - } -} +/** + * Servlet that can read SOAP 1.1 messages that contain an XACML query in saml payload + * + * @author Anil.Saldhana@redhat.com + * @since Jan 27, 2009 + */ +public class SOAPSAMLXACMLServlet extends org.picketlink.identity.federation.web.servlets.saml.SOAPSAMLXACMLServlet { + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/servlets/SecurityActions.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/servlets/SecurityActions.java new file mode 100644 index 000000000..615b2e1f6 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/servlets/SecurityActions.java @@ -0,0 +1,46 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.servlets; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Privileged Blocks + * + * @author Anil.Saldhana@redhat.com + * @since Mar 17, 2009 + */ +class SecurityActions { + static void setSystemProperty(final String key, final String value) { + if (System.getSecurityManager() != null) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + System.setProperty(key, value); + return null; + } + }); + } else { + System.setProperty(key, value); + } + } +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/stspool/STSClientPoolFactory.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/stspool/STSClientPoolFactory.java new file mode 100644 index 000000000..b255fea34 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/stspool/STSClientPoolFactory.java @@ -0,0 +1,146 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * Licensed 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.picketlink.identity.federation.bindings.stspool; + +import org.picketlink.identity.federation.core.wstrust.STSClient; +import org.picketlink.identity.federation.core.wstrust.STSClientConfig; +import org.picketlink.identity.federation.core.wstrust.STSClientCreationCallBack; +import org.picketlink.identity.federation.core.wstrust.STSClientPool; +import org.picketlink.identity.federation.core.wstrust.STSClientFactory; + + +/** + * Simple factory for creating {@link STSClient}s. + * + * @author Peter Skopek + */ +public final class STSClientPoolFactory implements STSClientPool { + + private STSClientPoolInternal stsClientPoolInternal; + + private STSClientPoolFactory() { + stsClientPoolInternal = new STSClientPoolInternal(); + } + + private static class LazySTSClientFactory { + private static final STSClientPoolFactory INSTANCE = new STSClientPoolFactory(); + } + + /** + * Get instance of {@link STSClientPool}. + * + * @return {@link STSClientPool} instance + */ + public static STSClientPool getPoolInstance() { + STSClientPoolFactory cf = LazySTSClientFactory.INSTANCE; + STSClientFactory.setInstance(cf); + return cf; + } + + /** + * This method initializes sub pool of clients by given configuration data and returns client from that pool. + * + * When pooling is disabled it does nothing. + * + * @param config to construct the pool of clients + */ + public void createPool(final STSClientConfig config) { + createPool(STSClientPoolInternal.DEFAULT_NUM_STS_CLIENTS, config); + } + + /** + * This method initializes sub pool of clients by given configuration data and returns client from that pool. + * initialNumberOfClients is used to initialize the pool for the given number of clients. + * + * When pooling is disabled it does nothing. + * + * @param initialNumberOfClients initial number of clients in the pool + * @param config to construct the pool of clients + */ + public void createPool(int initialNumberOfClients, final STSClientConfig config) { + stsClientPoolInternal.initialize(initialNumberOfClients, config); + } + + /** + * This method initializes sub pool of clients by given configuration data. + * initialNumberOfClients is used to initialize the pool for the given number of clients. + * + * When pooling is disabled it does nothing. + * + * @param initialNumberOfClients initial number of clients in the pool + * @param callBack which provide configuration + */ + + public void createPool(int initialNumberOfClients, final STSClientCreationCallBack callBack) { + stsClientPoolInternal.initialize(initialNumberOfClients, callBack); + } + + /** + * Destroys client sub pool denoted by given config. + * + * @param config {@link STSClientConfiguration} to find client sub pool to destroy + */ + public void destroyPool(final STSClientConfig config) { + stsClientPoolInternal.destroy(config); + } + + + /** + * Destroy all the pools attached to given module name. + * + * @param moduleName module name to destroy pools or "" or null to destroy default module's pools. + */ + public void destroyPool(final String moduleName) { + stsClientPoolInternal.destroy(moduleName); + } + + /** + * Returns given {@link STSClient} back to the sub pool of clients. + * Sub pool is determined automatically from client configuration. + * + * @param {@link STSClient} to return back to the sub pool of clients + */ + public void returnClient(final STSClient stsClient) { + stsClientPoolInternal.putIn(stsClient); + } + + /** + * Get STSClient from sub pool denoted by config. + * @param config {@link STSClientConfiguration} to find client sub pool + * @return {@link STSClient} from the sub pool of clients + */ + public STSClient getClient(final STSClientConfig config) { + STSClient client = stsClientPoolInternal.takeOut(config); + if (client == null) { + // non pooled client + return new STSClient(config); + } + return client; + } + + /** + * Checks whether given config has already sub pool of clients created. + * + * @param config {@link STSClientConfiguration} to find client sub pool + * @return true if config was already used as sub pool key + */ + public boolean configExists(final STSClientConfig config) { + return stsClientPoolInternal.isConfigInitialized(config); + } + +} diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/stspool/STSClientPoolInternal.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/stspool/STSClientPoolInternal.java new file mode 100644 index 000000000..c671d23d6 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/stspool/STSClientPoolInternal.java @@ -0,0 +1,292 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * Licensed 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.picketlink.identity.federation.bindings.stspool; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Hashtable; +import org.picketlink.common.PicketLinkLogger; +import org.picketlink.common.PicketLinkLoggerFactory; +import org.picketlink.identity.federation.bindings.util.ModuleUtils; +import org.picketlink.identity.federation.core.wstrust.STSClient; +import org.picketlink.identity.federation.core.wstrust.STSClientConfig; +import org.picketlink.identity.federation.core.wstrust.STSClientConfigKeyProvider; +import org.picketlink.identity.federation.core.wstrust.STSClientCreationCallBack; + +/** + * Simple pool of {@link STSClient} classes. + * This class is not intended to be used directly by user code. Use {@link STSClientPoolFactory} class instead. + * + * @author Peter Skopek : pskopek at (redhat.com) + * + */ +class STSClientPoolInternal { + + private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); + static int DEFAULT_NUM_STS_CLIENTS = 10; + + private Hashtable> free = new Hashtable>(); + private Hashtable> inUse = new Hashtable>(); + private Hashtable configs = new Hashtable(); + + STSClientPoolInternal() { + } + + void initialize(int numberOfSTSClients, STSClientConfig stsClientConfig) { + internalInitialize(numberOfSTSClients, stsClientConfig, null); + } + + void initialize(STSClientConfig stsClientConfig) { + internalInitialize(DEFAULT_NUM_STS_CLIENTS, stsClientConfig, null); + } + + + void initialize(int numberOfSTSClients, STSClientCreationCallBack clientCreationCallBack) { + internalInitialize(numberOfSTSClients, null, clientCreationCallBack); + } + + private synchronized void internalInitialize(final int numberOfSTSClients, STSClientConfig stsClientConfig, STSClientCreationCallBack clientCreationCallBack) { + + if (numberOfSTSClients <= 0) { + return; + } + + + String key = null; + if (clientCreationCallBack != null) { + key = substituteKey(clientCreationCallBack.getKey()); + } else { + key = key(stsClientConfig); + } + + if (!configs.containsKey(key)) { + ArrayList clients = new ArrayList(numberOfSTSClients); + if (clientCreationCallBack != null) { + for (int i = 0; i < numberOfSTSClients; i++) { + clients.add(clientCreationCallBack.createClient()); + } + } else { + for (int i = 0; i < numberOfSTSClients; i++) { + clients.add(new STSClient(stsClientConfig)); + } + } + STSConfigData configData = new STSConfigData(); + configData.initialNumberOfClients = numberOfSTSClients; + if (clientCreationCallBack != null) { + configData.config = null; + configData.callBack = clientCreationCallBack; + } else { + configData.config = stsClientConfig; + configData.callBack = null; + } + configs.put(key, configData); + free.put(key, clients); + inUse.put(key, new ArrayList(numberOfSTSClients)); + } else { + // free pool already contains given key: + throw logger.freePoolAlreadyContainsGivenKey(key); + } + + } + + synchronized void destroy(STSClientConfig stsClientConfig) { + String key = key(stsClientConfig); + free.remove(key); + inUse.remove(key); + configs.remove(key); + } + + synchronized void destroy(String moduleName) { + String module = moduleName; + if (moduleName == null || moduleName.isEmpty()) { + module = ModuleUtils.getCurrentModuleId(); + } + int removed = 0; + removeByPrefix(module, free); + removeByPrefix(module, inUse); + removed += removeByPrefix(module, configs); + if (removed == 0) { + // fallback to modified prefix + module = "deployment." + module; + removeByPrefix(module, free); + removeByPrefix(module, inUse); + removeByPrefix(module, configs); + } + } + + + STSClient takeOut(STSClientConfig stsClientConfig) { + String key = key(stsClientConfig); + return takeOutInternal(key); + } + + + STSClient takeOut(String key) { + String substKey = substituteKey(key); + STSClient client = takeOutInternal(substKey); + if (client == null) { + STSConfigData configData = configs.get(substKey); + if (configData == null) { + throw logger.cannotGetSTSConfigByKey(substKey); + } + if (configData.callBack != null) { + internalInitialize(DEFAULT_NUM_STS_CLIENTS, null, configData.callBack); + } + else if (configData.config != null) { + internalInitialize(DEFAULT_NUM_STS_CLIENTS, configData.config, configData.callBack); + } + client = takeOutInternal(substKey); + } + return client; + } + + boolean isConfigInitialized(STSClientConfig stsClientConfig) { + if (stsClientConfig == null) { + return false; + } + STSConfigData configData = configs.get(key(stsClientConfig)); + return (configData != null); + } + + boolean isConfigInitialized(String key) { + if (key == null) { + return false; + } + STSConfigData configData = configs.get(substituteKey(key)); + return (configData != null); + } + + void putIn(STSClientConfigKeyProvider keyProvider, STSClient client) { + putInInternal(substituteKey(keyProvider.getSTSClientConfigKey()), client); + } + + void putIn(String key, STSClient client) { + putInInternal(substituteKey(key), client); + } + + void putIn(STSClient client) { + putInInternal(substituteKey(client.getSTSClientConfigKey()), client); + } + + private synchronized STSClient takeOutInternal(String key) { + // no key substitution + ArrayList clients = free.get(key); + if (clients != null) { + int size = clients.size(); + STSClient client; + if (size > 0) { + client = clients.remove(size - 1); + } else { + addClients(key); + client = clients.remove(clients.size() -1); + } + markInUse(key, client); + return client; + } + return null; + } + + private void addClients(String key) { + // no key substitution + STSConfigData configData = configs.get(key); + if (configData != null) { + ArrayList freeClientPool = free.get(key); + if (freeClientPool != null) { + ArrayList clients = new ArrayList(configData.initialNumberOfClients); + if (configData.config != null) { + for (int i = 0; i < configData.initialNumberOfClients; i++) { + clients.add(new STSClient(configData.config)); + } + } else { + for (int i = 0; i < configData.initialNumberOfClients; i++) { + clients.add(configData.callBack.createClient()); + } + } + freeClientPool.addAll(clients); + } else { + // cannot get free client pool key: + throw logger.cannotGetFreeClientPoolKey(key); + } + } else { + // cannot get STS config by key: + throw logger.cannotGetSTSConfigByKey(key); + } + } + + private void markInUse(String key, STSClient client) { + // no key substitution + ArrayList usedClients = inUse.get(key); + if (usedClients != null) { + usedClients.add(client); + } else { + // cannot get used clients by key: + logger.cannotGetUsedClientsByKey(key); + } + } + + private synchronized void putInInternal(String key, STSClient client) { + // no key substitution + STSConfigData configData = configs.get(key); + if (configData == null) { + // attempt to return client not from pool, we can silently ignore it + return; + } + + ArrayList freeClients = free.get(key); + ArrayList usedClients = inUse.get(key); + + if (usedClients != null && !usedClients.remove(client)) { + // removing non existing client from used clients by key: + throw logger.removingNonExistingClientFromUsedClientsByKey(key); + } + + freeClients.add(client); + + } + + private String key(STSClientConfig stsClientConfig) { + return substituteKey(stsClientConfig.getSTSClientConfigKey()); + } + + private String substituteKey(String originalKey) { + if (originalKey != null && originalKey.indexOf(STSClientConfig.SUBSTITUTE_MODULE) != -1) { + return originalKey.replaceAll("\\Q" + STSClientConfig.SUBSTITUTE_MODULE + "\\E", ModuleUtils.getCurrentModuleId()); + } + return originalKey; + } + + private int removeByPrefix(String prefix, Hashtable hashTbl) { + int num = 0; + Enumeration keys = hashTbl.keys(); + while(keys.hasMoreElements()) { + String k = keys.nextElement(); + if (k.startsWith(prefix)) { + num++; + hashTbl.remove(k); + } + } + return num; + } + +} + +class STSConfigData { + STSClientConfig config; + STSClientCreationCallBack callBack; + int initialNumberOfClients = STSClientPoolInternal.DEFAULT_NUM_STS_CLIENTS; +} diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/AbstractGenericHeaderAuthenticator.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/AbstractGenericHeaderAuthenticator.java new file mode 100644 index 000000000..5f2008726 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/AbstractGenericHeaderAuthenticator.java @@ -0,0 +1,235 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * Licensed 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.picketlink.identity.federation.bindings.tomcat; + +import java.io.IOException; +import java.security.Principal; +import java.util.StringTokenizer; + +import org.apache.catalina.Realm; +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.Constants; +import org.apache.catalina.authenticator.FormAuthenticator; +import org.apache.catalina.connector.Request; +import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.picketlink.common.PicketLinkLogger; +import org.picketlink.common.PicketLinkLoggerFactory; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * JBAS-2283: Provide custom header based authentication support + * + * Header Authenticator that deals with userid from the request header Requires two attributes configured on the Tomcat Service + * - one for the http header denoting the authenticated identity and the other is the SESSION cookie + * + * @author Anil Saldhana + * @author Stefan Guilhen + * @version $Revision$ + * @since Sep 11, 2006 + */ +public abstract class AbstractGenericHeaderAuthenticator extends FormAuthenticator { + + protected static final PicketLinkLogger log = PicketLinkLoggerFactory.getLogger(); + + // JBAS-4804: AbstractGenericHeaderAuthenticator injection of ssoid and sessioncookie name. + private String httpHeaderForSSOAuth = null; + + private String sessionCookieForSSOAuth = null; + + /** + *

+ * Obtain the value of the httpHeaderForSSOAuth attribute. This attribute is used to indicate the request + * header ids that have to be checked in order to retrieve the SSO identity set by a third party security system. + *

+ * + * @return a String containing the value of the httpHeaderForSSOAuth attribute. + */ + public String getHttpHeaderForSSOAuth() { + return httpHeaderForSSOAuth; + } + + /** + *

+ * Set the value of the httpHeaderForSSOAuth attribute. This attribute is used to indicate the request header + * ids that have to be checked in order to retrieve the SSO identity set by a third party security system. + *

+ * + * @param httpHeaderForSSOAuth a String containing the value of the httpHeaderForSSOAuth + * attribute. + */ + public void setHttpHeaderForSSOAuth(String httpHeaderForSSOAuth) { + this.httpHeaderForSSOAuth = httpHeaderForSSOAuth; + } + + /** + *

+ * Obtain the value of the sessionCookieForSSOAuth attribute. This attribute is used to indicate the names of + * the SSO cookies that may be present in the request object. + *

+ * + * @return a String containing the names (separated by a ',') of the SSO cookies that may have + * been set by a third party security system in the request. + */ + public String getSessionCookieForSSOAuth() { + return sessionCookieForSSOAuth; + } + + /** + *

+ * Set the value of the sessionCookieForSSOAuth attribute. This attribute is used to indicate the names of the + * SSO cookies that may be present in the request object. + *

+ * + * @param sessionCookieForSSOAuth a String containing the names (separated by a ',') of the SSO + * cookies that may have been set by a third party security system in the request. + */ + public void setSessionCookieForSSOAuth(String sessionCookieForSSOAuth) { + this.sessionCookieForSSOAuth = sessionCookieForSSOAuth; + } + + /** + *

+ * Creates an instance of AbstractGenericHeaderAuthenticator. + *

+ */ + public AbstractGenericHeaderAuthenticator() { + super(); + } + + public boolean performAuthentication(Request request, HttpServletResponse response, LoginConfig config) throws IOException { + boolean trace = log.isTraceEnabled(); + if (log.isTraceEnabled()) { + log.trace("Authenticating user"); + } + + Principal principal = request.getUserPrincipal(); + if (principal != null) { + if (trace) + log.trace("Already authenticated '" + principal.getName() + "'"); + return true; + } + + Realm realm = context.getRealm(); + Session session = request.getSessionInternal(true); + + String username = getUserId(request); + String password = getSessionCookie(request); + + // Check if there is sso id as well as sessionkey + if (username == null || password == null) { + if (log.isTraceEnabled()) { + log.trace("Username is null or password(sessionkey) is null:fallback to form auth"); + } + return super.authenticate(request, response); + } + principal = realm.authenticate(username, password); + + if (principal == null) { + forwardToErrorPage(request, response, config); + return false; + } + + session.setNote(Constants.SESS_USERNAME_NOTE, username); + session.setNote(Constants.SESS_PASSWORD_NOTE, password); + request.setUserPrincipal(principal); + + register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password); + return true; + } + + /** + * Get the username from the request header + * + * @param request + * @return + */ + protected String getUserId(Request request) { + String ssoid = null; + // We can have a comma-separated ids + String ids = this.httpHeaderForSSOAuth; + + if (ids == null || ids.length() == 0) + throw new IllegalStateException("Http headers configuration in tomcat service missing"); + + StringTokenizer st = new StringTokenizer(ids, ","); + while (st.hasMoreTokens()) { + ssoid = request.getHeader(st.nextToken()); + if (ssoid != null) + break; + } + if (log.isTraceEnabled()) { + log.trace("SSOID-" + ssoid); + } + return ssoid; + } + + /** + * Obtain the session cookie from the request + * + * @param request + * @return + */ + protected String getSessionCookie(Request request) { + Cookie[] cookies = request.getCookies(); + log.trace("Cookies:" + cookies); + int numCookies = cookies != null ? cookies.length : 0; + + // We can have comma-separated ids + String ids = sessionCookieForSSOAuth; + + if (ids == null || ids.length() == 0) + throw new IllegalStateException("Session cookies configuration in tomcat service missing"); + + StringTokenizer st = new StringTokenizer(ids, ","); + while (st.hasMoreTokens()) { + String cookieToken = st.nextToken(); + String val = getCookieValue(cookies, numCookies, cookieToken); + if (val != null) + return val; + } + if (log.isTraceEnabled()) { + log.trace("Session Cookie not found"); + } + return null; + } + + /** + * Get the value of a cookie if the name matches the token + * + * @param cookies array of cookies + * @param numCookies number of cookies in the array + * @param token Key + * @return value of cookie + */ + protected String getCookieValue(Cookie[] cookies, int numCookies, String token) { + for (int i = 0; i < numCookies; i++) { + Cookie cookie = cookies[i]; + log.trace("Matching cookieToken:" + token + " with cookie name=" + cookie.getName()); + if (token.equals(cookie.getName())) { + if (log.isTraceEnabled()) { + log.trace("Cookie-" + token + " value=" + cookie.getValue()); + } + return cookie.getValue(); + } + } + return null; + } +} diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/AbstractPicketLinkAuthenticator.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/AbstractPicketLinkAuthenticator.java new file mode 100644 index 000000000..48d4074a1 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/AbstractPicketLinkAuthenticator.java @@ -0,0 +1,202 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2012, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.picketlink.identity.federation.bindings.tomcat; + +import java.io.IOException; +import java.security.AccessController; +import java.security.Principal; +import java.security.PrivilegedAction; +import java.util.Set; +import java.util.UUID; + +import javax.security.auth.Subject; + +import org.apache.catalina.Realm; +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.AuthenticatorBase; +import org.apache.catalina.authenticator.Constants; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.picketlink.common.PicketLinkLogger; +import org.picketlink.common.PicketLinkLoggerFactory; + +/** + *

An authenticator that delegates actual authentication to a realm, and in turn to a security manager, by presenting a + * "conventional" identity. The security manager must accept the conventional identity and generate the real identity for the + * authenticated principal.

+ *

Subclasses should override some methods to provide especific implementation according with the binding/environment.

+ * + * @author Ovidiu Feodorov + * @author Anil.Saldhana@redhat.com + * @author Pedro Silva + * + */ +public abstract class AbstractPicketLinkAuthenticator extends AuthenticatorBase { + + protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); + + /** + * This is the auth method used in the register method + */ + protected String authMethod = "SECURITY_DOMAIN"; + + /** + * The authenticator may not be aware of the user name until after the underlying security exercise is complete. The Subject + * will have the proper user name. Hence we may need to perform an additional authentication now with the user name we have + * obtained. + */ + protected boolean needSubjectPrincipalSubstitution = true; + + protected SubjectSecurityInteraction subjectInteraction = null; + + protected String subjectInteractionClassName = "org.picketlink.identity.federation.bindings.jboss.subject.PicketLinkJBossSubjectInteraction"; + + /** + * Set the auth method via WEB-INF/context.xml (JBoss AS) + * + * @param authMethod + */ + public void setAuthMethod(String authMethod) { + this.authMethod = authMethod; + } + + public void setNeedSubjectPrincipalSubstitution(String needSubjectPrincipalSubstitutionVal) { + this.needSubjectPrincipalSubstitution = Boolean.valueOf(needSubjectPrincipalSubstitutionVal); + } + + /** + * Set this if you want to override the default {@link SubjectSecurityInteraction} + * + * @param subjectRetrieverClassName + */ + public void setSubjectInteractionClassName(String subjectRetrieverClassName) { + this.subjectInteractionClassName = subjectRetrieverClassName; + } + + /** + *

Actually performs the authentication. Subclasses should call this method when implementing the AuthenticatorBase.authenticate method.

+ *

This method was created to allow different signatures for the AuthenticatorBase.authenticate method according with the catalina version.

+ * + * @param request + * @param response + * @param loginConfig + * @return + * @throws IOException + */ + protected boolean performAuthentication(Request request, Response response, LoginConfig loginConfig) throws IOException { + logger.trace("Authenticating user"); + + Principal principal = request.getUserPrincipal(); + if (principal != null) { + logger.trace("Already authenticated '" + principal.getName() + "'"); + return true; + } + + Session session = request.getSessionInternal(true); + String userName = UUID.randomUUID().toString(); + String password = userName; + Realm realm = context.getRealm(); + + principal = realm.authenticate(userName, password); + Principal originalPrincipal = principal; + + if (principal != null) { + if (needSubjectPrincipalSubstitution) { + principal = getSubjectPrincipal(); + if (principal == null) + throw new RuntimeException("Principal from subject is null"); + principal = realm.authenticate(principal.getName(), password); + } + session.setNote(Constants.SESS_USERNAME_NOTE, principal.getName()); + session.setNote(Constants.SESS_PASSWORD_NOTE, password); + request.setUserPrincipal(principal); + doRegister(request, response, principal, password); + if (originalPrincipal != null && needSubjectPrincipalSubstitution) { + subjectInteraction.cleanup(originalPrincipal); + } + return true; + } + + return false; + } + + /** + *

Subclasses should override this method to register an authenticated Principal.

+ * + * @param request + * @param response + * @param principal + * @param password + */ + protected abstract void doRegister(Request request, Response response, Principal principal, String password); + + protected Principal getSubjectPrincipal() { + if (subjectInteraction == null) { + Class clazz = loadClass(getClass(), subjectInteractionClassName); + try { + subjectInteraction = (SubjectSecurityInteraction) clazz.newInstance(); + subjectInteraction.setSecurityDomain(context.getRealm().getContainer().getName()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + Subject subject = subjectInteraction.get(); + if (subject != null) { + Set principals = subject.getPrincipals(); + if (!principals.isEmpty()) { + return subject.getPrincipals().iterator().next(); + } + } + return null; + } + + Class loadClass(final Class theClass, final String fqn) { + return AccessController.doPrivileged(new PrivilegedAction>() { + public Class run() { + ClassLoader classLoader = theClass.getClassLoader(); + + Class clazz = loadClass(classLoader, fqn); + if (clazz == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + clazz = loadClass(classLoader, fqn); + } + return clazz; + } + }); + } + + Class loadClass(final ClassLoader cl, final String fqn) { + return AccessController.doPrivileged(new PrivilegedAction>() { + public Class run() { + try { + return cl.loadClass(fqn); + } catch (ClassNotFoundException e) { + } + return null; + } + }); + } + +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SSLValve.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SSLValve.java new file mode 100644 index 000000000..863bb30e0 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SSLValve.java @@ -0,0 +1,103 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * Licensed 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.picketlink.identity.federation.bindings.tomcat; + +import java.io.IOException; +import java.io.ByteArrayInputStream; + +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import jakarta.servlet.ServletException; + +import org.apache.catalina.valves.ValveBase; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.picketlink.common.PicketLinkLogger; +import org.picketlink.common.PicketLinkLoggerFactory; + +/** + * Valve to fill the SSL information in the request + * mod_header is used to fill the headers and the valve + * will fill the parameters of the request. + * In httpd.conf add the following: + * + * + * RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s" + * RequestHeader set SSL_CIPHER "%{SSL_CIPHER}s" + * RequestHeader set SSL_SESSION_ID "%{SSL_SESSION_ID}s" + * RequestHeader set SSL_CIPHER_USEKEYSIZE "%{SSL_CIPHER_USEKEYSIZE}s" + * + * + * Visit: https://community.jboss.org/wiki/SSLModproxyForwarding + * + * @author Jean-Frederic Clere + * @author Anil Saldhana + * @since November 07, 2013 + */ +public class SSLValve extends ValveBase{ + protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); + + @Override + public void invoke(Request request, Response response) throws IOException, ServletException { + + // mod_header converts the '\n' into ' ' so we have to rebuild the client certificate + String strcert0 = request.getHeader("ssl_client_cert"); + + if (isNotNull(strcert0)) { + + String strcert1 = strcert0.replace(' ', '\n'); + String strcert2 = strcert1.substring(28, strcert1.length()-26); + String strcert3 = new String("-----BEGIN CERTIFICATE-----\n"); + String strcert4 = strcert3.concat(strcert2); + String strcerts = strcert4.concat("\n-----END CERTIFICATE-----\n"); + + // ByteArrayInputStream bais = new ByteArrayInputStream(strcerts.getBytes("UTF-8")); + ByteArrayInputStream bais = new ByteArrayInputStream(strcerts.getBytes()); + X509Certificate jsseCerts[] = null; + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); + jsseCerts = new X509Certificate[1]; + jsseCerts[0] = cert; + } catch (CertificateException certificateException) { + logger.error("SSLValve failed :" + strcerts); + logger.error(certificateException); + } + request.setAttribute("jakarta.servlet.request.X509Certificate", jsseCerts); + } + strcert0 = request.getHeader("ssl_cipher"); + if (isNotNull(strcert0)) { + request.setAttribute("jakarta.servlet.request.cipher_suite", strcert0); + } + strcert0 = request.getHeader("ssl_session_id"); + if (isNotNull(strcert0)) { + request.setAttribute("jakarta.servlet.request.ssl_session", strcert0); + } + strcert0 = request.getHeader("ssl_cipher_usekeysize"); + if (isNotNull(strcert0)) { + request.setAttribute("jakarta.servlet.request.key_size", strcert0); + } + getNext().invoke(request, response); + } + + private boolean isNotNull(String str) { + return str != null && !"".equals(str.trim()); + } +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SecurityActions.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SecurityActions.java new file mode 100644 index 000000000..9e5cb808d --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SecurityActions.java @@ -0,0 +1,122 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.tomcat; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Privileged Blocks + * + * @author Anil.Saldhana@redhat.com + * @since Dec 9, 2008 + */ +class SecurityActions { + + /** + *

+ * Loads a {@link Class} using the fullQualifiedName supplied. This method tries first to load from the + * specified {@link Class}, if not found it will try to load from using TCL. + *

+ * + * @param theClass + * @param fullQualifiedName + * @return + */ + static Class loadClass(final Class theClass, final String fullQualifiedName) { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction>() { + public Class run() { + ClassLoader classLoader = theClass.getClassLoader(); + + Class clazz = loadClass(classLoader, fullQualifiedName); + if (clazz == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + clazz = loadClass(classLoader, fullQualifiedName); + } + return clazz; + } + }); + } else { + ClassLoader classLoader = theClass.getClassLoader(); + + Class clazz = loadClass(classLoader, fullQualifiedName); + if (clazz == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + clazz = loadClass(classLoader, fullQualifiedName); + } + return clazz; + } + } + + /** + *

+ * Loads a class from the specified {@link ClassLoader} using the fullQualifiedName supplied. + *

+ * + * @param classLoader + * @param fullQualifiedName + * @return + */ + static Class loadClass(final ClassLoader classLoader, final String fullQualifiedName) { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction>() { + public Class run() { + try { + return classLoader.loadClass(fullQualifiedName); + } catch (ClassNotFoundException e) { + } + return null; + } + }); + } else { + try { + return classLoader.loadClass(fullQualifiedName); + } catch (ClassNotFoundException e) { + } + return null; + } + } + + /** + * Get a system property + * + * @param key the key for the property + * @param defaultValue A default value to return if the property is not set (Can be null) + * @return + */ + static String getProperty(final String key, final String defaultValue) { + if (System.getSecurityManager() != null) { + return AccessController.doPrivileged(new PrivilegedAction() { + public String run() { + return System.getProperty(key, defaultValue); + } + }); + } else { + return System.getProperty(key, defaultValue); + } + } +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SubjectSecurityInteraction.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SubjectSecurityInteraction.java new file mode 100644 index 000000000..5cb5a26ef --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SubjectSecurityInteraction.java @@ -0,0 +1,56 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.tomcat; + +import java.security.Principal; + +import javax.security.auth.Subject; + +/** + * Interface to retrieve a subject + * + * @author Anil.Saldhana@redhat.com + * @since Sep 13, 2011 + */ +public interface SubjectSecurityInteraction { + /** + * Obtain a subject based on implementation + * + * @return + */ + Subject get(); + + /** + * Clean up the {@link Principal} from the security cache + * + * @param principal + * @return + */ + boolean cleanup(Principal principal); + + /** + *

Sets the security domain name

+ * + * @param securityDomain + */ + void setSecurityDomain(String securityDomain); +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/TomcatAttributeManager.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/TomcatAttributeManager.java new file mode 100644 index 000000000..00470c117 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/TomcatAttributeManager.java @@ -0,0 +1,44 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.tomcat; + +import java.security.Principal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.picketlink.identity.federation.core.interfaces.AttributeManager; + +/** + * An implementation of attribute manager to get attributes of an identity + * + * @author Anil.Saldhana@redhat.com + * @since Aug 31, 2009 + */ +public class TomcatAttributeManager implements AttributeManager { + /** + * @see AttributeManager#getAttributes(Principal, List) + */ + public Map getAttributes(Principal userPrincipal, List attributeKeys) { + return new HashMap(); + } +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/TomcatRoleGenerator.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/TomcatRoleGenerator.java new file mode 100644 index 000000000..112d9338f --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/TomcatRoleGenerator.java @@ -0,0 +1,73 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.tomcat; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.apache.catalina.Role; +import org.apache.catalina.User; +import org.apache.catalina.realm.GenericPrincipal; +import org.picketlink.common.PicketLinkLogger; +import org.picketlink.common.PicketLinkLoggerFactory; +import org.picketlink.identity.federation.core.interfaces.RoleGenerator; + +/** + * Generate roles from Tomcat Principal + * + * @author Anil.Saldhana@redhat.com + * @since Jan 21, 2009 + */ +public class TomcatRoleGenerator implements RoleGenerator { + + private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); + + /** + * @see RoleGenerator#generateRoles(Principal) + * @throws IllegalArgumentException if principal is not of type GenericPrincipal or User + */ + public List generateRoles(Principal principal) { + String className = principal.getClass().getCanonicalName(); + + if (principal instanceof GenericPrincipal == false && principal instanceof User == false) + throw logger.wrongTypeError("principal is not tomcat principal:" + className); + List userRoles = new ArrayList(); + + if (principal instanceof GenericPrincipal) { + GenericPrincipal gp = (GenericPrincipal) principal; + String[] roles = gp.getRoles(); + if (roles.length > 0) + userRoles.addAll(Arrays.asList(roles)); + } else if (principal instanceof User) { + User tomcatUser = (User) principal; + Iterator iter = tomcatUser.getRoles(); + while (iter.hasNext()) { + Role tomcatRole = (Role) iter.next(); + userRoles.add(tomcatRole.getRolename()); + } + } + return userRoles; + } +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/AbstractAccountChooserValve.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/AbstractAccountChooserValve.java new file mode 100644 index 000000000..78ce6625b --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/AbstractAccountChooserValve.java @@ -0,0 +1,333 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * Licensed 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.picketlink.identity.federation.bindings.tomcat.sp; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.catalina.Context; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Session; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.valves.ValveBase; +import org.picketlink.common.PicketLinkLogger; +import org.picketlink.common.PicketLinkLoggerFactory; +import org.picketlink.common.constants.GeneralConstants; +import org.picketlink.common.util.StringUtil; +import org.picketlink.identity.federation.bindings.tomcat.sp.plugins.PropertiesAccountMapProvider; + +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; + +/** + * PLINK-344: Account Chooser At the Service Provider to enable redirection to + * the appropriate IDP + * + * @author Anil Saldhana + * @since January 21, 2014 + */ +public abstract class AbstractAccountChooserValve extends ValveBase implements Lifecycle { + protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); + + public static final String ACCOUNT_CHOOSER_COOKIE_NAME = "picketlink.account.name"; + + public static final String ACCOUNT_PARAMETER = "idp"; + + public static final String AUTHENTICATING = "AUTHENTICATING"; + + public static final String STATE = "STATE"; + + /** + * Domain Name to be used in the cookie that is sent out + */ + protected String domainName; + + protected String accountChooserPage = "/accountChooser.html"; + + protected ConcurrentHashMap idpMap = new ConcurrentHashMap<>(); + + private String accountIDPMapProviderName = PropertiesAccountMapProvider.class.getName(); + + protected AccountIDPMapProvider accountIDPMapProvider; + + /** + * Sets the account chooser cookie expiry. By default, we choose -1 which + * means cookie exists for the remainder of the browser session. + */ + protected int cookieExpiry = -1; + + @Override + public void initInternal() throws LifecycleException { + super.initInternal(); + try { + Class clazz = SecurityActions.loadClass(getClass(), this.accountIDPMapProviderName); + + if (clazz == null) { + throw logger.classNotLoadedError(this.accountIDPMapProviderName); + } + + accountIDPMapProvider = (AccountIDPMapProvider) clazz.newInstance(); + + Context context = (Context) getContainer(); + accountIDPMapProvider.setServletContext(context.getServletContext()); + idpMap.putAll(accountIDPMapProvider.getIDPMap()); + } catch (Exception e) { + throw new LifecycleException("Could not start " + getClass().getName() + ".", e); + } + } + + /** + * Set the domain name for the cookie to be sent to the browser There is no + * default. Setting the domain name for the cookie is optional. + * + * @param domainName + */ + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + /** + * Set the cookie expiry in seconds. Default value is -1 + * + * @param value + */ + public void setCookieExpiry(String value) { + try { + int expiry = Integer.parseInt(value); + cookieExpiry = expiry; + } catch (NumberFormatException nfe) { + logger.processingError(nfe); + } + } + + /** + * Set the fully qualified name of the implementation of + * {@link org.picketlink.identity.federation.bindings.tomcat.sp.AbstractAccountChooserValve.AccountIDPMapProvider} + * Default: + * {@link org.picketlink.identity.federation.bindings.tomcat.sp.plugins.PropertiesAccountMapProvider} + * + * @param idpMapProviderName + */ + public void setAccountIDPMapProvider(String idpMapProviderName) { + this.accountIDPMapProviderName = idpMapProviderName; + } + + /** + * Set the name of the html or jsp page that has the accounts for the user to + * choose. Default: "/accountChooser.html" is used + * + * @param pageName + */ + public void setAccountChooserPage(String pageName) { + this.accountChooserPage = pageName; + } + + @Override + public void invoke(Request request, Response response) throws IOException, ServletException { + Session session = request.getSessionInternal(); + + if (idpMap.isEmpty()) { + idpMap.putAll(accountIDPMapProvider.getIDPMap()); + } + + String sessionState = (String) session.getNote(STATE); + + String idpChosenKey = request.getParameter(ACCOUNT_PARAMETER); + String cookieValue = cookieValue(request); + if (cookieValue != null || AUTHENTICATING.equals(sessionState)) { + if (idpChosenKey != null) { + String chosenIDP = idpMap.get(idpChosenKey); + request.setAttribute(org.picketlink.identity.federation.web.constants.GeneralConstants.DESIRED_IDP, chosenIDP); + } + + // Case when user is directed to IDP and wants to change the IDP. So he + // enters the URL again + if (AUTHENTICATING.equals(sessionState) && request.getParameter(GeneralConstants.SAML_RESPONSE_KEY) == null) { + session.removeNote(STATE); + redirectToChosenPage(accountChooserPage, request, response); + return; + } + proceedToAuthentication(request, response, cookieValue); + } else { + if (idpChosenKey != null) { + String chosenIDP = idpMap.get(idpChosenKey); + if (chosenIDP != null) { + request.setAttribute(org.picketlink.identity.federation.web.constants.GeneralConstants.DESIRED_IDP, chosenIDP); + session.setNote(STATE, AUTHENTICATING); + proceedToAuthentication(request, response, idpChosenKey); + } else { + logger.configurationFileMissing(":IDP Mapping"); + throw new ServletException(); + } + } else { + // redirect to provided html + // saveRequest(request, request.getSessionInternal()); + redirectToChosenPage(accountChooserPage, request, response); + return; + } + } + } + + /** + * Proceed to the Service Provider Authentication Mechanism + * + * @param request + * @param response + * @param cookieValue + * @throws IOException + * @throws ServletException + */ + protected void proceedToAuthentication(Request request, Response response, String cookieValue) throws IOException, + ServletException { + Session session = request.getSessionInternal(false); + try { + /* + * String sessionState = (String) session.getNote(STATE); // Case when + * user is directed to IDP and wants to change the IDP. So he enters the + * URL again if (AUTHENTICATING.equals(sessionState) && + * request.getParameter(GeneralConstants.SAML_RESPONSE_KEY) == null) { + * session.removeNote(STATE); + * redirectToChosenPage(accountConfirmationPage, request, response); + * return; } + */ + getNext().invoke(request, response); + } finally { + String state = session != null ? (String) session.getNote(STATE) : null; + + // If we are authenticated and registered at the service provider + if (request.getUserPrincipal() != null && StringUtil.isNotNull(state)) { + session.removeNote(STATE); + // Send back a cookie + Context context = (Context) getContainer(); + String contextpath = context.getPath(); + + if (cookieValue == null) { + cookieValue = request.getParameter(AbstractAccountChooserValve.ACCOUNT_PARAMETER); + } + + Cookie cookie = new Cookie(ACCOUNT_CHOOSER_COOKIE_NAME, cookieValue); + cookie.setPath(contextpath); + cookie.setMaxAge(cookieExpiry); + if (domainName != null) { + cookie.setDomain(domainName); + } + response.addCookie(cookie); + } + } + } + + /** + * Redirect user to a page + * + * @param page + * @param request + * @param response + * @throws ServletException + * @throws IOException + */ + protected void redirectToChosenPage(String page, Request request, Response response) throws ServletException, IOException { + Context context = (Context) getContainer(); + RequestDispatcher requestDispatcher = context.getServletContext().getRequestDispatcher(page); + if (requestDispatcher != null) { + requestDispatcher.forward(request.getRequest(), response); + } + } + + protected String cookieValue(Request request) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + String cookieName = cookie.getName(); + String cookieDomain = cookie.getDomain(); + if (cookieDomain != null && cookieDomain.equalsIgnoreCase(domainName)) { + // Found a cookie with the same domain name + if (ACCOUNT_CHOOSER_COOKIE_NAME.equals(cookieName)) { + // Found cookie + String cookieValue = cookie.getValue(); + String chosenIDP = idpMap.get(cookieValue); + if (chosenIDP != null) { + request.setAttribute(org.picketlink.identity.federation.web.constants.GeneralConstants.DESIRED_IDP, chosenIDP); + return cookieValue; + } + } + } else { + if (ACCOUNT_CHOOSER_COOKIE_NAME.equals(cookieName)) { + // Found cookie + String cookieValue = cookie.getValue(); + String chosenIDP = idpMap.get(cookieValue); + if (chosenIDP != null) { + request.setAttribute(org.picketlink.identity.federation.web.constants.GeneralConstants.DESIRED_IDP, chosenIDP); + return cookieValue; + } + } + } + } + } + return null; + } + + /** + * Save the original request information into our session. + * + * @param request The request to be saved + * @param session The session to contain the saved information + * @throws IOException + */ + protected abstract void saveRequest(Request request, Session session) throws IOException; + + /** + * Restore the original request from information stored in our session. If the + * original request is no longer present (because the session timed out), + * return false; otherwise, return true. + * + * @param request The request to be restored + * @param session The session containing the saved information + */ + protected abstract boolean restoreRequest(Request request, Session session) throws IOException; + + /** + * Interface for obtaining the Identity Provider Mapping + */ + public interface AccountIDPMapProvider { + /** + * Set the servlet context for resources on web classpath + * + * @param servletContext + */ + void setServletContext(ServletContext servletContext); + + /** + * Set a {@link java.lang.ClassLoader} for the Provider + * + * @param classLoader + */ + void setClassLoader(ClassLoader classLoader); + + /** + * Get a map of AccountName versus IDP URLs + * + * @return + */ + Map getIDPMap() throws IOException; + } +} diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/AbstractSAML11SPRedirectFormAuthenticator.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/AbstractSAML11SPRedirectFormAuthenticator.java new file mode 100644 index 000000000..a5f7497ac --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/AbstractSAML11SPRedirectFormAuthenticator.java @@ -0,0 +1,134 @@ +package org.picketlink.identity.federation.bindings.tomcat.sp; + +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.Constants; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.picketlink.common.ErrorCodes; +import org.picketlink.common.constants.GeneralConstants; +import org.picketlink.identity.federation.bindings.tomcat.sp.holder.ServiceProviderSAMLContext; +import org.picketlink.identity.federation.core.parsers.saml.SAMLParser; +import org.picketlink.identity.federation.core.saml.v2.util.AssertionUtil; +import org.picketlink.identity.federation.saml.v1.assertion.SAML11AssertionType; +import org.picketlink.identity.federation.saml.v1.assertion.SAML11AuthenticationStatementType; +import org.picketlink.identity.federation.saml.v1.assertion.SAML11StatementAbstractType; +import org.picketlink.identity.federation.saml.v1.assertion.SAML11SubjectType; +import org.picketlink.identity.federation.saml.v1.protocol.SAML11ResponseType; +import org.picketlink.identity.federation.web.util.RedirectBindingUtil; +import org.picketlink.identity.federation.web.util.ServerDetector; + +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.io.InputStream; +import java.security.Principal; +import java.util.ArrayList; +import java.util.List; + +import static org.picketlink.common.util.StringUtil.isNotNull; + +/** + * Authenticator for SAML 1.1 processing at the Service Provider + * @author anil saldhana + * @since Jul 7, 2011 + */ +public abstract class AbstractSAML11SPRedirectFormAuthenticator extends AbstractSPFormAuthenticator { + + @Override + public boolean authenticate(Request request, HttpServletResponse response) throws IOException { + if (handleSAML11UnsolicitedResponse(request, response, this)) { + return true; + } + + logger.trace("Falling back on local Form Authentication if available"); + // fallback + return super.authenticate(request, response); + } + + public static boolean handleSAML11UnsolicitedResponse(Request request, HttpServletResponse response, AbstractSPFormAuthenticator formAuthenticator) throws IOException { + String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); + + Principal principal = request.getUserPrincipal(); + + // If we have already authenticated the user and there is no request from IDP or logout from user + if (principal != null) + return true; + + Session session = request.getSessionInternal(true); + + // See if we got a response from IDP + if (isNotNull(samlResponse)) { + boolean isValid = false; + try { + isValid = formAuthenticator.validate(request); + } catch (Exception e) { + logger.samlSPHandleRequestError(e); + throw new IOException(); + } + if (!isValid) + throw new IOException(ErrorCodes.VALIDATION_CHECK_FAILED); + + try { + InputStream base64DecodedResponse = RedirectBindingUtil.base64DeflateDecode(samlResponse); + SAMLParser parser = new SAMLParser(); + SAML11ResponseType saml11Response = (SAML11ResponseType) parser.parse(base64DecodedResponse); + + List assertions = saml11Response.get(); + if (assertions.size() > 1) { + logger.trace("More than one assertion from IDP. Considering the first one."); + } + String username = null; + List roles = new ArrayList(); + SAML11AssertionType assertion = assertions.get(0); + if (assertion != null) { + // Get the subject + List statements = assertion.getStatements(); + for (SAML11StatementAbstractType statement : statements) { + if (statement instanceof SAML11AuthenticationStatementType) { + SAML11AuthenticationStatementType subStat = (SAML11AuthenticationStatementType) statement; + SAML11SubjectType subject = subStat.getSubject(); + username = subject.getChoice().getNameID().getValue(); + } + } + roles = AssertionUtil.getRoles(assertion, null); + } + + String password = ServiceProviderSAMLContext.EMPTY_PASSWORD; + + // Map to JBoss specific principal + if ((new ServerDetector()).isJboss() || formAuthenticator.jbossEnv) { + // Push a context + ServiceProviderSAMLContext.push(username, roles); + principal = formAuthenticator.getContext().getRealm().authenticate(username, password); + ServiceProviderSAMLContext.clear(); + } else { + // tomcat env + SPUtil spUtil = new SPUtil(); + principal = spUtil.createGenericPrincipal(request, username, roles); + } + + session.setNote(Constants.SESS_USERNAME_NOTE, username); + session.setNote(Constants.SESS_PASSWORD_NOTE, password); + request.setUserPrincipal(principal); + + if (formAuthenticator.saveRestoreRequest) { + formAuthenticator.restoreRequest(request, session); + } + formAuthenticator.register(request, response, principal, FORM_METHOD, username, password); + + return true; + } catch (Exception e) { + logger.samlSPHandleRequestError(e); + } + } + + return false; + } + + protected void startPicketLink() throws LifecycleException{ + super.startPicketLink(); + this.spConfiguration.setBindingType("REDIRECT"); + } +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/AbstractSPFormAuthenticator.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/AbstractSPFormAuthenticator.java new file mode 100644 index 000000000..6154aa660 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/AbstractSPFormAuthenticator.java @@ -0,0 +1,812 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2012, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.picketlink.identity.federation.bindings.tomcat.sp; + +import static org.picketlink.common.util.StringUtil.isNotNull; +import static org.picketlink.common.util.StringUtil.isNullOrEmpty; +import static org.picketlink.identity.federation.bindings.tomcat.sp.AbstractSAML11SPRedirectFormAuthenticator.handleSAML11UnsolicitedResponse; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.security.Principal; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.Constants; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.jboss.security.audit.AuditLevel; +import org.picketlink.common.ErrorCodes; +import org.picketlink.common.constants.GeneralConstants; +import org.picketlink.common.constants.JBossSAMLConstants; +import org.picketlink.common.exceptions.ConfigurationException; +import org.picketlink.common.exceptions.ParsingException; +import org.picketlink.common.exceptions.ProcessingException; +import org.picketlink.common.exceptions.TrustKeyProcessingException; +import org.picketlink.common.exceptions.fed.AssertionExpiredException; +import org.picketlink.common.util.DocumentUtil; +import org.picketlink.common.util.StringUtil; +import org.picketlink.config.federation.AuthPropertyType; +import org.picketlink.config.federation.KeyProviderType; +import org.picketlink.identity.federation.bindings.tomcat.sp.holder.ServiceProviderSAMLContext; +import org.picketlink.identity.federation.core.audit.PicketLinkAuditEvent; +import org.picketlink.identity.federation.core.audit.PicketLinkAuditEventType; +import org.picketlink.identity.federation.core.interfaces.TrustKeyManager; +import org.picketlink.identity.federation.core.saml.v2.holders.DestinationInfoHolder; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerResponse; +import org.picketlink.identity.federation.core.util.CoreConfigUtil; +import org.picketlink.identity.federation.web.core.HTTPContext; +import org.picketlink.identity.federation.web.process.ServiceProviderBaseProcessor; +import org.picketlink.identity.federation.web.process.ServiceProviderSAMLRequestProcessor; +import org.picketlink.identity.federation.web.process.ServiceProviderSAMLResponseProcessor; +import org.picketlink.identity.federation.web.util.HTTPRedirectUtil; +import org.picketlink.identity.federation.web.util.PostBindingUtil; +import org.picketlink.identity.federation.web.util.RedirectBindingUtil; +import org.picketlink.identity.federation.web.util.RedirectBindingUtil.RedirectBindingUtilDestHolder; +import org.picketlink.identity.federation.web.util.ServerDetector; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletResponse; + +/** + *

+ * Abstract class to be extended by Service Provider valves to handle SAML + * requests and responses. + *

+ * + * @author Anil Saldhana + * @author Pedro Silva + */ +public abstract class AbstractSPFormAuthenticator extends BaseFormAuthenticator { + + /** + * The previously authenticated principal (if caching is disabled). + */ + public static final String FORM_PRINCIPAL_NOTE = "org.apache.catalina.authenticator.PRINCIPAL"; + + public static final String FORM_METHOD = "FORM"; + + protected boolean jbossEnv = false; + + AbstractSPFormAuthenticator() { + super(); + ServerDetector detector = new ServerDetector(); + jbossEnv = detector.isJboss(); + } + + /* + * (non-Javadoc) + * @see + * org.picketlink.identity.federation.bindings.tomcat.sp.BaseFormAuthenticator + * #processStart() + */ + @Override + protected void startPicketLink() throws LifecycleException { + super.startPicketLink(); + initKeyProvider(context); + } + + /** + *

+ * Send the request to the IDP. Subclasses should override this method to + * implement how requests must be sent to the IDP. + *

+ * + * @param destination idp url + * @param samlDocument request or response document + * @param relayState + * @param response + * @param request + * @param willSendRequest are we sending Request or Response to IDP + * @param destinationQueryStringWithSignature used only with Redirect binding + * and with signature enabled. + * @throws ProcessingException + * @throws ConfigurationException + * @throws IOException + */ + protected void sendRequestToIDP(String destination, + Document samlDocument, + String relayState, + Request request, + HttpServletResponse response, + boolean willSendRequest, + String destinationQueryStringWithSignature) throws ProcessingException, + ConfigurationException, + IOException { + + if (isAjaxRequest(request) && request.getUserPrincipal() == null) { + response.sendError(Response.SC_FORBIDDEN); + } else { + if (isHttpPostBinding()) { + sendHttpPostBindingRequest(destination, samlDocument, relayState, response, willSendRequest); + } else { + sendHttpRedirectRequest(destination, + samlDocument, + relayState, + response, + willSendRequest, + destinationQueryStringWithSignature); + } + } + } + + /** + *

+ * Sends a HTTP Redirect request to the IDP. + *

+ * + * @param destination + * @param relayState + * @param response + * @param willSendRequest + * @param destinationQueryStringWithSignature + * @throws IOException + * @throws UnsupportedEncodingException + * @throws ConfigurationException + * @throws ProcessingException + */ + protected void sendHttpRedirectRequest(String destination, + Document samlDocument, + String relayState, + HttpServletResponse response, + boolean willSendRequest, + String destinationQueryStringWithSignature) throws IOException, + ProcessingException, + ConfigurationException { + String destinationQueryString = null; + + // We already have queryString with signature from + // SAML2SignatureGenerationHandler + if (destinationQueryStringWithSignature != null) { + destinationQueryString = destinationQueryStringWithSignature; + } else { + String samlMessage = DocumentUtil.getDocumentAsString(samlDocument); + String base64Request = RedirectBindingUtil.deflateBase64URLEncode(samlMessage.getBytes("UTF-8")); + destinationQueryString = RedirectBindingUtil.getDestinationQueryString(base64Request, relayState, willSendRequest); + } + + RedirectBindingUtilDestHolder holder = new RedirectBindingUtilDestHolder(); + + holder.setDestination(destination).setDestinationQueryString(destinationQueryString); + + HTTPRedirectUtil.sendRedirectForRequestor(RedirectBindingUtil.getDestinationURL(holder), response); + } + + /** + *

+ * Sends a HTTP POST request to the IDP. + *

+ * + * @param destination + * @param samlDocument + * @param relayState + * @param response + * @param willSendRequest + * @throws TrustKeyProcessingException + * @throws ProcessingException + * @throws IOException + * @throws ConfigurationException + */ + protected void sendHttpPostBindingRequest(String destination, + Document samlDocument, + String relayState, + HttpServletResponse response, + boolean willSendRequest) throws ProcessingException, + IOException, + ConfigurationException { + String samlMessage = PostBindingUtil.base64Encode(DocumentUtil.getDocumentAsString(samlDocument)); + + DestinationInfoHolder destinationHolder = new DestinationInfoHolder(destination, samlMessage, relayState); + + PostBindingUtil.sendPost(destinationHolder, response, willSendRequest); + } + + /** + *

+ * Initialize the KeyProvider configurations. This configurations are to be + * used during signing and validation of SAML assertions. + *

+ * + * @param context + * @throws LifecycleException + */ + protected void initKeyProvider(Context context) throws LifecycleException { + if (!doSupportSignature()) { + return; + } + + KeyProviderType keyProvider = this.spConfiguration.getKeyProvider(); + + if (keyProvider == null && doSupportSignature()) + throw new LifecycleException(ErrorCodes.NULL_VALUE + "KeyProvider is null for context=" + context.getName()); + + try { + String keyManagerClassName = keyProvider.getClassName(); + if (keyManagerClassName == null) + throw new RuntimeException(ErrorCodes.NULL_VALUE + "KeyManager class name"); + + Class clazz = SecurityActions.loadClass(getClass(), keyManagerClassName); + + if (clazz == null) + throw new ClassNotFoundException(ErrorCodes.CLASS_NOT_LOADED + keyManagerClassName); + this.keyManager = (TrustKeyManager) clazz.newInstance(); + + List authProperties = CoreConfigUtil.getKeyProviderProperties(keyProvider); + + keyManager.setAuthProperties(authProperties); + keyManager.setValidatingAlias(keyProvider.getValidatingAlias()); + + String identityURL = this.spConfiguration.getIdentityURL(); + + // Special case when you need X509Data in SignedInfo + if (authProperties != null) { + for (AuthPropertyType authPropertyType : authProperties) { + String key = authPropertyType.getKey(); + if (GeneralConstants.X509CERTIFICATE.equals(key)) { + // we need X509Certificate in SignedInfo. The value is the alias + // name + keyManager.addAdditionalOption(GeneralConstants.X509CERTIFICATE, authPropertyType.getValue()); + break; + } + } + } + keyManager.addAdditionalOption(ServiceProviderBaseProcessor.IDP_KEY, new URL(identityURL).getHost()); + } catch (Exception e) { + logger.trustKeyManagerCreationError(e); + throw new LifecycleException(e.getLocalizedMessage()); + } + + logger.trace("Key Provider=" + keyProvider.getClassName()); + } + + /** + * Authenticate the request + * + * @param request + * @param response + * @param config + * @return + * @throws IOException + * @throws {@link RuntimeException} when the response is not of type catalina + * response object + */ + public boolean authenticate(Request request, HttpServletResponse response) throws IOException { + return doAuthenticate(request, response); + } + + /* + * (non-Javadoc) + * @see + * org.apache.catalina.authenticator.FormAuthenticator#authenticate(org.apache + * .catalina.connector.Request, org.apache.catalina.connector.Response, + * org.apache.tomcat.util.descriptor.web.LoginConfig) + */ + @Override + protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException { + try { + // needs to be done first, *before* accessing any parameters. + // super.authenticate(..) gets called to late + String characterEncoding = getCharacterEncoding(); + if (characterEncoding != null) { + request.setCharacterEncoding(characterEncoding); + } + + Session session = request.getSessionInternal(true); + + // check if this call is resulting from the redirect after successful + // authentication. + // if so, make the authentication successful and continue the original + // request + if (saveRestoreRequest && matchRequest(request)) { + logger.trace("Restoring request from session '" + session.getIdInternal() + "'"); + Principal savedPrincipal = (Principal) session.getNote(FORM_PRINCIPAL_NOTE); + register(request, + response, + savedPrincipal, + FORM_METHOD, + (String) session.getNote(Constants.SESS_USERNAME_NOTE), + (String) session.getNote(Constants.SESS_PASSWORD_NOTE)); + + // try to restore the original request (including post data, etc...) + if (restoreRequest(request, session)) { + // success! user is authenticated; continue processing original + // request + logger.trace("Continuing with restored request."); + return true; + } else { + // no saved request found... + logger.trace("Restore of original request failed!"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return false; + } + } + + // Eagerly look for Local LogOut + boolean localLogout = isLocalLogout(request); + + if (localLogout) { + try { + sendToLogoutPage(request, response, session); + } catch (ServletException e) { + logger.samlLogoutError(e); + throw new IOException(e); + } + return false; + } + + String samlRequest = request.getParameter(GeneralConstants.SAML_REQUEST_KEY); + String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); + + Principal principal = request.getUserPrincipal(); + + // If we have already authenticated the user and there is no request from + // IDP or logout from user + if (principal != null && !(isGlobalLogout(request) || isNotNull(samlRequest) || isNotNull(samlResponse))) + return true; + + // General User Request + if (!isNotNull(samlRequest) && !isNotNull(samlResponse)) { + return generalUserRequest(request, response); + } + + // Handle a SAML Response from IDP + if (isNotNull(samlResponse)) { + return handleSAMLResponse(request, response); + } + + // Handle SAML Requests from IDP + if (isNotNull(samlRequest)) { + return handleSAMLRequest(request, response); + } // end if + + return localAuthentication(request, response); + } catch (IOException e) { + if (StringUtil.isNotNull(spConfiguration.getErrorPage())) { + try { + request.getRequestDispatcher(spConfiguration.getErrorPage()).forward(request.getRequest(), response); + } catch (ServletException e1) { + logger.samlErrorPageForwardError(spConfiguration.getErrorPage(), e1); + } + return false; + } else { + throw e; + } + } + } + + /** + *

+ * Indicates if the current request is a GlobalLogout request. + *

+ * + * @param request + * @return + */ + private boolean isGlobalLogout(Request request) { + String gloStr = request.getParameter(GeneralConstants.GLOBAL_LOGOUT); + return isNotNull(gloStr) && "true".equalsIgnoreCase(gloStr); + } + + /** + *

+ * Indicates if the current request is a LocalLogout request. + *

+ * + * @param request + * @return + */ + private boolean isLocalLogout(Request request) { + String lloStr = request.getParameter(GeneralConstants.LOCAL_LOGOUT); + return isNotNull(lloStr) && "true".equalsIgnoreCase(lloStr); + } + + /** + * Handle the IDP Request + * + * @param request + * @param response + * @param loginConfig + * @return + * @throws IOException + */ + private boolean handleSAMLRequest(Request request, HttpServletResponse response) throws IOException { + String samlRequest = request.getParameter(GeneralConstants.SAML_REQUEST_KEY); + HTTPContext httpContext = new HTTPContext(request, response, context.getServletContext()); + Set handlers = chain.handlers(); + + try { + ServiceProviderSAMLRequestProcessor requestProcessor = new ServiceProviderSAMLRequestProcessor( + request.getMethod() + .equals("POST"), + this.serviceURL, + this.picketLinkConfiguration); + requestProcessor.setTrustKeyManager(keyManager); + boolean result = requestProcessor.process(samlRequest, httpContext, handlers, chainLock); + + if (enableAudit) { + PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent(AuditLevel.INFO); + auditEvent.setType(PicketLinkAuditEventType.REQUEST_FROM_IDP); + auditEvent.setWhoIsAuditing(getContextPath()); + auditHelper.audit(auditEvent); + } + + // If response is already commited, we need to stop with processing of + // HTTP request + if (response.isCommitted() || response.isCommitted()) + return false; + + if (result) + return result; + } catch (Exception e) { + logger.samlSPHandleRequestError(e); + throw logger.samlSPProcessingExceptionError(e); + } + + return localAuthentication(request, response); + } + + private Document toSAMLResponseDocument(String samlResponse, boolean isPostBinding) throws ParsingException { + InputStream dataStream = null; + + if (isPostBinding) { + // deal with SAML response from IDP + dataStream = PostBindingUtil.base64DecodeAsStream(samlResponse); + } else { + // deal with SAML response from IDP + dataStream = RedirectBindingUtil.base64DeflateDecode(samlResponse); + } + + try { + return DocumentUtil.getDocument(dataStream); + } catch (Exception e) { + logger.samlResponseFromIDPParsingFailed(); + throw new ParsingException("", e); + } + } + + /** + * Handle IDP Response + * + * @param request + * @param response + * @param loginConfig + * @return + * @throws IOException + */ + private boolean handleSAMLResponse(Request request, HttpServletResponse response) throws IOException { + if (!super.validate(request)) { + throw new IOException(ErrorCodes.VALIDATION_CHECK_FAILED); + } + + String samlVersion = getSAMLVersion(request); + + if (!JBossSAMLConstants.VERSION_2_0.get().equals(samlVersion)) { + return handleSAML11UnsolicitedResponse(request, response, this); + } + + return handleSAML2Response(request, response); + } + + private boolean handleSAML2Response(Request request, HttpServletResponse response) throws IOException { + Session session = request.getSessionInternal(true); + String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); + HTTPContext httpContext = new HTTPContext(request, response, context.getServletContext()); + Set handlers = chain.handlers(); + + Principal principal = request.getUserPrincipal(); + + boolean willSendRequest;// deal with SAML response from IDP + + try { + ServiceProviderSAMLResponseProcessor responseProcessor = + new ServiceProviderSAMLResponseProcessor(request.getMethod() + .equals("POST"), + serviceURL, + this.picketLinkConfiguration); + if (auditHelper != null) { + responseProcessor.setAuditHelper(auditHelper); + } + + responseProcessor.setTrustKeyManager(keyManager); + + SAML2HandlerResponse saml2HandlerResponse = responseProcessor.process(samlResponse, + httpContext, + handlers, + chainLock); + + Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); + String relayState = saml2HandlerResponse.getRelayState(); + + String destination = saml2HandlerResponse.getDestination(); + + willSendRequest = saml2HandlerResponse.getSendRequest(); + + String destinationQueryStringWithSignature = saml2HandlerResponse.getDestinationQueryStringWithSignature(); + + if (destination != null && samlResponseDocument != null) { + sendRequestToIDP(destination, + samlResponseDocument, + relayState, + request, + response, + willSendRequest, + destinationQueryStringWithSignature); + } else { + // See if the session has been invalidated + + boolean sessionValidity = session.isValid(); + + if (!sessionValidity) { + sendToLogoutPage(request, response, session); + return false; + } + + // We got a response with the principal + List roles = saml2HandlerResponse.getRoles(); + if (principal == null) + principal = (Principal) session.getSession().getAttribute(GeneralConstants.PRINCIPAL_ID); + + String username = principal.getName(); + String password = ServiceProviderSAMLContext.EMPTY_PASSWORD; + + if (logger.isTraceEnabled()) { + logger.trace("Roles determined for username=" + username + "=" + Arrays.toString(roles.toArray())); + } + + // Map to JBoss specific principal + if ((new ServerDetector()).isJboss() || jbossEnv) { + // Push a context + ServiceProviderSAMLContext.push(username, roles); + principal = context.getRealm().authenticate(username, password); + ServiceProviderSAMLContext.clear(); + } else { + // tomcat env + principal = getGenericPrincipal(request, username, roles); + } + + session.setNote(Constants.SESS_USERNAME_NOTE, username); + session.setNote(Constants.SESS_PASSWORD_NOTE, password); + request.setUserPrincipal(principal); + + if (enableAudit) { + PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent(AuditLevel.INFO); + auditEvent.setType(PicketLinkAuditEventType.RESPONSE_FROM_IDP); + auditEvent.setSubjectName(username); + auditEvent.setWhoIsAuditing(getContextPath()); + auditHelper.audit(auditEvent); + } + + // Redirect the user to the originally requested URL + if (saveRestoreRequest) { + // Store the authenticated principal in the session. + session.setNote(FORM_PRINCIPAL_NOTE, principal); + + // Redirect to the original URL. Note that this will trigger the + // authenticator again, but on resubmission we will look in the + // session notes to retrieve the authenticated principal and + // prevent reauthentication + String requestURI = savedRequestURL(session); + + if (requestURI != null) { + logger.trace("Redirecting back to original Request URI: " + requestURI); + response.sendRedirect(response.encodeRedirectURL(requestURI)); + } + } + + register(request, response, principal, FORM_METHOD, username, password); + return true; + } + } catch (ProcessingException pe) { + Throwable t = pe.getCause(); + if (t != null && t instanceof AssertionExpiredException) { + logger.error("Assertion has expired. Asking IDP for reissue"); + if (enableAudit) { + PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent(AuditLevel.INFO); + auditEvent.setType(PicketLinkAuditEventType.EXPIRED_ASSERTION); + auditEvent.setAssertionID(((AssertionExpiredException) t).getId()); + auditHelper.audit(auditEvent); + } + // Just issue a fresh request back to IDP + return generalUserRequest(request, response); + } + logger.samlSPHandleRequestError(pe); + throw logger.samlSPProcessingExceptionError(pe); + } catch (Exception e) { + logger.samlSPHandleRequestError(e); + throw logger.samlSPProcessingExceptionError(e); + } + + return localAuthentication(request, response); + } + + private String getSAMLVersion(Request request) { + String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); + String version; + + try { + Document samlDocument = toSAMLResponseDocument(samlResponse, "POST".equalsIgnoreCase(request.getMethod())); + Element element = samlDocument.getDocumentElement(); + + // let's try SAML 2.0 Version attribute first + version = element.getAttribute("Version"); + + if (isNullOrEmpty(version)) { + // fallback to SAML 1.1 Minor and Major attributes + String minorVersion = element.getAttribute("MinorVersion"); + String majorVersion = element.getAttribute("MajorVersion"); + + version = minorVersion + "." + majorVersion; + } + } catch (Exception e) { + throw new RuntimeException("Could not extract version from SAML Response.", e); + } + + return version; + } + + protected boolean isPOSTBindingResponse() { + return spConfiguration.isIdpUsesPostBinding(); + } + + /* + * (non-Javadoc) + * @see + * org.picketlink.identity.federation.bindings.tomcat.sp.BaseFormAuthenticator + * #getBinding() + */ + @Override + protected String getBinding() { + return spConfiguration.getBindingType(); + } + + /** + * Handle the user invocation for the first time + * + * @param request + * @param response + * @param loginConfig + * @return + * @throws IOException + */ + private boolean generalUserRequest(Request request, HttpServletResponse response) throws IOException { + Session session = request.getSessionInternal(true); + boolean willSendRequest = false; + HTTPContext httpContext = new HTTPContext(request, response, context.getServletContext()); + Set handlers = chain.handlers(); + + boolean postBinding = spConfiguration.getBindingType().equals("POST"); + + // Neither saml request nor response from IDP + // So this is a user request + SAML2HandlerResponse saml2HandlerResponse = null; + try { + ServiceProviderBaseProcessor baseProcessor = new ServiceProviderBaseProcessor(postBinding, + serviceURL, + this.picketLinkConfiguration); + if (issuerID != null) + baseProcessor.setIssuer(issuerID); + + // If the user has a different desired idp + String idp = (String) request.getAttribute(org.picketlink.identity.federation.web.constants.GeneralConstants.DESIRED_IDP); + if (StringUtil.isNotNull(idp)) { + baseProcessor.setIdentityURL(idp); + } else { + baseProcessor.setIdentityURL(identityURL); + } + baseProcessor.setAuditHelper(auditHelper); + + saml2HandlerResponse = baseProcessor.process(httpContext, handlers, chainLock); + } catch (ProcessingException pe) { + logger.samlSPHandleRequestError(pe); + throw new RuntimeException(pe); + } catch (ParsingException pe) { + logger.samlSPHandleRequestError(pe); + throw new RuntimeException(pe); + } catch (ConfigurationException pe) { + logger.samlSPHandleRequestError(pe); + throw new RuntimeException(pe); + } + + willSendRequest = saml2HandlerResponse.getSendRequest(); + + Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); + String relayState = saml2HandlerResponse.getRelayState(); + + String destination = saml2HandlerResponse.getDestination(); + String destinationQueryStringWithSignature = saml2HandlerResponse.getDestinationQueryStringWithSignature(); + + if (destination != null && samlResponseDocument != null) { + try { + if (saveRestoreRequest && !isGlobalLogout(request)) { + this.saveRequest(request, session); + } + if (enableAudit) { + PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent(AuditLevel.INFO); + auditEvent.setType(PicketLinkAuditEventType.REQUEST_TO_IDP); + auditEvent.setWhoIsAuditing(getContextPath()); + auditHelper.audit(auditEvent); + } + sendRequestToIDP(destination, + samlResponseDocument, + relayState, + request, + response, + willSendRequest, + destinationQueryStringWithSignature); + return false; + } catch (Exception e) { + logger.samlSPHandleRequestError(e); + throw logger.samlSPProcessingExceptionError(e); + } + } + + return localAuthentication(request, response); + } + + /** + *

+ * Indicates if the SP is configure with HTTP POST Binding. + *

+ * + * @return + */ + protected boolean isHttpPostBinding() { + return getBinding().equalsIgnoreCase("POST"); + } + + public Context getContext() { + return (Context) getContainer(); + } + + @Override + public boolean restoreRequest(Request request, Session session) throws IOException { + return super.restoreRequest(request, session); + } + + /** + * Subclasses need to return the context path based on the capability of their + * servlet api + * + * @return + */ + protected abstract String getContextPath(); + + protected Principal getGenericPrincipal(Request request, String username, List roles) { + return (new SPUtil()).createGenericPrincipal(request, username, roles); + } + + private boolean isAjaxRequest(Request request) { + String requestedWithHeader = request.getHeader(GeneralConstants.HTTP_HEADER_X_REQUESTED_WITH); + return requestedWithHeader != null && "XMLHttpRequest".equalsIgnoreCase(requestedWithHeader); + } +} diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/BaseFormAuthenticator.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/BaseFormAuthenticator.java new file mode 100644 index 000000000..1d38fbf7e --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/BaseFormAuthenticator.java @@ -0,0 +1,717 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.tomcat.sp; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.security.GeneralSecurityException; +import java.security.Principal; +import java.security.cert.X509Certificate; +import java.util.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import javax.xml.crypto.dsig.CanonicalizationMethod; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.AuthenticatorBase; +import org.apache.catalina.authenticator.FormAuthenticator; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.picketlink.common.ErrorCodes; +import org.picketlink.common.PicketLinkLogger; +import org.picketlink.common.PicketLinkLoggerFactory; +import org.picketlink.common.constants.GeneralConstants; +import org.picketlink.common.constants.JBossSAMLURIConstants; +import org.picketlink.common.exceptions.ConfigurationException; +import org.picketlink.common.exceptions.ParsingException; +import org.picketlink.common.exceptions.ProcessingException; +import org.picketlink.common.util.DocumentUtil; +import org.picketlink.common.util.StringUtil; +import org.picketlink.common.util.SystemPropertiesUtil; +import org.picketlink.config.federation.PicketLinkType; +import org.picketlink.config.federation.SPType; +import org.picketlink.config.federation.handler.Handlers; +import org.picketlink.identity.federation.api.saml.v2.metadata.MetaDataExtractor; +import org.picketlink.identity.federation.core.audit.PicketLinkAuditHelper; +import org.picketlink.identity.federation.core.interfaces.TrustKeyManager; +import org.picketlink.identity.federation.core.parsers.saml.SAMLParser; +import org.picketlink.identity.federation.core.saml.v2.factories.SAML2HandlerChainFactory; +import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerChainConfig; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerChain; +import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerChainConfig; +import org.picketlink.identity.federation.core.saml.v2.util.HandlerUtil; +import org.picketlink.identity.federation.core.util.CoreConfigUtil; +import org.picketlink.identity.federation.core.util.XMLSignatureUtil; +import org.picketlink.identity.federation.saml.v2.metadata.EndpointType; +import org.picketlink.identity.federation.saml.v2.metadata.EntitiesDescriptorType; +import org.picketlink.identity.federation.saml.v2.metadata.EntityDescriptorType; +import org.picketlink.identity.federation.saml.v2.metadata.IDPSSODescriptorType; +import org.picketlink.identity.federation.saml.v2.metadata.KeyDescriptorType; +import org.picketlink.identity.federation.web.config.AbstractSAMLConfigurationProvider; +import org.picketlink.identity.federation.web.util.ConfigurationUtil; +import org.picketlink.identity.federation.web.util.SAMLConfigurationProvider; +import org.w3c.dom.Document; + +import static org.picketlink.common.constants.GeneralConstants.CONFIG_FILE_LOCATION; +import static org.picketlink.common.util.StringUtil.isNullOrEmpty; + +/** + * Base Class for Service Provider Form Authenticators + * + * @author Anil.Saldhana@redhat.com + * @since Jun 9, 2009 + */ +public abstract class BaseFormAuthenticator extends FormAuthenticator { + protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); + + protected boolean enableAudit = false; + + protected PicketLinkAuditHelper auditHelper = null; + + protected TrustKeyManager keyManager; + + protected SPType spConfiguration = null; + + protected PicketLinkType picketLinkConfiguration = null; + + protected String serviceURL = null; + + protected String identityURL = null; + + protected String issuerID = null; + + protected String configFile; + + /** + * If the service provider is configured with an IDP metadata file, then this + * certificate can be picked up from the metadata + */ + protected transient X509Certificate idpCertificate = null; + + protected transient SAML2HandlerChain chain = null; + + protected transient String samlHandlerChainClass = null; + + protected Map chainConfigOptions = new HashMap<>(); + + // Whether the authenticator has to to save and restore request + protected boolean saveRestoreRequest = true; + + /** + * A Lock for Handler operations in the chain + */ + protected Lock chainLock = new ReentrantLock(); + + protected String canonicalizationMethod = CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS; + + /** + * The user can inject a fully qualified name of a + * {@link SAMLConfigurationProvider} + */ + protected SAMLConfigurationProvider configProvider = null; + + /** + * Servlet3 related changes forced Tomcat to change the authenticate method + * signature in the FormAuthenticator. For now, we use reflection for forward + * compatibility. This has to be changed in future. + */ + private Method theSuperRegisterMethod = null; + + /** + * If it is determined that we are running in a Tomcat6/JBAS5 environment, + * there is no need to seek the super.register method that conforms to the + * servlet3 spec changes + */ + private boolean seekSuperRegisterMethod = true; + + protected int timerInterval = -1; + + protected Timer timer = null; + + public BaseFormAuthenticator() { + super(); + } + + protected String idpAddress = null; + + /** + * If the request.getRemoteAddr is not exactly the IDP address that you have + * keyed in your deployment descriptor for keystore alias, you can set it here + * explicitly + */ + public void setIdpAddress(String idpAddress) { + this.idpAddress = idpAddress; + } + + /** + * Get the name of the configuration file + * + * @return + */ + public String getConfigFile() { + return configFile; + } + + /** + * Set the name of the configuration file + * + * @param configFile + */ + public void setConfigFile(String configFile) { + this.configFile = configFile; + } + + /** + * Set the SAML Handler Chain Class fqn + * + * @param samlHandlerChainClass + */ + public void setSamlHandlerChainClass(String samlHandlerChainClass) { + this.samlHandlerChainClass = samlHandlerChainClass; + } + + /** + * Set the service URL + * + * @param serviceURL + */ + public void setServiceURL(String serviceURL) { + this.serviceURL = serviceURL; + } + + /** + * Set whether the authenticator saves/restores the request during form + * authentication + * + * @param saveRestoreRequest + */ + public void setSaveRestoreRequest(boolean saveRestoreRequest) { + this.saveRestoreRequest = saveRestoreRequest; + } + + /** + * Set the {@link SAMLConfigurationProvider} fqn + * + * @param cp fqn of a {@link SAMLConfigurationProvider} + */ + public void setConfigProvider(String cp) { + if (cp == null) + throw new IllegalStateException(ErrorCodes.NULL_ARGUMENT + cp); + Class clazz = SecurityActions.loadClass(getClass(), cp); + if (clazz == null) + throw new RuntimeException(ErrorCodes.CLASS_NOT_LOADED + cp); + try { + configProvider = (SAMLConfigurationProvider) clazz.newInstance(); + } catch (Exception e) { + throw new RuntimeException(ErrorCodes.CANNOT_CREATE_INSTANCE + cp + ":" + e.getMessage()); + } + } + + /** + * Set an instance of the {@link SAMLConfigurationProvider} + * + * @param configProvider + */ + public void setConfigProvider(SAMLConfigurationProvider configProvider) { + this.configProvider = configProvider; + } + + /** + * Get the {@link SPType} + * + * @return + */ + public SPType getConfiguration() { + return spConfiguration; + } + + /** + * Set a separate issuer id + * + * @param issuerID + */ + public void setIssuerID(String issuerID) { + this.issuerID = issuerID; + } + + /** + * Set the logout page + * + * @param logOutPage + */ + public void setLogOutPage(String logOutPage) { + logger.warn("Option logOutPage is now configured with the PicketLinkSP element."); + + } + + /** + * Set the Timer Value to reload the configuration + * + * @param value an integer value that represents timer value (in miliseconds) + */ + public void setTimerInterval(String value) { + if (StringUtil.isNotNull(value)) { + timerInterval = Integer.parseInt(value); + } + } + + /** + * Perform validation os the request object + * + * @param request + * @return + * @throws IOException + * @throws GeneralSecurityException + */ + protected boolean validate(Request request) { + return request.getParameter("SAMLResponse") != null; + } + + /** + * Get the Identity URL + * + * @return + */ + public String getIdentityURL() { + return identityURL; + } + + /** + * Get the {@link X509Certificate} of the IDP if provided via the IDP metadata + * file + * + * @return {@link X509Certificate} or null + */ + public X509Certificate getIdpCertificate() { + return idpCertificate; + } + + /** + * This method is a hack!!! Tomcat on account of Servlet3 changed their + * authenticator method signatures We utilize Java Reflection to identify the + * super register method on the first call and save it. Subsquent invocations + * utilize the saved {@link Method} + * + * @see org.apache.catalina.authenticator.AuthenticatorBase#register(org.apache.catalina.connector.Request, + * org.apache.catalina.connector.Response, java.security.Principal, + * java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public void register(Request request, + HttpServletResponse response, + Principal principal, + String arg3, + String arg4, + String arg5) { + // Try the JBossAS6 version + if (theSuperRegisterMethod == null && seekSuperRegisterMethod) { + Class[] args = new Class[] { Request.class, HttpServletResponse.class, Principal.class, String.class, + String.class, String.class }; + Class superClass = getAuthenticatorBaseClass(); + theSuperRegisterMethod = SecurityActions.getMethod(superClass, "register", args); + } + try { + if (theSuperRegisterMethod != null) { + Object[] callArgs = new Object[] { request, response, principal, arg3, arg4, arg5 }; + theSuperRegisterMethod.invoke(this, callArgs); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + // Try the older version + if (theSuperRegisterMethod == null) { + seekSuperRegisterMethod = false; // Don't try to seek super register + // method on next invocation + super.register(request, response, principal, arg3, arg4, arg5); + return; + } + } + + /** + * Fall back on local authentication at the service provider side + * + * @param request + * @param response + * @param loginConfig + * @return + * @throws IOException + */ + protected boolean localAuthentication(Request request, HttpServletResponse response) throws IOException { + if (request.getUserPrincipal() == null) { + logger.samlSPFallingBackToLocalFormAuthentication();// fallback + return super.authenticate(request, response); + } else + return true; + } + + /** + * Return the SAML Binding that this authenticator supports + * + * @see {@link JBossSAMLURIConstants#SAML_HTTP_POST_BINDING} + * @see {@link JBossSAMLURIConstants#SAML_HTTP_REDIRECT_BINDING} + * @return + */ + protected abstract String getBinding(); + + /** + * Attempt to process a metadata file available locally + */ + protected void processIDPMetadataFile(String idpMetadataFile) { + ServletContext servletContext = context.getServletContext(); + InputStream is = servletContext.getResourceAsStream(idpMetadataFile); + if (is == null) + return; + + Object metadata = null; + try { + Document samlDocument = DocumentUtil.getDocument(is); + SAMLParser parser = new SAMLParser(); + metadata = parser.parse(DocumentUtil.getNodeAsStream(samlDocument)); + } catch (Exception e) { + throw new RuntimeException(e); + } + IDPSSODescriptorType idpSSO = null; + if (metadata instanceof EntitiesDescriptorType) { + EntitiesDescriptorType entities = (EntitiesDescriptorType) metadata; + idpSSO = handleMetadata(entities); + } else { + idpSSO = handleMetadata((EntityDescriptorType) metadata); + } + if (idpSSO == null) { + logger.samlSPUnableToGetIDPDescriptorFromMetadata(); + return; + } + List endpoints = idpSSO.getSingleSignOnService(); + for (EndpointType endpoint : endpoints) { + String endpointBinding = endpoint.getBinding().toString(); + if (endpointBinding.contains("HTTP-POST")) + endpointBinding = "POST"; + else if (endpointBinding.contains("HTTP-Redirect")) + endpointBinding = "REDIRECT"; + if (getBinding().equals(endpointBinding)) { + identityURL = endpoint.getLocation().toString(); + break; + } + } + List keyDescriptors = idpSSO.getKeyDescriptor(); + if (keyDescriptors.size() > 0) { + this.idpCertificate = MetaDataExtractor.getCertificate(keyDescriptors.get(0)); + } + } + + /** + * Process the configuration from the configuration file + */ + @SuppressWarnings("deprecation") + protected void processConfiguration() { + ServletContext servletContext = context.getServletContext(); + InputStream is = null; + + if (isNullOrEmpty(this.configFile)) { + this.configFile = CONFIG_FILE_LOCATION; + is = servletContext.getResourceAsStream(this.configFile); + } else { + try { + is = new FileInputStream(this.configFile); + } catch (FileNotFoundException e) { + throw logger.samlIDPConfigurationError(e); + } + } + + try { + // Work on the IDP Configuration + if (configProvider != null) { + try { + if (is == null) { + // Try the older version + is = servletContext.getResourceAsStream(GeneralConstants.DEPRECATED_CONFIG_FILE_LOCATION); + + // Additionally parse the deprecated config file + if (is != null && configProvider instanceof AbstractSAMLConfigurationProvider) { + ((AbstractSAMLConfigurationProvider) configProvider).setConfigFile(is); + } + } else { + // Additionally parse the consolidated config file + if (is != null && configProvider instanceof AbstractSAMLConfigurationProvider) { + ((AbstractSAMLConfigurationProvider) configProvider).setConsolidatedConfigFile(is); + } + } + + picketLinkConfiguration = configProvider.getPicketLinkConfiguration(); + spConfiguration = configProvider.getSPConfiguration(); + } catch (ProcessingException e) { + throw logger.samlSPConfigurationError(e); + } catch (ParsingException e) { + throw logger.samlSPConfigurationError(e); + } + } else { + if (is != null) { + try { + picketLinkConfiguration = ConfigurationUtil.getConfiguration(is); + spConfiguration = (SPType) picketLinkConfiguration.getIdpOrSP(); + } catch (ParsingException e) { + logger.trace(e); + throw logger.samlSPConfigurationError(e); + } + } else { + is = servletContext.getResourceAsStream(GeneralConstants.DEPRECATED_CONFIG_FILE_LOCATION); + if (is == null) + throw logger.configurationFileMissing(configFile); + spConfiguration = ConfigurationUtil.getSPConfiguration(is); + } + } + + if (this.picketLinkConfiguration != null) { + enableAudit = picketLinkConfiguration.isEnableAudit(); + + // See if we have the system property enabled + if (!enableAudit) { + String sysProp = SecurityActions.getSystemProperty(GeneralConstants.AUDIT_ENABLE, "NULL"); + if (!"NULL".equals(sysProp)) { + enableAudit = Boolean.parseBoolean(sysProp); + } + } + + if (enableAudit) { + if (auditHelper == null) { + String securityDomainName = PicketLinkAuditHelper.getSecurityDomainName(servletContext); + + auditHelper = new PicketLinkAuditHelper(securityDomainName); + } + } + } + + if (StringUtil.isNotNull(spConfiguration.getIdpMetadataFile())) { + processIDPMetadataFile(spConfiguration.getIdpMetadataFile()); + } else { + this.identityURL = spConfiguration.getIdentityURL(); + } + this.serviceURL = spConfiguration.getServiceURL(); + this.canonicalizationMethod = spConfiguration.getCanonicalizationMethod(); + + logger.samlSPSettingCanonicalizationMethod(canonicalizationMethod); + XMLSignatureUtil.setCanonicalizationMethodType(canonicalizationMethod); + + logger.trace("Identity Provider URL=" + this.identityURL); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected IDPSSODescriptorType handleMetadata(EntitiesDescriptorType entities) { + IDPSSODescriptorType idpSSO = null; + + List entityDescs = entities.getEntityDescriptor(); + for (Object entityDescriptor : entityDescs) { + if (entityDescriptor instanceof EntitiesDescriptorType) { + idpSSO = getIDPSSODescriptor(entities); + } else + idpSSO = handleMetadata((EntityDescriptorType) entityDescriptor); + if (idpSSO != null) + break; + } + return idpSSO; + } + + protected IDPSSODescriptorType handleMetadata(EntityDescriptorType entityDescriptor) { + return CoreConfigUtil.getIDPDescriptor(entityDescriptor); + } + + protected IDPSSODescriptorType getIDPSSODescriptor(EntitiesDescriptorType entities) { + List entityDescs = entities.getEntityDescriptor(); + for (Object entityDescriptor : entityDescs) { + + if (entityDescriptor instanceof EntitiesDescriptorType) { + return getIDPSSODescriptor((EntitiesDescriptorType) entityDescriptor); + } + return CoreConfigUtil.getIDPDescriptor((EntityDescriptorType) entityDescriptor); + } + return null; + } + + protected void initializeHandlerChain() throws ConfigurationException, ProcessingException { + populateChainConfig(); + SAML2HandlerChainConfig handlerChainConfig = new DefaultSAML2HandlerChainConfig(chainConfigOptions); + + Set samlHandlers = chain.handlers(); + + for (SAML2Handler handler : samlHandlers) { + handler.initChainConfig(handlerChainConfig); + } + } + + protected void populateChainConfig() throws ConfigurationException, ProcessingException { + chainConfigOptions.put(GeneralConstants.CONFIGURATION, spConfiguration); + chainConfigOptions.put(GeneralConstants.ROLE_VALIDATOR_IGNORE, "false"); // No + // validator + // as + // tomcat + // realm + // does + // validn + + if (doSupportSignature()) { + chainConfigOptions.put(GeneralConstants.KEYPAIR, keyManager.getSigningKeyPair()); + // If there is a need for X509Data in signedinfo + String certificateAlias = (String) keyManager.getAdditionalOption(GeneralConstants.X509CERTIFICATE); + if (certificateAlias != null) { + chainConfigOptions.put(GeneralConstants.X509CERTIFICATE, keyManager.getCertificate(certificateAlias)); + } + } + } + + protected void sendToLogoutPage(Request request, HttpServletResponse response, Session session) throws IOException, + ServletException { + // we are invalidated. + RequestDispatcher dispatch = context.getServletContext().getRequestDispatcher(this.getConfiguration().getLogOutPage()); + if (dispatch == null) + logger.samlSPCouldNotDispatchToLogoutPage(this.getConfiguration().getLogOutPage()); + else { + logger.trace("Forwarding request to logOutPage: " + this.getConfiguration().getLogOutPage()); + session.expire(); + try { + dispatch.forward(request, response); + } catch (Exception e) { + // JBAS5.1 and 6 quirkiness + dispatch.forward(request.getRequest(), response); + } + } + } + + // Mock test purpose + public void testStart() throws LifecycleException { + this.saveRestoreRequest = false; + if (context == null) + throw new RuntimeException("Catalina Context not set up"); + startPicketLink(); + } + + protected void startPicketLink() throws LifecycleException { + SystemPropertiesUtil.ensure(); + Handlers handlers = null; + + // Introduce a timer to reload configuration if desired + if (timerInterval > 0) { + if (timer == null) { + timer = new Timer(); + } + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + // Clear the configuration + picketLinkConfiguration = null; + spConfiguration = null; + + processConfiguration(); + try { + initKeyProvider(context); + } catch (LifecycleException e) { + logger.trace(e.getMessage()); + } + } + }, timerInterval, timerInterval); + } + + // Get the chain from config + if (StringUtil.isNullOrEmpty(samlHandlerChainClass)) { + chain = SAML2HandlerChainFactory.createChain(); + } else { + try { + chain = SAML2HandlerChainFactory.createChain(this.samlHandlerChainClass); + } catch (ProcessingException e1) { + throw new LifecycleException(e1); + } + } + + ServletContext servletContext = context.getServletContext(); + + this.processConfiguration(); + + try { + if (picketLinkConfiguration != null) { + handlers = picketLinkConfiguration.getHandlers(); + } else { + // Get the handlers + String handlerConfigFileName = GeneralConstants.HANDLER_CONFIG_FILE_LOCATION; + handlers = ConfigurationUtil.getHandlers(servletContext.getResourceAsStream(handlerConfigFileName)); + } + + chain.addAll(HandlerUtil.getHandlers(handlers)); + + this.initKeyProvider(context); + this.populateChainConfig(); + this.initializeHandlerChain(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + if (this.picketLinkConfiguration == null) { + this.picketLinkConfiguration = new PicketLinkType(); + + this.picketLinkConfiguration.setIdpOrSP(getConfiguration()); + this.picketLinkConfiguration.setHandlers(handlers); + } + } + + /** + *

+ * Indicates if digital signatures/validation of SAML assertions are enabled. + * Subclasses that supports signature should override this method. + *

+ * + * @return + */ + protected boolean doSupportSignature() { + if (spConfiguration != null) { + return spConfiguration.isSupportsSignature(); + } + return false; + } + + private Class getAuthenticatorBaseClass() { + Class myClass = getClass(); + do { + myClass = myClass.getSuperclass(); + } while (myClass != AuthenticatorBase.class); + return myClass; + } + + protected abstract void initKeyProvider(Context context) throws LifecycleException; + + public void setAuditHelper(PicketLinkAuditHelper auditHelper) { + this.auditHelper = auditHelper; + } +} diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/SPUtil.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/SPUtil.java new file mode 100644 index 000000000..ea180f0a7 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/SPUtil.java @@ -0,0 +1,77 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.tomcat.sp; + +import java.security.Principal; +import java.util.List; + +import org.apache.catalina.Context; +import org.apache.catalina.connector.Request; +import org.apache.catalina.realm.GenericPrincipal; +import org.picketlink.common.PicketLinkLogger; +import org.picketlink.common.PicketLinkLoggerFactory; +import org.picketlink.common.exceptions.ConfigurationException; +import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request; +import org.picketlink.identity.federation.core.saml.v2.common.IDGenerator; +import org.picketlink.identity.federation.saml.v2.protocol.AuthnRequestType; + +/** + * Common code useful for a SP + * + * @author Anil.Saldhana@redhat.com + * @since Jan 9, 2009 + */ +public class SPUtil { + + private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); + + /** + * Create a SAML2 auth request + * + * @param serviceURL URL of the service + * @param identityURL URL of the identity provider + * @return + * @throws ConfigurationException + */ + public AuthnRequestType createSAMLRequest(String serviceURL, String identityURL) throws ConfigurationException { + if (serviceURL == null) + throw logger.nullArgumentError("serviceURL"); + if (identityURL == null) + throw logger.nullArgumentError("identityURL"); + + SAML2Request saml2Request = new SAML2Request(); + String id = IDGenerator.create("ID_"); + return saml2Request.createAuthnRequestType(id, serviceURL, identityURL, serviceURL); + } + + /** + * Create an instance of the {@link GenericPrincipal} + * @param request + * @param username + * @param roles + * @return + */ + public Principal createGenericPrincipal(Request request, String username, List roles) { + Context ctx = request.getContext(); + return new GenericPrincipal(username, roles); + } +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/SecurityActions.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/SecurityActions.java new file mode 100644 index 000000000..263907781 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/SecurityActions.java @@ -0,0 +1,156 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.tomcat.sp; + +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Privileged Blocks + * + * @author Anil.Saldhana@redhat.com + * @since Dec 9, 2008 + */ +class SecurityActions { + + /** + *

+ * Loads a {@link Class} using the fullQualifiedName supplied. This method tries first to load from the + * specified {@link Class}, if not found it will try to load from using TCL. + *

+ * + * @param theClass + * @param fullQualifiedName + * @return + */ + static Class loadClass(final Class theClass, final String fullQualifiedName) { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction>() { + public Class run() { + ClassLoader classLoader = theClass.getClassLoader(); + + Class clazz = loadClass(classLoader, fullQualifiedName); + if (clazz == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + clazz = loadClass(classLoader, fullQualifiedName); + } + return clazz; + } + }); + } else { + ClassLoader classLoader = theClass.getClassLoader(); + + Class clazz = loadClass(classLoader, fullQualifiedName); + if (clazz == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + clazz = loadClass(classLoader, fullQualifiedName); + } + return clazz; + } + } + + /** + *

+ * Loads a class from the specified {@link ClassLoader} using the fullQualifiedName supplied. + *

+ * + * @param classLoader + * @param fullQualifiedName + * @return + */ + static Class loadClass(final ClassLoader classLoader, final String fullQualifiedName) { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction>() { + public Class run() { + try { + return classLoader.loadClass(fullQualifiedName); + } catch (ClassNotFoundException e) { + } + return null; + } + }); + } else { + try { + return classLoader.loadClass(fullQualifiedName); + } catch (ClassNotFoundException e) { + } + return null; + } + } + + /** + *

Returns a system property value using the specified key. If not found the defaultValue will be returned.

+ * + * @param key + * @param defaultValue + * @return + */ + static String getSystemProperty(final String key, final String defaultValue) { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction() { + public String run() { + return System.getProperty(key, defaultValue); + } + }); + } else { + return System.getProperty(key, defaultValue); + } + } + + /** + * Use reflection to get the {@link Method} on a {@link Class} with the given parameter types + * + * @param clazz + * @param methodName + * @param parameterTypes + * @return + */ + static Method getMethod(final Class clazz, final String methodName, final Class[] parameterTypes) { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Method run() { + try { + return clazz.getDeclaredMethod(methodName, parameterTypes); + } catch (Exception e) { + return null; + } + } + }); + } else { + try { + return clazz.getDeclaredMethod(methodName, parameterTypes); + } catch (Exception e) { + return null; + } + } + } + +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/holder/ServiceProviderSAMLContext.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/holder/ServiceProviderSAMLContext.java new file mode 100644 index 000000000..63afb104b --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/holder/ServiceProviderSAMLContext.java @@ -0,0 +1,65 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.tomcat.sp.holder; + +import org.picketlink.identity.federation.core.constants.PicketLinkFederationConstants; + +import java.util.List; + +/** + * A context of username/roles to be used by login modules + * + * @author Anil.Saldhana@redhat.com + * @since Feb 13, 2009 + */ +public class ServiceProviderSAMLContext { + public static final String EMPTY_PASSWORD = "EMPTY_STR"; + + private static ThreadLocal username = new ThreadLocal(); + private static ThreadLocal> userRoles = new ThreadLocal>(); + + public static void push(String user, List roles) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(PicketLinkFederationConstants.RUNTIME_PERMISSION_CORE); + } + username.set(user); + userRoles.set(roles); + } + + public static void clear() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(PicketLinkFederationConstants.RUNTIME_PERMISSION_CORE); + } + username.remove(); + userRoles.remove(); + } + + public static String getUserName() { + return username.get(); + } + + public static List getRoles() { + return userRoles.get(); + } +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/plugins/PropertiesAccountMapProvider.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/plugins/PropertiesAccountMapProvider.java new file mode 100644 index 000000000..e8dcc533d --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/tomcat/sp/plugins/PropertiesAccountMapProvider.java @@ -0,0 +1,86 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * Licensed 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.picketlink.identity.federation.bindings.tomcat.sp.plugins; + +import org.picketlink.identity.federation.bindings.tomcat.sp.AbstractAccountChooserValve; + +import jakarta.servlet.ServletContext; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +/** + * Implementation of + * {@link org.picketlink.identity.federation.bindings.tomcat.sp.AbstractAccountChooserValve.AccountIDPMapProvider} using a + * properties file + * + * @author Anil Saldhana + * @since January 23, 2014 + */ +public class PropertiesAccountMapProvider implements AbstractAccountChooserValve.AccountIDPMapProvider { + private ClassLoader classLoader = null; + + private ServletContext servletContext = null; + + public static final String PROP_FILE_NAME = "idpmap.properties"; + + public static final String WEB_INF_PROP_FILE_NAME = "/WEB-INF/idpmap.properties"; + + @Override + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public void setServletContext(ServletContext servletContext){ + this.servletContext = servletContext; + } + + @Override + public Map getIDPMap() throws IOException { + Map idpmap = new HashMap(); + + InputStream inputStream = null; + + Properties properties = new Properties(); + if (classLoader != null) { + inputStream = classLoader.getResourceAsStream(PROP_FILE_NAME); + } + if (inputStream == null && servletContext != null) { + inputStream = servletContext.getResourceAsStream(PROP_FILE_NAME); + } + if (inputStream == null && servletContext != null) { + inputStream = servletContext.getResourceAsStream(WEB_INF_PROP_FILE_NAME); + } + if(inputStream == null){ + inputStream = getClass().getResourceAsStream(PROP_FILE_NAME); + } + if (inputStream != null) { + properties.load(inputStream); + if (properties != null) { + Set keyset = properties.keySet(); + for (Object key : keyset) { + idpmap.put((String) key, (String) properties.get(key)); + } + } + } + return idpmap; + } +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/util/ModuleUtils.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/util/ModuleUtils.java new file mode 100644 index 000000000..911fe4272 --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/util/ModuleUtils.java @@ -0,0 +1,35 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * Licensed 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.picketlink.identity.federation.bindings.util; + +import org.picketlink.identity.federation.core.wstrust.STSClientConfig; + +/** + * Placeholder for utility class to work with modules. + * + * @author Peter Skopek + * + */ +public class ModuleUtils { + + public static String getCurrentModuleId() { + return STSClientConfig.NO_MODULE; + } + +} diff --git a/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/util/SecurityActions.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/util/SecurityActions.java new file mode 100644 index 000000000..94c322eed --- /dev/null +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/util/SecurityActions.java @@ -0,0 +1,54 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.picketlink.identity.federation.bindings.util; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Privileged Blocks + * + * @author Anil.Saldhana@redhat.com + * @since Dec 9, 2008 + */ +class SecurityActions { + /** + *

Returns a system property value using the specified key. If not found the defaultValue will be returned.

+ * + * @param key + * @param defaultValue + * @return + */ + static String getSystemProperty(final String key, final String defaultValue) { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction() { + public String run() { + return System.getProperty(key, defaultValue); + } + }); + } else { + return System.getProperty(key, defaultValue); + } + } +} \ No newline at end of file diff --git a/common-plugin/src/main/java/org/gatein/sso/plugin/HttpResponseContext.java b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/util/ValveUtil.java similarity index 50% rename from common-plugin/src/main/java/org/gatein/sso/plugin/HttpResponseContext.java rename to sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/util/ValveUtil.java index 48887be2c..cf0546409 100644 --- a/common-plugin/src/main/java/org/gatein/sso/plugin/HttpResponseContext.java +++ b/sso-saml-plugin/src/main/java/org/picketlink/identity/federation/bindings/util/ValveUtil.java @@ -1,9 +1,8 @@ /* - * JBoss, a division of Red Hat - * Copyright 2012, Red Hat Middleware, LLC, and individual - * contributors as indicated by the @authors tag. See the - * copyright.txt in the distribution for a full listing of - * individual contributors. + * JBoss, Home of Professional Open Source. + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as @@ -20,27 +19,28 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ +package org.picketlink.identity.federation.bindings.util; -package org.gatein.sso.plugin; +import java.io.IOException; +import java.net.URL; /** - * @author Marek Posolda + * Util for tomcat valves + * + * @author Anil.Saldhana@redhat.com + * @since Jan 22, 2009 */ -class HttpResponseContext { - - private final int responseCode; - private final String response; - - public HttpResponseContext(int responseCode, String response) { - this.responseCode = responseCode; - this.response = response; - } - - public int getResponseCode() { - return responseCode; - } +public class ValveUtil { - public String getResponse() { - return response; + /** + * Given a SP or IDP issuer from the assertion, return the host + * + * @param domainURL + * @return + * @throws IOException + */ + public static String getDomain(String domainURL) throws IOException { + URL url = new URL(domainURL); + return url.getHost(); } -} +} \ No newline at end of file diff --git a/sso-saml-plugin/src/main/patches/java.security.acl.Group.patch b/sso-saml-plugin/src/main/patches/java.security.acl.Group.patch new file mode 100644 index 000000000..1bf4857ef --- /dev/null +++ b/sso-saml-plugin/src/main/patches/java.security.acl.Group.patch @@ -0,0 +1,793 @@ +diff -uNr picketlink-orig/org/jboss/security/auth/spi/AbstractServerLoginModule.java picketlink/org/jboss/security/auth/spi/AbstractServerLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/AbstractServerLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/AbstractServerLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -31,7 +31,7 @@ + import javax.security.auth.spi.LoginModule; + import java.lang.reflect.Constructor; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.*; + + /** +@@ -209,7 +209,7 @@ + to the subject getPrincipals() Set. + + @see javax.security.auth.Subject; +- @see java.security.acl.Group; ++ @see org.jboss.security.Group; + @return true always. + */ + public boolean commit() throws LoginException +diff -uNr picketlink-orig/org/jboss/security/auth/spi/AnonLoginModule.java picketlink/org/jboss/security/auth/spi/AnonLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/AnonLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/AnonLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -21,7 +21,7 @@ + */ + package org.jboss.security.auth.spi; + +-import java.security.acl.Group; ++import org.jboss.security.Group; + + import javax.security.auth.login.LoginException; + +diff -uNr picketlink-orig/org/jboss/security/auth/spi/BaseCertLoginModule.java picketlink/org/jboss/security/auth/spi/BaseCertLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/BaseCertLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/BaseCertLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -25,7 +25,7 @@ + import java.security.KeyStore; + import java.security.KeyStoreException; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.security.cert.X509Certificate; + import java.util.ArrayList; + import java.util.Enumeration; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/CertRolesLoginModule.java picketlink/org/jboss/security/auth/spi/CertRolesLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/CertRolesLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/CertRolesLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.io.IOException; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + import java.util.Properties; + +diff -uNr picketlink-orig/org/jboss/security/auth/spi/DatabaseCertLoginModule.java picketlink/org/jboss/security/auth/spi/DatabaseCertLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/DatabaseCertLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/DatabaseCertLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -21,7 +21,7 @@ + */ + package org.jboss.security.auth.spi; + +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + + import javax.security.auth.Subject; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/DatabaseServerLoginModule.java picketlink/org/jboss/security/auth/spi/DatabaseServerLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/DatabaseServerLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/DatabaseServerLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -21,7 +21,7 @@ + */ + package org.jboss.security.auth.spi; + +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.sql.Connection; + import java.sql.PreparedStatement; + import java.sql.ResultSet; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/DbUtil.java picketlink/org/jboss/security/auth/spi/DbUtil.java +--- picketlink-orig/org/jboss/security/auth/spi/DbUtil.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/DbUtil.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.sql.Connection; + import java.sql.PreparedStatement; + import java.sql.ResultSet; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/IdentityLoginModule.java picketlink/org/jboss/security/auth/spi/IdentityLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/IdentityLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/IdentityLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + import java.util.StringTokenizer; + +diff -uNr picketlink-orig/org/jboss/security/auth/spi/LdapExtLoginModule.java picketlink/org/jboss/security/auth/spi/LdapExtLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/LdapExtLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/LdapExtLoginModule.java 2023-12-17 08:04:43.368951953 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Iterator; + import java.util.Map; + import java.util.Properties; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/LdapLoginModule.java picketlink/org/jboss/security/auth/spi/LdapLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/LdapLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/LdapLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Arrays; + import java.util.Iterator; + import java.util.Properties; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/LdapUsersLoginModule.java picketlink/org/jboss/security/auth/spi/LdapUsersLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/LdapUsersLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/LdapUsersLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -21,7 +21,7 @@ + */ + package org.jboss.security.auth.spi; + +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Iterator; + import java.util.Map; + import java.util.Map.Entry; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/otp/JBossTimeBasedOTPLoginModule.java picketlink/org/jboss/security/auth/spi/otp/JBossTimeBasedOTPLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/otp/JBossTimeBasedOTPLoginModule.java 2023-12-17 08:04:11.748905792 +0100 ++++ picketlink/org/jboss/security/auth/spi/otp/JBossTimeBasedOTPLoginModule.java 2023-12-17 08:04:43.368951953 +0100 +@@ -24,7 +24,7 @@ + import java.io.IOException; + import java.io.InputStream; + import java.security.GeneralSecurityException; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Arrays; + import java.util.HashMap; + import java.util.HashSet; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/PropertiesUsersLoginModule.java picketlink/org/jboss/security/auth/spi/PropertiesUsersLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/PropertiesUsersLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/PropertiesUsersLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.io.IOException; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + import java.util.Properties; + +diff -uNr picketlink-orig/org/jboss/security/auth/spi/RemoteHostTrustLoginModule.java picketlink/org/jboss/security/auth/spi/RemoteHostTrustLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/RemoteHostTrustLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/RemoteHostTrustLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -21,7 +21,7 @@ + */ + package org.jboss.security.auth.spi; + +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Arrays; + import java.util.List; + import java.util.Map; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/RoleMappingLoginModule.java picketlink/org/jboss/security/auth/spi/RoleMappingLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/RoleMappingLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/RoleMappingLoginModule.java 2023-12-17 08:04:43.368951953 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Enumeration; + import java.util.Iterator; + import java.util.Map; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/SimpleServerLoginModule.java picketlink/org/jboss/security/auth/spi/SimpleServerLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/SimpleServerLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/SimpleServerLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + + import javax.security.auth.login.LoginException; + +diff -uNr picketlink-orig/org/jboss/security/auth/spi/Users.java picketlink/org/jboss/security/auth/spi/Users.java +--- picketlink-orig/org/jboss/security/auth/spi/Users.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/Users.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.ArrayList; + import java.util.Enumeration; + import java.util.HashMap; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/UsersLoginModule.java picketlink/org/jboss/security/auth/spi/UsersLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/UsersLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/UsersLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -26,7 +26,7 @@ + import java.io.IOException; + import java.io.InputStream; + import java.net.URL; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + import java.util.Properties; + +diff -uNr picketlink-orig/org/jboss/security/auth/spi/UsersRolesLoginModule.java picketlink/org/jboss/security/auth/spi/UsersRolesLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/UsersRolesLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/UsersRolesLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.auth.spi; + + import java.io.IOException; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + import java.util.Properties; + +diff -uNr picketlink-orig/org/jboss/security/auth/spi/Util.java picketlink/org/jboss/security/auth/spi/Util.java +--- picketlink-orig/org/jboss/security/auth/spi/Util.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/Util.java 2023-12-17 08:04:43.364951947 +0100 +@@ -31,7 +31,7 @@ + import java.security.MessageDigest; + import java.security.Principal; + import java.security.PrivilegedActionException; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.ArrayList; + import java.util.Enumeration; + import java.util.Properties; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/XMLLoginModule.java picketlink/org/jboss/security/auth/spi/XMLLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/XMLLoginModule.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/auth/spi/XMLLoginModule.java 2023-12-17 08:04:43.364951947 +0100 +@@ -21,7 +21,7 @@ + */ + package org.jboss.security.auth.spi; + +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + + import javax.security.auth.Subject; +diff -uNr picketlink-orig/org/jboss/security/AuthorizationManager.java picketlink/org/jboss/security/AuthorizationManager.java +--- picketlink-orig/org/jboss/security/AuthorizationManager.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/jboss/security/AuthorizationManager.java 2023-12-17 08:04:43.356951936 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + import java.util.Set; + +diff -uNr picketlink-orig/org/jboss/security/identity/extensions/CertificateIdentityFactory.java picketlink/org/jboss/security/identity/extensions/CertificateIdentityFactory.java +--- picketlink-orig/org/jboss/security/identity/extensions/CertificateIdentityFactory.java 2023-12-17 08:04:11.740905781 +0100 ++++ picketlink/org/jboss/security/identity/extensions/CertificateIdentityFactory.java 2023-12-17 08:04:43.356951936 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.identity.extensions; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.security.cert.X509Certificate; + + import org.jboss.security.identity.IdentityFactory; +diff -uNr picketlink-orig/org/jboss/security/identity/extensions/CredentialIdentityFactory.java picketlink/org/jboss/security/identity/extensions/CredentialIdentityFactory.java +--- picketlink-orig/org/jboss/security/identity/extensions/CredentialIdentityFactory.java 2023-12-17 08:04:11.740905781 +0100 ++++ picketlink/org/jboss/security/identity/extensions/CredentialIdentityFactory.java 2023-12-17 08:04:43.356951936 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.identity.extensions; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + + import org.jboss.security.identity.IdentityFactory; + import org.jboss.security.identity.Role; +diff -uNr picketlink-orig/org/jboss/security/identity/Identity.java picketlink/org/jboss/security/identity/Identity.java +--- picketlink-orig/org/jboss/security/identity/Identity.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/jboss/security/identity/Identity.java 2023-12-17 08:04:43.356951936 +0100 +@@ -23,7 +23,7 @@ + + import java.io.Serializable; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + + //$Id$ + +diff -uNr picketlink-orig/org/jboss/security/identity/plugins/IdentityFactory.java picketlink/org/jboss/security/identity/plugins/IdentityFactory.java +--- picketlink-orig/org/jboss/security/identity/plugins/IdentityFactory.java 2023-12-17 08:04:11.740905781 +0100 ++++ picketlink/org/jboss/security/identity/plugins/IdentityFactory.java 2023-12-17 08:04:43.356951936 +0100 +@@ -23,7 +23,7 @@ + + import java.lang.reflect.Constructor; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + + import org.jboss.security.identity.Identity; + import org.jboss.security.identity.Role; +diff -uNr picketlink-orig/org/jboss/security/identity/plugins/SimpleIdentity.java picketlink/org/jboss/security/identity/plugins/SimpleIdentity.java +--- picketlink-orig/org/jboss/security/identity/plugins/SimpleIdentity.java 2023-12-17 08:04:11.740905781 +0100 ++++ picketlink/org/jboss/security/identity/plugins/SimpleIdentity.java 2023-12-17 08:04:43.356951936 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.identity.plugins; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + + import org.jboss.security.identity.Identity; + import org.jboss.security.identity.Role; +diff -uNr picketlink-orig/org/jboss/security/identity/plugins/SimpleRoleGroup.java picketlink/org/jboss/security/identity/plugins/SimpleRoleGroup.java +--- picketlink-orig/org/jboss/security/identity/plugins/SimpleRoleGroup.java 2023-12-17 08:04:11.740905781 +0100 ++++ picketlink/org/jboss/security/identity/plugins/SimpleRoleGroup.java 2023-12-17 08:04:43.356951936 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.identity.plugins; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.ArrayList; + import java.util.Collections; + import java.util.Enumeration; +diff -uNr picketlink-orig/org/jboss/security/jacc/ContextPolicy.java picketlink/org/jboss/security/jacc/ContextPolicy.java +--- picketlink-orig/org/jboss/security/jacc/ContextPolicy.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/jacc/ContextPolicy.java 2023-12-17 08:04:43.364951947 +0100 +@@ -26,7 +26,7 @@ + import java.security.Permissions; + import java.security.Principal; + import java.security.ProtectionDomain; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.ArrayList; + import java.util.Enumeration; + import java.util.HashMap; +diff -uNr picketlink-orig/org/jboss/security/mapping/providers/DeploymentRolesMappingProvider.java picketlink/org/jboss/security/mapping/providers/DeploymentRolesMappingProvider.java +--- picketlink-orig/org/jboss/security/mapping/providers/DeploymentRolesMappingProvider.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/mapping/providers/DeploymentRolesMappingProvider.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.mapping.providers; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + import java.util.Set; + +diff -uNr picketlink-orig/org/jboss/security/mapping/providers/MappingProviderUtil.java picketlink/org/jboss/security/mapping/providers/MappingProviderUtil.java +--- picketlink-orig/org/jboss/security/mapping/providers/MappingProviderUtil.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/mapping/providers/MappingProviderUtil.java 2023-12-17 08:04:43.364951947 +0100 +@@ -23,7 +23,7 @@ + + import java.lang.reflect.Constructor; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Enumeration; + import java.util.HashSet; + import java.util.StringTokenizer; +diff -uNr picketlink-orig/org/jboss/security/mapping/providers/principal/AbstractPrincipalMappingProvider.java picketlink/org/jboss/security/mapping/providers/principal/AbstractPrincipalMappingProvider.java +--- picketlink-orig/org/jboss/security/mapping/providers/principal/AbstractPrincipalMappingProvider.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/mapping/providers/principal/AbstractPrincipalMappingProvider.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,13 +22,13 @@ + package org.jboss.security.mapping.providers.principal; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + + import org.jboss.security.mapping.MappingProvider; + + /** + * Abstract class for Principal mapping providers +- * Group Principal (java.security.acl.Group) is not supported. ++ * Group Principal (org.jboss.security.Group) is not supported. + * @author Anil.Saldhana@redhat.com + */ + public abstract class AbstractPrincipalMappingProvider implements MappingProvider +diff -uNr picketlink-orig/org/jboss/security/mapping/providers/role/AbstractRolesMappingProvider.java picketlink/org/jboss/security/mapping/providers/role/AbstractRolesMappingProvider.java +--- picketlink-orig/org/jboss/security/mapping/providers/role/AbstractRolesMappingProvider.java 2023-12-17 08:04:11.744905786 +0100 ++++ picketlink/org/jboss/security/mapping/providers/role/AbstractRolesMappingProvider.java 2023-12-17 08:04:43.364951947 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security.mapping.providers.role; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Enumeration; + import java.util.Map; + import java.util.Set; +diff -uNr picketlink-orig/org/jboss/security/NestableGroup.java picketlink/org/jboss/security/NestableGroup.java +--- picketlink-orig/org/jboss/security/NestableGroup.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/jboss/security/NestableGroup.java 2023-12-17 08:04:43.356951936 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Enumeration; + import java.util.LinkedList; + +diff -uNr picketlink-orig/org/jboss/security/NestablePrincipal.java picketlink/org/jboss/security/NestablePrincipal.java +--- picketlink-orig/org/jboss/security/NestablePrincipal.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/jboss/security/NestablePrincipal.java 2023-12-17 08:04:43.356951936 +0100 +@@ -22,7 +22,7 @@ + package org.jboss.security; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Enumeration; + import java.util.LinkedList; + +diff -uNr picketlink-orig/org/jboss/security/plugins/auth/JaasSecurityManagerBase.java picketlink/org/jboss/security/plugins/auth/JaasSecurityManagerBase.java +--- picketlink-orig/org/jboss/security/plugins/auth/JaasSecurityManagerBase.java 2023-12-17 08:04:11.748905792 +0100 ++++ picketlink/org/jboss/security/plugins/auth/JaasSecurityManagerBase.java 2023-12-17 08:04:43.368951953 +0100 +@@ -228,7 +228,7 @@ + the active user and assigned user roles. + @param rolePrincipals - a Set of Principals for the roles to check. + +- @see java.security.acl.Group; ++ @see org.jboss.security.Group; + @see Subject#getPrincipals() + */ + public boolean doesUserHaveRole(Principal principal, Set rolePrincipals) +diff -uNr picketlink-orig/org/jboss/security/plugins/JBossAuthorizationManager.java picketlink/org/jboss/security/plugins/JBossAuthorizationManager.java +--- picketlink-orig/org/jboss/security/plugins/JBossAuthorizationManager.java 2023-12-17 08:04:11.748905792 +0100 ++++ picketlink/org/jboss/security/plugins/JBossAuthorizationManager.java 2023-12-17 08:04:43.368951953 +0100 +@@ -24,7 +24,7 @@ + import static org.jboss.security.SecurityConstants.ROLES_IDENTIFIER; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Enumeration; + import java.util.HashMap; + import java.util.HashSet; +@@ -139,7 +139,7 @@ + the active user and assigned user roles. + @param rolePrincipals - a Set of Principals for the roles to check. + +- @see java.security.acl.Group; ++ @see org.jboss.security.Group; + @see Subject#getPrincipals() + */ + public boolean doesUserHaveRole(Principal principal, Set rolePrincipals) +diff -uNr picketlink-orig/org/jboss/security/plugins/JBossSecurityContext.java picketlink/org/jboss/security/plugins/JBossSecurityContext.java +--- picketlink-orig/org/jboss/security/plugins/JBossSecurityContext.java 2023-12-17 08:04:11.748905792 +0100 ++++ picketlink/org/jboss/security/plugins/JBossSecurityContext.java 2023-12-17 08:04:43.368951953 +0100 +@@ -9,7 +9,7 @@ + import static org.jboss.security.SecurityConstants.ROLES_IDENTIFIER; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Enumeration; + import java.util.HashMap; + import java.util.Map; +diff -uNr picketlink-orig/org/jboss/security/plugins/JBossSecurityContextUtil.java picketlink/org/jboss/security/plugins/JBossSecurityContextUtil.java +--- picketlink-orig/org/jboss/security/plugins/JBossSecurityContextUtil.java 2023-12-17 08:04:11.748905792 +0100 ++++ picketlink/org/jboss/security/plugins/JBossSecurityContextUtil.java 2023-12-17 08:04:43.368951953 +0100 +@@ -26,7 +26,7 @@ + import static org.jboss.security.SecurityConstants.RUNAS_IDENTITY_IDENTIFIER; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + + import javax.security.auth.Subject; +diff -uNr picketlink-orig/org/jboss/security/SecurityUtil.java picketlink/org/jboss/security/SecurityUtil.java +--- picketlink-orig/org/jboss/security/SecurityUtil.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/jboss/security/SecurityUtil.java 2023-12-17 08:04:43.356951936 +0100 +@@ -21,7 +21,7 @@ + */ + package org.jboss.security; + +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Iterator; + import java.util.Set; + +diff -uNr picketlink-orig/org/jboss/security/SimpleGroup.java picketlink/org/jboss/security/SimpleGroup.java +--- picketlink-orig/org/jboss/security/SimpleGroup.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/jboss/security/SimpleGroup.java 2023-12-17 08:04:43.356951936 +0100 +@@ -24,7 +24,7 @@ + import java.security.AccessController; + import java.security.Principal; + import java.security.PrivilegedAction; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Collection; + import java.util.Collections; + import java.util.Enumeration; +diff -uNr picketlink-orig/org/picketbox/datasource/security/CallerIdentityLoginModule.java picketlink/org/picketbox/datasource/security/CallerIdentityLoginModule.java +--- picketlink-orig/org/picketbox/datasource/security/CallerIdentityLoginModule.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/picketbox/datasource/security/CallerIdentityLoginModule.java 2023-12-17 08:04:43.356951936 +0100 +@@ -22,7 +22,7 @@ + package org.picketbox.datasource.security; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + import java.util.Set; + +diff -uNr picketlink-orig/org/picketbox/datasource/security/ConfiguredIdentityLoginModule.java picketlink/org/picketbox/datasource/security/ConfiguredIdentityLoginModule.java +--- picketlink-orig/org/picketbox/datasource/security/ConfiguredIdentityLoginModule.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/picketbox/datasource/security/ConfiguredIdentityLoginModule.java 2023-12-17 08:04:43.356951936 +0100 +@@ -23,7 +23,7 @@ + + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + + import javax.resource.spi.security.PasswordCredential; +diff -uNr picketlink-orig/org/picketbox/datasource/security/JaasSecurityDomainIdentityLoginModule.java picketlink/org/picketbox/datasource/security/JaasSecurityDomainIdentityLoginModule.java +--- picketlink-orig/org/picketbox/datasource/security/JaasSecurityDomainIdentityLoginModule.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/picketbox/datasource/security/JaasSecurityDomainIdentityLoginModule.java 2023-12-17 08:04:43.356951936 +0100 +@@ -25,7 +25,7 @@ + import java.security.Principal; + import java.security.PrivilegedActionException; + import java.security.PrivilegedExceptionAction; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + + import javax.management.MBeanServer; +diff -uNr picketlink-orig/org/picketbox/datasource/security/PBEIdentityLoginModule.java picketlink/org/picketbox/datasource/security/PBEIdentityLoginModule.java +--- picketlink-orig/org/picketbox/datasource/security/PBEIdentityLoginModule.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/picketbox/datasource/security/PBEIdentityLoginModule.java 2023-12-17 08:04:43.356951936 +0100 +@@ -22,7 +22,7 @@ + package org.picketbox.datasource.security; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + + import javax.crypto.Cipher; +diff -uNr picketlink-orig/org/picketbox/datasource/security/SecureIdentityLoginModule.java picketlink/org/picketbox/datasource/security/SecureIdentityLoginModule.java +--- picketlink-orig/org/picketbox/datasource/security/SecureIdentityLoginModule.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/picketbox/datasource/security/SecureIdentityLoginModule.java 2023-12-17 08:04:43.356951936 +0100 +@@ -25,7 +25,7 @@ + import java.security.InvalidKeyException; + import java.security.NoSuchAlgorithmException; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + + import javax.crypto.BadPaddingException; +diff -uNr picketlink-orig/org/picketbox/datasource/security/SubjectActions.java picketlink/org/picketbox/datasource/security/SubjectActions.java +--- picketlink-orig/org/picketbox/datasource/security/SubjectActions.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/picketbox/datasource/security/SubjectActions.java 2023-12-17 08:04:43.356951936 +0100 +@@ -24,7 +24,7 @@ + import java.security.AccessController; + import java.security.Principal; + import java.security.PrivilegedAction; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Iterator; + import java.util.Set; + +diff -uNr picketlink-orig/org/picketbox/plugins/authorization/PicketBoxAuthorizationModule.java picketlink/org/picketbox/plugins/authorization/PicketBoxAuthorizationModule.java +--- picketlink-orig/org/picketbox/plugins/authorization/PicketBoxAuthorizationModule.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/picketbox/plugins/authorization/PicketBoxAuthorizationModule.java 2023-12-17 08:04:43.352951930 +0100 +@@ -22,7 +22,7 @@ + package org.picketbox.plugins.authorization; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Enumeration; + import java.util.HashSet; + import java.util.Map; +diff -uNr picketlink-orig/org/picketbox/util/PicketBoxUtil.java picketlink/org/picketbox/util/PicketBoxUtil.java +--- picketlink-orig/org/picketbox/util/PicketBoxUtil.java 2023-12-17 08:04:11.736905774 +0100 ++++ picketlink/org/picketbox/util/PicketBoxUtil.java 2023-12-17 08:04:43.352951930 +0100 +@@ -22,7 +22,7 @@ + package org.picketbox.util; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Set; + + import javax.security.auth.Subject; +diff -uNr picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/RegExUserNameLoginModule.java picketlink/org/picketlink/identity/federation/bindings/jboss/auth/RegExUserNameLoginModule.java +--- picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/RegExUserNameLoginModule.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/identity/federation/bindings/jboss/auth/RegExUserNameLoginModule.java 2023-12-17 08:04:43.352951930 +0100 +@@ -18,7 +18,7 @@ + package org.picketlink.identity.federation.bindings.jboss.auth; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Map; + import java.util.regex.Matcher; + import java.util.regex.Pattern; +diff -uNr picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAML20CommonTokenRoleAttributeProvider.java picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAML20CommonTokenRoleAttributeProvider.java +--- picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAML20CommonTokenRoleAttributeProvider.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAML20CommonTokenRoleAttributeProvider.java 2023-12-17 08:04:43.352951930 +0100 +@@ -1,7 +1,7 @@ + package org.picketlink.identity.federation.bindings.jboss.auth; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Enumeration; + import java.util.Map; + +diff -uNr picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAML2CommonLoginModule.java picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAML2CommonLoginModule.java +--- picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAML2CommonLoginModule.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAML2CommonLoginModule.java 2023-12-17 08:04:43.352951930 +0100 +@@ -22,7 +22,7 @@ + package org.picketlink.identity.federation.bindings.jboss.auth; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.List; + import java.util.Map; + +diff -uNr picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAML2STSCommonLoginModule.java picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAML2STSCommonLoginModule.java +--- picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAML2STSCommonLoginModule.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAML2STSCommonLoginModule.java 2023-12-17 08:04:43.352951930 +0100 +@@ -22,7 +22,7 @@ + package org.picketlink.identity.federation.bindings.jboss.auth; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.ArrayList; + import java.util.Date; + import java.util.HashMap; +diff -uNr picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAMLTokenCertValidatingCommonLoginModule.java picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAMLTokenCertValidatingCommonLoginModule.java +--- picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAMLTokenCertValidatingCommonLoginModule.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAMLTokenCertValidatingCommonLoginModule.java 2023-12-17 08:04:43.352951930 +0100 +@@ -24,7 +24,7 @@ + + import java.security.KeyStore; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.security.cert.CertPath; + import java.security.cert.CertPathValidator; + import java.security.cert.CertPathValidatorResult; +diff -uNr picketlink-orig/org/picketlink/identity/federation/bindings/jboss/subject/PicketLinkGroup.java picketlink/org/picketlink/identity/federation/bindings/jboss/subject/PicketLinkGroup.java +--- picketlink-orig/org/picketlink/identity/federation/bindings/jboss/subject/PicketLinkGroup.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/identity/federation/bindings/jboss/subject/PicketLinkGroup.java 2023-12-17 08:04:43.352951930 +0100 +@@ -22,7 +22,7 @@ + package org.picketlink.identity.federation.bindings.jboss.subject; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.Collections; + import java.util.Enumeration; + import java.util.HashSet; +@@ -46,7 +46,7 @@ + /** + * Add a role principal to group + * +- * @see java.security.acl.Group#addMember(java.security.Principal) ++ * @see org.jboss.security.Group#addMember(java.security.Principal) + */ + public boolean addMember(Principal role) { + return roles.add(role); +@@ -55,7 +55,7 @@ + /** + * Check if the role is a member of the group + * +- * @see java.security.acl.Group#isMember(java.security.Principal) ++ * @see org.jboss.security.Group#isMember(java.security.Principal) + */ + public boolean isMember(Principal role) { + return roles.contains(role); +@@ -64,7 +64,7 @@ + /** + * Get the group members + * +- * @see java.security.acl.Group#members() ++ * @see org.jboss.security.Group#members() + */ + public Enumeration members() { + Set readOnly = Collections.unmodifiableSet(roles); +@@ -74,7 +74,7 @@ + /** + * Remove role from groups + * +- * @see java.security.acl.Group#removeMember(java.security.Principal) ++ * @see org.jboss.security.Group#removeMember(java.security.Principal) + */ + public boolean removeMember(Principal user) { + return roles.remove(user); +diff -uNr picketlink-orig/org/picketlink/identity/federation/core/wstrust/auth/AbstractSTSLoginModule.java picketlink/org/picketlink/identity/federation/core/wstrust/auth/AbstractSTSLoginModule.java +--- picketlink-orig/org/picketlink/identity/federation/core/wstrust/auth/AbstractSTSLoginModule.java 2023-12-17 08:04:11.728905762 +0100 ++++ picketlink/org/picketlink/identity/federation/core/wstrust/auth/AbstractSTSLoginModule.java 2023-12-17 08:04:43.348951924 +0100 +@@ -57,7 +57,7 @@ + + import java.io.IOException; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.ArrayList; + import java.util.HashMap; + import java.util.List; +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/handler/AbstractSAML2Handler.java picketlink/org/picketlink/trust/jbossws/handler/AbstractSAML2Handler.java +--- picketlink-orig/org/picketlink/trust/jbossws/handler/AbstractSAML2Handler.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/trust/jbossws/handler/AbstractSAML2Handler.java 2023-12-17 08:04:43.352951930 +0100 +@@ -22,7 +22,7 @@ + package org.picketlink.trust.jbossws.handler; + + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.ArrayList; + import java.util.List; + +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/handler/SecurityActions.java picketlink/org/picketlink/trust/jbossws/handler/SecurityActions.java +--- picketlink-orig/org/picketlink/trust/jbossws/handler/SecurityActions.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/trust/jbossws/handler/SecurityActions.java 2023-12-17 08:04:43.352951930 +0100 +@@ -24,7 +24,7 @@ + import java.security.AccessController; + import java.security.Principal; + import java.security.PrivilegedAction; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.List; + + import javax.security.auth.Subject; +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/jaas/SAMLBearerTokenLoginModule.java picketlink/org/picketlink/trust/jbossws/jaas/SAMLBearerTokenLoginModule.java +--- picketlink-orig/org/picketlink/trust/jbossws/jaas/SAMLBearerTokenLoginModule.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/trust/jbossws/jaas/SAMLBearerTokenLoginModule.java 2023-12-17 08:04:43.352951930 +0100 +@@ -22,7 +22,7 @@ + import java.io.InputStream; + import java.net.URI; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.HashSet; + import java.util.List; + import java.util.Map; +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/jaas/SAMLRoleLoginModule.java picketlink/org/picketlink/trust/jbossws/jaas/SAMLRoleLoginModule.java +--- picketlink-orig/org/picketlink/trust/jbossws/jaas/SAMLRoleLoginModule.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/trust/jbossws/jaas/SAMLRoleLoginModule.java 2023-12-17 08:04:43.352951930 +0100 +@@ -23,7 +23,7 @@ + + import java.io.ByteArrayInputStream; + import java.security.Principal; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.List; + import java.util.Set; + +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/util/SecurityActions.java picketlink/org/picketlink/trust/jbossws/util/SecurityActions.java +--- picketlink-orig/org/picketlink/trust/jbossws/util/SecurityActions.java 2023-12-17 08:04:11.732905768 +0100 ++++ picketlink/org/picketlink/trust/jbossws/util/SecurityActions.java 2023-12-17 08:04:43.352951930 +0100 +@@ -24,7 +24,7 @@ + import java.security.AccessController; + import java.security.Principal; + import java.security.PrivilegedAction; +-import java.security.acl.Group; ++import org.jboss.security.Group; + import java.util.List; + + import javax.security.auth.Subject; diff --git a/sso-saml-plugin/src/main/patches/javax.servlet.patch b/sso-saml-plugin/src/main/patches/javax.servlet.patch new file mode 100644 index 000000000..7b5d590fd --- /dev/null +++ b/sso-saml-plugin/src/main/patches/javax.servlet.patch @@ -0,0 +1,813 @@ +diff -uNr picketlink-orig/org/jboss/security/auth/container/modules/HttpServletServerAuthModule.java picketlink/org/jboss/security/auth/container/modules/HttpServletServerAuthModule.java +--- picketlink-orig/org/jboss/security/auth/container/modules/HttpServletServerAuthModule.java 2023-12-17 08:04:43.420952029 +0100 ++++ picketlink/org/jboss/security/auth/container/modules/HttpServletServerAuthModule.java 2023-12-17 08:05:07.608987531 +0100 +@@ -27,8 +27,8 @@ + import javax.security.auth.message.AuthException; + import javax.security.auth.message.AuthStatus; + import javax.security.auth.message.MessageInfo; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; + + import org.jboss.security.PicketBoxMessages; + import org.jboss.security.SimplePrincipal; +diff -uNr picketlink-orig/org/jboss/security/auth/spi/otp/JBossTimeBasedOTPLoginModule.java picketlink/org/jboss/security/auth/spi/otp/JBossTimeBasedOTPLoginModule.java +--- picketlink-orig/org/jboss/security/auth/spi/otp/JBossTimeBasedOTPLoginModule.java 2023-12-17 08:04:43.420952029 +0100 ++++ picketlink/org/jboss/security/auth/spi/otp/JBossTimeBasedOTPLoginModule.java 2023-12-17 08:05:07.608987531 +0100 +@@ -41,7 +41,7 @@ + import javax.security.auth.spi.LoginModule; + import javax.security.jacc.PolicyContext; + import javax.security.jacc.PolicyContextException; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + + import org.jboss.security.PicketBoxLogger; + import org.jboss.security.PicketBoxMessages; +@@ -310,7 +310,7 @@ + String totp = null; + + //This is JBoss AS specific mechanism +- String WEB_REQUEST_KEY = "javax.servlet.http.HttpServletRequest"; ++ String WEB_REQUEST_KEY = "jakarta.servlet.http.HttpServletRequest"; + + try + { +diff -uNr picketlink-orig/org/jboss/security/authorization/modules/web/WebJACCPolicyModuleDelegate.java picketlink/org/jboss/security/authorization/modules/web/WebJACCPolicyModuleDelegate.java +--- picketlink-orig/org/jboss/security/authorization/modules/web/WebJACCPolicyModuleDelegate.java 2023-12-17 08:04:43.412952017 +0100 ++++ picketlink/org/jboss/security/authorization/modules/web/WebJACCPolicyModuleDelegate.java 2023-12-17 08:05:07.600987519 +0100 +@@ -34,7 +34,7 @@ + import javax.security.jacc.WebResourcePermission; + import javax.security.jacc.WebRoleRefPermission; + import javax.security.jacc.WebUserDataPermission; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + + import org.jboss.security.PicketBoxLogger; + import org.jboss.security.PicketBoxMessages; +diff -uNr picketlink-orig/org/jboss/security/authorization/modules/web/WebXACMLPolicyModuleDelegate.java picketlink/org/jboss/security/authorization/modules/web/WebXACMLPolicyModuleDelegate.java +--- picketlink-orig/org/jboss/security/authorization/modules/web/WebXACMLPolicyModuleDelegate.java 2023-12-17 08:04:43.412952017 +0100 ++++ picketlink/org/jboss/security/authorization/modules/web/WebXACMLPolicyModuleDelegate.java 2023-12-17 08:05:07.600987519 +0100 +@@ -26,7 +26,7 @@ + + import javax.security.auth.Subject; + import javax.security.jacc.PolicyContext; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + + import org.jboss.security.PicketBoxLogger; + import org.jboss.security.PicketBoxMessages; +diff -uNr picketlink-orig/org/jboss/security/authorization/modules/web/WebXACMLUtil.java picketlink/org/jboss/security/authorization/modules/web/WebXACMLUtil.java +--- picketlink-orig/org/jboss/security/authorization/modules/web/WebXACMLUtil.java 2023-12-17 08:04:43.412952017 +0100 ++++ picketlink/org/jboss/security/authorization/modules/web/WebXACMLUtil.java 2023-12-17 08:05:07.600987519 +0100 +@@ -29,7 +29,7 @@ + import java.util.Enumeration; + import java.util.List; + +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + + import org.jboss.security.PicketBoxLogger; + import org.jboss.security.PicketBoxMessages; +diff -uNr picketlink-orig/org/jboss/security/authorization/resources/WebResource.java picketlink/org/jboss/security/authorization/resources/WebResource.java +--- picketlink-orig/org/jboss/security/authorization/resources/WebResource.java 2023-12-17 08:04:43.412952017 +0100 ++++ picketlink/org/jboss/security/authorization/resources/WebResource.java 2023-12-17 08:05:07.600987519 +0100 +@@ -25,9 +25,9 @@ + import java.util.Enumeration; + import java.util.Map; + +-import javax.servlet.ServletRequest; +-import javax.servlet.ServletResponse; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.ServletRequest; ++import jakarta.servlet.ServletResponse; ++import jakarta.servlet.http.HttpServletRequest; + + import org.jboss.security.authorization.Resource; + import org.jboss.security.authorization.ResourceType; +diff -uNr picketlink-orig/org/jboss/security/javaee/AbstractWebAuthorizationHelper.java picketlink/org/jboss/security/javaee/AbstractWebAuthorizationHelper.java +--- picketlink-orig/org/jboss/security/javaee/AbstractWebAuthorizationHelper.java 2023-12-17 08:04:43.416952023 +0100 ++++ picketlink/org/jboss/security/javaee/AbstractWebAuthorizationHelper.java 2023-12-17 08:05:07.604987525 +0100 +@@ -27,8 +27,8 @@ + import java.util.Set; + + import javax.security.auth.Subject; +-import javax.servlet.ServletRequest; +-import javax.servlet.ServletResponse; ++import jakarta.servlet.ServletRequest; ++import jakarta.servlet.ServletResponse; + + /** + * Abstract Web Authorization Helper +diff -uNr picketlink-orig/org/jboss/security/plugins/javaee/WebAuthorizationHelper.java picketlink/org/jboss/security/plugins/javaee/WebAuthorizationHelper.java +--- picketlink-orig/org/jboss/security/plugins/javaee/WebAuthorizationHelper.java 2023-12-17 08:04:43.424952035 +0100 ++++ picketlink/org/jboss/security/plugins/javaee/WebAuthorizationHelper.java 2023-12-17 08:05:07.612987537 +0100 +@@ -29,8 +29,8 @@ + import java.util.Set; + + import javax.security.auth.Subject; +-import javax.servlet.ServletRequest; +-import javax.servlet.ServletResponse; ++import jakarta.servlet.ServletRequest; ++import jakarta.servlet.ServletResponse; + + import org.jboss.security.AuthorizationManager; + import org.jboss.security.PicketBoxLogger; +diff -uNr picketlink-orig/org/jboss/security/SecurityConstants.java picketlink/org/jboss/security/SecurityConstants.java +--- picketlink-orig/org/jboss/security/SecurityConstants.java 2023-12-17 08:04:43.408952012 +0100 ++++ picketlink/org/jboss/security/SecurityConstants.java 2023-12-17 08:05:07.596987514 +0100 +@@ -100,7 +100,7 @@ + + /** Policy Context Constants **/ + String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container"; +- String WEB_REQUEST_KEY = "javax.servlet.http.HttpServletRequest"; ++ String WEB_REQUEST_KEY = "jakarta.servlet.http.HttpServletRequest"; + String CALLBACK_HANDLER_KEY = "org.jboss.security.auth.spi.CallbackHandler"; + + /** +diff -uNr picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAMLTokenFromHttpRequestAbstractLoginModule.java picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAMLTokenFromHttpRequestAbstractLoginModule.java +--- picketlink-orig/org/picketlink/identity/federation/bindings/jboss/auth/SAMLTokenFromHttpRequestAbstractLoginModule.java 2023-12-17 08:04:43.404952006 +0100 ++++ picketlink/org/picketlink/identity/federation/bindings/jboss/auth/SAMLTokenFromHttpRequestAbstractLoginModule.java 2023-12-17 08:05:07.592987508 +0100 +@@ -29,7 +29,7 @@ + import javax.security.auth.Subject; + import javax.security.auth.callback.CallbackHandler; + import javax.security.jacc.PolicyContext; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + + import org.jboss.security.auth.spi.AbstractServerLoginModule; + import org.picketlink.common.PicketLinkLogger; +@@ -98,7 +98,7 @@ + */ + public static final String BASE64_TOKEN_ENCODING = "base64"; + +- public static final String WEB_REQUEST_KEY = "javax.servlet.http.HttpServletRequest"; ++ public static final String WEB_REQUEST_KEY = "jakarta.servlet.http.HttpServletRequest"; + public static final String REG_EX_PATTERN_KEY = "samlTokenHttpHeaderRegEx"; + public static final String REG_EX_GROUP_KEY = "samlTokenHttpHeaderRegExGroup"; + public static final String SAML_TOKEN_HTTP_HEADER_KEY = "samlTokenHttpHeader"; +diff -uNr picketlink-orig/org/picketlink/identity/federation/bindings/jboss/roles/JBossWebRoleGenerator.java picketlink/org/picketlink/identity/federation/bindings/jboss/roles/JBossWebRoleGenerator.java +--- picketlink-orig/org/picketlink/identity/federation/bindings/jboss/roles/JBossWebRoleGenerator.java 2023-12-17 08:04:43.404952006 +0100 ++++ picketlink/org/picketlink/identity/federation/bindings/jboss/roles/JBossWebRoleGenerator.java 2023-12-17 08:05:07.592987508 +0100 +@@ -23,7 +23,7 @@ + + import javax.security.jacc.PolicyContext; + import javax.security.jacc.PolicyContextException; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + import java.security.Principal; + import java.util.List; + +@@ -39,7 +39,7 @@ + //Use JACC to get the request + try { + HttpServletRequest request = +- (HttpServletRequest) PolicyContext.getContext("javax.servlet.http.HttpServletRequest"); ++ (HttpServletRequest) PolicyContext.getContext("jakarta.servlet.http.HttpServletRequest"); + if(request instanceof Request){ + Request catalinaRequest = (Request) request; + return super.generateRoles(catalinaRequest.getPrincipal()); +diff -uNr picketlink-orig/org/picketlink/identity/federation/core/audit/PicketLinkAuditHelper.java picketlink/org/picketlink/identity/federation/core/audit/PicketLinkAuditHelper.java +--- picketlink-orig/org/picketlink/identity/federation/core/audit/PicketLinkAuditHelper.java 2023-12-17 08:04:43.396951994 +0100 ++++ picketlink/org/picketlink/identity/federation/core/audit/PicketLinkAuditHelper.java 2023-12-17 08:05:07.584987496 +0100 +@@ -35,7 +35,7 @@ + import javax.naming.Context; + import javax.naming.InitialContext; + import javax.naming.NamingException; +-import javax.servlet.ServletContext; ++import jakarta.servlet.ServletContext; + import java.io.InputStream; + + /** +diff -uNr picketlink-orig/org/picketlink/identity/federation/core/saml/workflow/ServiceProviderSAMLWorkflow.java picketlink/org/picketlink/identity/federation/core/saml/workflow/ServiceProviderSAMLWorkflow.java +--- picketlink-orig/org/picketlink/identity/federation/core/saml/workflow/ServiceProviderSAMLWorkflow.java 2023-12-17 08:04:43.400952000 +0100 ++++ picketlink/org/picketlink/identity/federation/core/saml/workflow/ServiceProviderSAMLWorkflow.java 2023-12-17 08:05:07.588987502 +0100 +@@ -29,12 +29,12 @@ + import org.picketlink.identity.federation.web.util.RedirectBindingUtil; + import org.w3c.dom.Document; + +-import javax.servlet.RequestDispatcher; +-import javax.servlet.ServletContext; +-import javax.servlet.ServletException; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.RequestDispatcher; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.ServletException; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpSession; + + import java.io.IOException; + +@@ -215,7 +215,7 @@ + /** + * Send the payload via HTTP/POST + * @param destinationHolder {@link org.picketlink.identity.federation.core.saml.v2.holders.DestinationInfoHolder} holds info on the destination +- * @param response {@link javax.servlet.http.HttpServletResponse} ++ * @param response {@link jakarta.servlet.http.HttpServletResponse} + * @param willSendRequest whether it is a SAML request or response so that the page title can be set + * @throws IOException + */ +@@ -226,7 +226,7 @@ + /** + * Send the payload via HTTP/REDIRECT + * @param url the redirect url +- * @param response {@link javax.servlet.http.HttpServletResponse} ++ * @param response {@link jakarta.servlet.http.HttpServletResponse} + * @throws IOException + */ + public void sendRedirectForRequestor(String url, HttpServletResponse response) throws IOException { +@@ -236,7 +236,7 @@ + /** + * Send the payload via HTTP/REDIRECT + * @param destination the destination url +- * @param response {@link javax.servlet.http.HttpServletResponse} ++ * @param response {@link jakarta.servlet.http.HttpServletResponse} + * @throws IOException + */ + public void sendRedirectForResponder(String destination, HttpServletResponse response) throws IOException { +diff -uNr picketlink-orig/org/picketlink/identity/federation/core/util/CoreConfigUtil.java picketlink/org/picketlink/identity/federation/core/util/CoreConfigUtil.java +--- picketlink-orig/org/picketlink/identity/federation/core/util/CoreConfigUtil.java 2023-12-17 08:04:43.396951994 +0100 ++++ picketlink/org/picketlink/identity/federation/core/util/CoreConfigUtil.java 2023-12-17 08:05:07.580987490 +0100 +@@ -49,7 +49,7 @@ + import javax.crypto.SecretKeyFactory; + import javax.crypto.spec.PBEKeySpec; + import javax.crypto.spec.PBEParameterSpec; +-import javax.servlet.ServletContext; ++import jakarta.servlet.ServletContext; + import java.io.UnsupportedEncodingException; + import java.security.GeneralSecurityException; + import java.security.PublicKey; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/config/IdentityURLConfigurationProvider.java picketlink/org/picketlink/identity/federation/web/config/IdentityURLConfigurationProvider.java +--- picketlink-orig/org/picketlink/identity/federation/web/config/IdentityURLConfigurationProvider.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/config/IdentityURLConfigurationProvider.java 2023-12-17 08:05:07.572987479 +0100 +@@ -1,6 +1,6 @@ + package org.picketlink.identity.federation.web.config; + +-import javax.servlet.ServletContext; ++import jakarta.servlet.ServletContext; + import java.io.IOException; + import java.util.Map; + +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/config/PropertiesIdentityURLProvider.java picketlink/org/picketlink/identity/federation/web/config/PropertiesIdentityURLProvider.java +--- picketlink-orig/org/picketlink/identity/federation/web/config/PropertiesIdentityURLProvider.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/config/PropertiesIdentityURLProvider.java 2023-12-17 08:05:07.572987479 +0100 +@@ -17,7 +17,7 @@ + */ + package org.picketlink.identity.federation.web.config; + +-import javax.servlet.ServletContext; ++import jakarta.servlet.ServletContext; + import java.io.IOException; + import java.io.InputStream; + import java.util.HashMap; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/core/HTTPContext.java picketlink/org/picketlink/identity/federation/web/core/HTTPContext.java +--- picketlink-orig/org/picketlink/identity/federation/web/core/HTTPContext.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/core/HTTPContext.java 2023-12-17 08:05:07.572987479 +0100 +@@ -20,9 +20,9 @@ + import org.picketlink.identity.federation.core.interfaces.ProtocolContext; + import org.picketlink.identity.federation.core.interfaces.SecurityTokenProvider; + +-import javax.servlet.ServletContext; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; + import javax.xml.namespace.QName; + + /** +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/core/IdentityServer.java picketlink/org/picketlink/identity/federation/web/core/IdentityServer.java +--- picketlink-orig/org/picketlink/identity/federation/web/core/IdentityServer.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/core/IdentityServer.java 2023-12-17 08:05:07.572987479 +0100 +@@ -21,10 +21,10 @@ + import org.picketlink.common.PicketLinkLoggerFactory; + import org.picketlink.common.constants.GeneralConstants; + +-import javax.servlet.ServletContext; +-import javax.servlet.http.HttpSession; +-import javax.servlet.http.HttpSessionEvent; +-import javax.servlet.http.HttpSessionListener; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.http.HttpSession; ++import jakarta.servlet.http.HttpSessionEvent; ++import jakarta.servlet.http.HttpSessionListener; + import java.security.AccessController; + import java.security.PrivilegedAction; + import java.util.HashSet; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/filters/IDPFilter.java picketlink/org/picketlink/identity/federation/web/filters/IDPFilter.java +--- picketlink-orig/org/picketlink/identity/federation/web/filters/IDPFilter.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/filters/IDPFilter.java 2023-12-17 08:05:07.572987479 +0100 +@@ -112,18 +112,18 @@ + import org.picketlink.identity.federation.web.util.SAMLConfigurationProvider; + import org.w3c.dom.Document; + +-import javax.servlet.Filter; +-import javax.servlet.FilterChain; +-import javax.servlet.FilterConfig; +-import javax.servlet.RequestDispatcher; +-import javax.servlet.ServletContext; +-import javax.servlet.ServletException; +-import javax.servlet.ServletRequest; +-import javax.servlet.ServletResponse; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletRequestWrapper; +-import javax.servlet.http.HttpServletResponse; +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.Filter; ++import jakarta.servlet.FilterChain; ++import jakarta.servlet.FilterConfig; ++import jakarta.servlet.RequestDispatcher; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.ServletException; ++import jakarta.servlet.ServletRequest; ++import jakarta.servlet.ServletResponse; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequestWrapper; ++import jakarta.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpSession; + + import static org.picketlink.common.constants.GeneralConstants.AUDIT_HELPER; + import static org.picketlink.common.constants.GeneralConstants.CONFIGURATION; +@@ -134,7 +134,7 @@ + import static org.picketlink.common.util.StringUtil.isNullOrEmpty; + + /** +- * A {@link javax.servlet.Filter} that can be configured to convert a ++ * A {@link jakarta.servlet.Filter} that can be configured to convert a + * JavaEE Web Application to an IDP + * + * @author Anil Saldhana +@@ -1385,7 +1385,7 @@ + } + + /** +- *

Checks if the given {@link javax.servlet.http.HttpServletRequest} containes a SAML11 Target parameter. Usually this indicates that the given request is ++ *

Checks if the given {@link jakarta.servlet.http.HttpServletRequest} containes a SAML11 Target parameter. Usually this indicates that the given request is + * a SAML11 request.

+ * + * @param request +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/filters/SPFilter.java picketlink/org/picketlink/identity/federation/web/filters/SPFilter.java +--- picketlink-orig/org/picketlink/identity/federation/web/filters/SPFilter.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/filters/SPFilter.java 2023-12-17 08:05:07.572987479 +0100 +@@ -81,17 +81,17 @@ + import org.w3c.dom.Node; + import org.xml.sax.SAXException; + +-import javax.servlet.Filter; +-import javax.servlet.FilterChain; +-import javax.servlet.FilterConfig; +-import javax.servlet.RequestDispatcher; +-import javax.servlet.ServletContext; +-import javax.servlet.ServletException; +-import javax.servlet.ServletRequest; +-import javax.servlet.ServletResponse; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.Filter; ++import jakarta.servlet.FilterChain; ++import jakarta.servlet.FilterConfig; ++import jakarta.servlet.RequestDispatcher; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.ServletException; ++import jakarta.servlet.ServletRequest; ++import jakarta.servlet.ServletResponse; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpSession; + import javax.xml.crypto.MarshalException; + import javax.xml.crypto.dsig.CanonicalizationMethod; + import javax.xml.crypto.dsig.XMLSignatureException; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/BaseSAML2Handler.java picketlink/org/picketlink/identity/federation/web/handlers/saml2/BaseSAML2Handler.java +--- picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/BaseSAML2Handler.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/handlers/saml2/BaseSAML2Handler.java 2023-12-17 08:05:07.572987479 +0100 +@@ -32,8 +32,8 @@ + import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerResponse; + import org.picketlink.identity.federation.web.core.HTTPContext; + +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpSession; + import java.net.URI; + + /** +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/RolesGenerationHandler.java picketlink/org/picketlink/identity/federation/web/handlers/saml2/RolesGenerationHandler.java +--- picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/RolesGenerationHandler.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/handlers/saml2/RolesGenerationHandler.java 2023-12-17 08:05:07.572987479 +0100 +@@ -34,7 +34,7 @@ + import org.picketlink.identity.federation.saml.v2.protocol.LogoutRequestType; + import org.picketlink.identity.federation.web.core.HTTPContext; + +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.http.HttpSession; + import java.security.Principal; + import java.util.Arrays; + import java.util.List; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2AttributeHandler.java picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2AttributeHandler.java +--- picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2AttributeHandler.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2AttributeHandler.java 2023-12-17 08:05:07.572987479 +0100 +@@ -37,7 +37,7 @@ + import org.picketlink.identity.federation.saml.v2.protocol.ResponseType; + import org.picketlink.identity.federation.web.core.HTTPContext; + +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.http.HttpSession; + import java.security.Principal; + import java.util.ArrayList; + import java.util.HashMap; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2AuthenticationHandler.java picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2AuthenticationHandler.java +--- picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2AuthenticationHandler.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2AuthenticationHandler.java 2023-12-17 08:05:07.572987479 +0100 +@@ -78,8 +78,8 @@ + import org.w3c.dom.Element; + import org.w3c.dom.Node; + +-import javax.servlet.ServletContext; +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.http.HttpSession; + import javax.xml.namespace.QName; + import java.net.URI; + import java.security.Principal; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2InResponseToVerificationHandler.java picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2InResponseToVerificationHandler.java +--- picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2InResponseToVerificationHandler.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2InResponseToVerificationHandler.java 2023-12-17 08:05:07.572987479 +0100 +@@ -24,7 +24,7 @@ + import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerResponse; + import org.picketlink.identity.federation.saml.v2.protocol.ResponseType; + +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.http.HttpSession; + + /** + * Handler is useful on SP side. It's used for verification that InResponseId from SAML Authentication Response is same +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2LogOutHandler.java picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2LogOutHandler.java +--- picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2LogOutHandler.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2LogOutHandler.java 2023-12-17 08:05:07.572987479 +0100 +@@ -48,9 +48,9 @@ + import org.picketlink.identity.federation.web.core.IdentityServer; + import org.picketlink.identity.federation.web.util.RedirectBindingUtil; + +-import javax.servlet.ServletContext; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpSession; + import javax.xml.parsers.ParserConfigurationException; + import java.io.IOException; + import java.net.URI; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2SignatureValidationHandler.java picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2SignatureValidationHandler.java +--- picketlink-orig/org/picketlink/identity/federation/web/handlers/saml2/SAML2SignatureValidationHandler.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/handlers/saml2/SAML2SignatureValidationHandler.java 2023-12-17 08:05:07.572987479 +0100 +@@ -32,7 +32,7 @@ + import org.picketlink.identity.federation.web.util.RedirectBindingSignatureUtil; + import org.w3c.dom.Document; + +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + import java.security.PublicKey; + import java.util.Map; + +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/listeners/IDPHttpSessionListener.java picketlink/org/picketlink/identity/federation/web/listeners/IDPHttpSessionListener.java +--- picketlink-orig/org/picketlink/identity/federation/web/listeners/IDPHttpSessionListener.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/listeners/IDPHttpSessionListener.java 2023-12-17 08:05:07.572987479 +0100 +@@ -25,9 +25,9 @@ + import org.picketlink.identity.federation.core.sts.PicketLinkCoreSTS; + import org.picketlink.identity.federation.saml.v2.assertion.AssertionType; + +-import javax.servlet.http.HttpSession; +-import javax.servlet.http.HttpSessionEvent; +-import javax.servlet.http.HttpSessionListener; ++import jakarta.servlet.http.HttpSession; ++import jakarta.servlet.http.HttpSessionEvent; ++import jakarta.servlet.http.HttpSessionListener; + + /** + * An instance of {@link HttpSessionListener} at the IDP that performs actions when an {@link HttpSession} is created +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/process/ServiceProviderBaseProcessor.java picketlink/org/picketlink/identity/federation/web/process/ServiceProviderBaseProcessor.java +--- picketlink-orig/org/picketlink/identity/federation/web/process/ServiceProviderBaseProcessor.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/process/ServiceProviderBaseProcessor.java 2023-12-17 08:05:07.572987479 +0100 +@@ -44,7 +44,7 @@ + import org.picketlink.identity.federation.saml.v2.metadata.IDPSSODescriptorType; + import org.picketlink.identity.federation.web.core.HTTPContext; + +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + import java.io.IOException; + import java.net.URL; + import java.security.PublicKey; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/process/ServiceProviderSAMLRequestProcessor.java picketlink/org/picketlink/identity/federation/web/process/ServiceProviderSAMLRequestProcessor.java +--- picketlink-orig/org/picketlink/identity/federation/web/process/ServiceProviderSAMLRequestProcessor.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/process/ServiceProviderSAMLRequestProcessor.java 2023-12-17 08:05:07.572987479 +0100 +@@ -38,7 +38,7 @@ + import org.picketlink.identity.federation.web.util.RedirectBindingUtil.RedirectBindingUtilDestHolder; + import org.w3c.dom.Document; + +-import javax.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpServletResponse; + import java.io.IOException; + import java.io.InputStream; + import java.util.Set; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/servlets/IDPLoginServlet.java picketlink/org/picketlink/identity/federation/web/servlets/IDPLoginServlet.java +--- picketlink-orig/org/picketlink/identity/federation/web/servlets/IDPLoginServlet.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/servlets/IDPLoginServlet.java 2023-12-17 08:05:07.572987479 +0100 +@@ -23,14 +23,14 @@ + import org.picketlink.identity.federation.web.interfaces.ILoginHandler; + + import javax.security.auth.login.LoginException; +-import javax.servlet.RequestDispatcher; +-import javax.servlet.ServletConfig; +-import javax.servlet.ServletContext; +-import javax.servlet.ServletException; +-import javax.servlet.http.HttpServlet; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.RequestDispatcher; ++import jakarta.servlet.ServletConfig; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.ServletException; ++import jakarta.servlet.http.HttpServlet; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpSession; + import java.io.IOException; + import java.security.Principal; + +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/servlets/IDPServlet.java picketlink/org/picketlink/identity/federation/web/servlets/IDPServlet.java +--- picketlink-orig/org/picketlink/identity/federation/web/servlets/IDPServlet.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/servlets/IDPServlet.java 2023-12-17 08:05:07.572987479 +0100 +@@ -68,13 +68,13 @@ + import org.picketlink.identity.federation.web.util.SAMLConfigurationProvider; + import org.w3c.dom.Document; + +-import javax.servlet.ServletConfig; +-import javax.servlet.ServletContext; +-import javax.servlet.ServletException; +-import javax.servlet.http.HttpServlet; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.ServletConfig; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.ServletException; ++import jakarta.servlet.http.HttpServlet; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpSession; + import javax.xml.crypto.dsig.CanonicalizationMethod; + import java.io.File; + import java.io.IOException; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/servlets/saml/CircleOfTrustServlet.java picketlink/org/picketlink/identity/federation/web/servlets/saml/CircleOfTrustServlet.java +--- picketlink-orig/org/picketlink/identity/federation/web/servlets/saml/CircleOfTrustServlet.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/servlets/saml/CircleOfTrustServlet.java 2023-12-17 08:05:07.572987479 +0100 +@@ -22,12 +22,12 @@ + import org.picketlink.identity.federation.core.saml.v2.metadata.store.IMetadataConfigurationStore; + import org.picketlink.identity.federation.saml.v2.metadata.EntityDescriptorType; + +-import javax.servlet.ServletConfig; +-import javax.servlet.ServletException; +-import javax.servlet.http.HttpServlet; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; +-import javax.servlet.http.HttpSession; ++import jakarta.servlet.ServletConfig; ++import jakarta.servlet.ServletException; ++import jakarta.servlet.http.HttpServlet; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpSession; + import java.io.IOException; + import java.util.HashMap; + import java.util.Map; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/servlets/saml/MetadataServlet.java picketlink/org/picketlink/identity/federation/web/servlets/saml/MetadataServlet.java +--- picketlink-orig/org/picketlink/identity/federation/web/servlets/saml/MetadataServlet.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/servlets/saml/MetadataServlet.java 2023-12-17 08:05:07.572987479 +0100 +@@ -42,12 +42,12 @@ + import org.picketlink.identity.federation.web.util.ConfigurationUtil; + import org.w3c.dom.Element; + +-import javax.servlet.ServletConfig; +-import javax.servlet.ServletContext; +-import javax.servlet.ServletException; +-import javax.servlet.http.HttpServlet; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; ++import jakarta.servlet.ServletConfig; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.ServletException; ++import jakarta.servlet.http.HttpServlet; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; + import javax.xml.stream.XMLStreamWriter; + import java.io.IOException; + import java.io.InputStream; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/servlets/saml/MetadataServletSP.java picketlink/org/picketlink/identity/federation/web/servlets/saml/MetadataServletSP.java +--- picketlink-orig/org/picketlink/identity/federation/web/servlets/saml/MetadataServletSP.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/servlets/saml/MetadataServletSP.java 2023-12-17 08:05:07.572987479 +0100 +@@ -34,12 +34,12 @@ + import java.util.List; + import java.util.Map; + +-import javax.servlet.ServletConfig; +-import javax.servlet.ServletContext; +-import javax.servlet.ServletException; +-import javax.servlet.http.HttpServlet; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; ++import jakarta.servlet.ServletConfig; ++import jakarta.servlet.ServletContext; ++import jakarta.servlet.ServletException; ++import jakarta.servlet.http.HttpServlet; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; + import javax.xml.crypto.dsig.DigestMethod; + import javax.xml.crypto.dsig.SignatureMethod; + import javax.xml.parsers.DocumentBuilderFactory; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/servlets/saml/SOAPSAMLXACMLServlet.java picketlink/org/picketlink/identity/federation/web/servlets/saml/SOAPSAMLXACMLServlet.java +--- picketlink-orig/org/picketlink/identity/federation/web/servlets/saml/SOAPSAMLXACMLServlet.java 2023-12-17 08:04:43.388951982 +0100 ++++ picketlink/org/picketlink/identity/federation/web/servlets/saml/SOAPSAMLXACMLServlet.java 2023-12-17 08:05:07.572987479 +0100 +@@ -37,11 +37,11 @@ + import org.w3c.dom.Node; + import org.w3c.dom.NodeList; + +-import javax.servlet.ServletConfig; +-import javax.servlet.ServletException; +-import javax.servlet.http.HttpServlet; +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; ++import jakarta.servlet.ServletConfig; ++import jakarta.servlet.ServletException; ++import jakarta.servlet.http.HttpServlet; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; + import javax.xml.soap.SOAPBody; + import javax.xml.soap.SOAPEnvelope; + import javax.xml.soap.SOAPException; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/util/ConfigurationUtil.java picketlink/org/picketlink/identity/federation/web/util/ConfigurationUtil.java +--- picketlink-orig/org/picketlink/identity/federation/web/util/ConfigurationUtil.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/util/ConfigurationUtil.java 2023-12-17 08:05:07.572987479 +0100 +@@ -36,7 +36,7 @@ + import org.picketlink.identity.federation.core.audit.PicketLinkAuditHelper; + import org.picketlink.identity.federation.web.config.AbstractSAMLConfigurationProvider; + +-import javax.servlet.ServletContext; ++import jakarta.servlet.ServletContext; + + import static org.picketlink.common.constants.GeneralConstants.AUDIT_HELPER; + import static org.picketlink.common.constants.GeneralConstants.CONFIG_FILE_LOCATION; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/util/HTTPRedirectUtil.java picketlink/org/picketlink/identity/federation/web/util/HTTPRedirectUtil.java +--- picketlink-orig/org/picketlink/identity/federation/web/util/HTTPRedirectUtil.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/util/HTTPRedirectUtil.java 2023-12-17 08:05:07.572987479 +0100 +@@ -17,7 +17,7 @@ + */ + package org.picketlink.identity.federation.web.util; + +-import javax.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpServletResponse; + import java.io.IOException; + + /** +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/util/IDPWebRequestUtil.java picketlink/org/picketlink/identity/federation/web/util/IDPWebRequestUtil.java +--- picketlink-orig/org/picketlink/identity/federation/web/util/IDPWebRequestUtil.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/util/IDPWebRequestUtil.java 2023-12-17 08:05:07.572987479 +0100 +@@ -46,8 +46,8 @@ + import org.picketlink.identity.federation.saml.v2.protocol.ResponseType; + import org.w3c.dom.Document; + +-import javax.servlet.http.HttpServletRequest; +-import javax.servlet.http.HttpServletResponse; ++import jakarta.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletResponse; + import javax.xml.crypto.dsig.CanonicalizationMethod; + import java.io.ByteArrayInputStream; + import java.io.IOException; +diff -uNr picketlink-orig/org/picketlink/identity/federation/web/util/PostBindingUtil.java picketlink/org/picketlink/identity/federation/web/util/PostBindingUtil.java +--- picketlink-orig/org/picketlink/identity/federation/web/util/PostBindingUtil.java 2023-12-17 08:04:43.384951976 +0100 ++++ picketlink/org/picketlink/identity/federation/web/util/PostBindingUtil.java 2023-12-17 08:05:07.572987479 +0100 +@@ -27,8 +27,8 @@ + import org.picketlink.common.util.Base64; + import org.picketlink.identity.federation.core.saml.v2.holders.DestinationInfoHolder; + +-import javax.servlet.ServletOutputStream; +-import javax.servlet.http.HttpServletResponse; ++import jakarta.servlet.ServletOutputStream; ++import jakarta.servlet.http.HttpServletResponse; + import java.io.ByteArrayInputStream; + import java.io.IOException; + import java.io.InputStream; +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/handler/AbstractPicketLinkTrustHandler.java picketlink/org/picketlink/trust/jbossws/handler/AbstractPicketLinkTrustHandler.java +--- picketlink-orig/org/picketlink/trust/jbossws/handler/AbstractPicketLinkTrustHandler.java 2023-12-17 08:04:43.404952006 +0100 ++++ picketlink/org/picketlink/trust/jbossws/handler/AbstractPicketLinkTrustHandler.java 2023-12-17 08:05:07.592987508 +0100 +@@ -41,7 +41,7 @@ + import javax.naming.InitialContext; + import javax.naming.NamingException; + import javax.security.auth.Subject; +-import javax.servlet.ServletContext; ++import jakarta.servlet.ServletContext; + import javax.xml.namespace.QName; + import javax.xml.ws.handler.LogicalMessageContext; + import javax.xml.ws.handler.MessageContext; +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/handler/AbstractWSAuthorizationHandler.java picketlink/org/picketlink/trust/jbossws/handler/AbstractWSAuthorizationHandler.java +--- picketlink-orig/org/picketlink/trust/jbossws/handler/AbstractWSAuthorizationHandler.java 2023-12-17 08:04:43.404952006 +0100 ++++ picketlink/org/picketlink/trust/jbossws/handler/AbstractWSAuthorizationHandler.java 2023-12-17 08:05:07.592987508 +0100 +@@ -30,7 +30,7 @@ + import java.util.Set; + + import javax.security.auth.Subject; +-import javax.servlet.ServletContext; ++import jakarta.servlet.ServletContext; + import javax.xml.namespace.QName; + import javax.xml.soap.SOAPBody; + import javax.xml.soap.SOAPException; +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/handler/BinaryTokenHandler.java picketlink/org/picketlink/trust/jbossws/handler/BinaryTokenHandler.java +--- picketlink-orig/org/picketlink/trust/jbossws/handler/BinaryTokenHandler.java 2023-12-17 08:04:43.404952006 +0100 ++++ picketlink/org/picketlink/trust/jbossws/handler/BinaryTokenHandler.java 2023-12-17 08:05:07.592987508 +0100 +@@ -26,8 +26,8 @@ + + import javax.security.jacc.PolicyContext; + import javax.security.jacc.PolicyContextException; +-import javax.servlet.http.Cookie; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.Cookie; ++import jakarta.servlet.http.HttpServletRequest; + import javax.xml.namespace.QName; + import javax.xml.soap.SOAPElement; + import javax.xml.soap.SOAPEnvelope; +@@ -267,7 +267,7 @@ + HttpServletRequest request = (HttpServletRequest) msgContext.get(MessageContext.SERVLET_REQUEST); + if (request == null) { + try { +- request = (HttpServletRequest) PolicyContext.getContext("javax.servlet.http.HttpServletRequest"); ++ request = (HttpServletRequest) PolicyContext.getContext("jakarta.servlet.http.HttpServletRequest"); + } catch (PolicyContextException e) { + throw new RuntimeException(e); + } +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/handler/SamlRequestSecurityTokenHandler.java picketlink/org/picketlink/trust/jbossws/handler/SamlRequestSecurityTokenHandler.java +--- picketlink-orig/org/picketlink/trust/jbossws/handler/SamlRequestSecurityTokenHandler.java 2023-12-17 08:04:43.404952006 +0100 ++++ picketlink/org/picketlink/trust/jbossws/handler/SamlRequestSecurityTokenHandler.java 2023-12-17 08:05:07.592987508 +0100 +@@ -25,7 +25,7 @@ + + import javax.security.jacc.PolicyContext; + import javax.security.jacc.PolicyContextException; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + import javax.xml.namespace.QName; + import javax.xml.soap.SOAPBodyElement; + import javax.xml.soap.SOAPElement; +@@ -106,7 +106,7 @@ + HttpServletRequest request = (HttpServletRequest) msgContext.get(MessageContext.SERVLET_REQUEST); + if (request == null) { + try { +- request = (HttpServletRequest) PolicyContext.getContext("javax.servlet.http.HttpServletRequest"); ++ request = (HttpServletRequest) PolicyContext.getContext("jakarta.servlet.http.HttpServletRequest"); + } catch (PolicyContextException e) { + return null; + } +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/jaas/SAMLBearerTokenLoginModule.java picketlink/org/picketlink/trust/jbossws/jaas/SAMLBearerTokenLoginModule.java +--- picketlink-orig/org/picketlink/trust/jbossws/jaas/SAMLBearerTokenLoginModule.java 2023-12-17 08:04:43.404952006 +0100 ++++ picketlink/org/picketlink/trust/jbossws/jaas/SAMLBearerTokenLoginModule.java 2023-12-17 08:05:07.592987508 +0100 +@@ -32,7 +32,7 @@ + import javax.security.auth.callback.CallbackHandler; + import javax.security.auth.login.LoginException; + import javax.security.jacc.PolicyContext; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + import javax.xml.datatype.XMLGregorianCalendar; + import javax.xml.stream.XMLEventReader; + import javax.xml.stream.XMLInputFactory; +@@ -105,7 +105,7 @@ + public boolean login() throws LoginException { + InputStream is = null; + try { +- HttpServletRequest request = (HttpServletRequest) PolicyContext.getContext("javax.servlet.http.HttpServletRequest"); ++ HttpServletRequest request = (HttpServletRequest) PolicyContext.getContext("jakarta.servlet.http.HttpServletRequest"); + String authorization = request.getHeader(AUTHORIZATION); + if (authorization != null && authorization.startsWith(BASIC)) { + String b64Data = authorization.substring(6); +diff -uNr picketlink-orig/org/picketlink/trust/jbossws/PicketLinkDispatch.java picketlink/org/picketlink/trust/jbossws/PicketLinkDispatch.java +--- picketlink-orig/org/picketlink/trust/jbossws/PicketLinkDispatch.java 2023-12-17 08:04:43.404952006 +0100 ++++ picketlink/org/picketlink/trust/jbossws/PicketLinkDispatch.java 2023-12-17 08:05:07.592987508 +0100 +@@ -34,7 +34,7 @@ + import javax.net.ssl.SSLSocketFactory; + import javax.security.jacc.PolicyContext; + import javax.security.jacc.PolicyContextException; +-import javax.servlet.http.HttpServletRequest; ++import jakarta.servlet.http.HttpServletRequest; + import javax.xml.bind.JAXBContext; + import javax.xml.namespace.QName; + import javax.xml.soap.SOAPConnection; +@@ -121,7 +121,7 @@ + msgContext.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, Boolean.TRUE); + + /** The JACC PolicyContext key for the current Subject */ +- String WEB_REQUEST_KEY = "javax.servlet.http.HttpServletRequest"; ++ String WEB_REQUEST_KEY = "jakarta.servlet.http.HttpServletRequest"; + + HttpServletRequest request = null; + try { diff --git a/sso-saml-plugin/src/main/resources/conf/configuration.xml b/sso-saml-plugin/src/main/resources/conf/configuration.xml new file mode 100644 index 000000000..b8c940b02 --- /dev/null +++ b/sso-saml-plugin/src/main/resources/conf/configuration.xml @@ -0,0 +1,38 @@ + + + + + + SAMLProperties + org.exoplatform.container.ExtendedPropertyConfigurator + + + SAMLProperties + + + + + + + + diff --git a/saml/gatein-saml-plugin/src/main/resources/conf/portal/configuration.xml b/sso-saml-plugin/src/main/resources/conf/portal/configuration.xml similarity index 55% rename from saml/gatein-saml-plugin/src/main/resources/conf/portal/configuration.xml rename to sso-saml-plugin/src/main/resources/conf/portal/configuration.xml index 5bdaea41f..a8f2b1435 100644 --- a/saml/gatein-saml-plugin/src/main/resources/conf/portal/configuration.xml +++ b/sso-saml-plugin/src/main/resources/conf/portal/configuration.xml @@ -1,68 +1,68 @@ + org.gatein.sso.integration.SSOFilterIntegrator - PortalIDPWebBrowserSSOFilter + LoginRedirectFilter addPlugin org.gatein.sso.integration.SSOFilterIntegratorPlugin filterClass - org.gatein.sso.saml.plugin.filter.PortalIDPWebBrowserSSOFilter + org.gatein.sso.agent.filter.LoginRedirectFilter enabled - ${gatein.sso.filter.saml.idp.enabled:false} + ${gatein.sso.filter.login.enabled:true} filterMapping /sso - CONFIG_FILE - ${gatein.sso.saml.config.file} - - - IGNORE_SIGNATURES - ${gatein.sso.saml.signature.ignore:true} + LOGIN_URL + ${gatein.sso.filter.login.sso.url} + + + + org.gatein.sso.integration.SSOFilterIntegrator - PortalSPWebBrowserSSOFilter + LogoutFilter addPlugin org.gatein.sso.integration.SSOFilterIntegratorPlugin filterClass - org.gatein.sso.saml.plugin.filter.SAML2LogoutFilter + ${gatein.sso.filter.logout.class} enabled - ${gatein.sso.saml.sp.enabled:false} + ${gatein.sso.filter.logout.enabled:true} filterMapping @@ -70,7 +70,7 @@ CONFIG_FILE - ${exo.conf.dir}/saml2/picketlink-sp.xml + ${gatein.sso.saml.config.file} IGNORE_SIGNATURES @@ -80,7 +80,12 @@ ROLES users + + LOGOUT_URL + ${gatein.sso.filter.logout.url} + + diff --git a/saml/gatein-saml-plugin/src/test/java/org/gatein/sso/saml/plugin/filter/SAML2LogoutFilterTest.java b/sso-saml-plugin/src/test/java/org/gatein/sso/saml/plugin/filter/SAML2LogoutFilterTest.java similarity index 96% rename from saml/gatein-saml-plugin/src/test/java/org/gatein/sso/saml/plugin/filter/SAML2LogoutFilterTest.java rename to sso-saml-plugin/src/test/java/org/gatein/sso/saml/plugin/filter/SAML2LogoutFilterTest.java index bd71d64ed..2c55b2219 100644 --- a/saml/gatein-saml-plugin/src/test/java/org/gatein/sso/saml/plugin/filter/SAML2LogoutFilterTest.java +++ b/sso-saml-plugin/src/test/java/org/gatein/sso/saml/plugin/filter/SAML2LogoutFilterTest.java @@ -7,12 +7,12 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import org.mockito.internal.verification.VerificationModeFactory; import org.picketlink.common.constants.GeneralConstants; diff --git a/saml/gatein-saml-plugin/src/test/resources/jbid_test_keystore.jks b/sso-saml-plugin/src/test/resources/jbid_test_keystore.jks similarity index 100% rename from saml/gatein-saml-plugin/src/test/resources/jbid_test_keystore.jks rename to sso-saml-plugin/src/test/resources/jbid_test_keystore.jks diff --git a/saml/gatein-saml-plugin/src/test/resources/picketlink-sp.xml b/sso-saml-plugin/src/test/resources/picketlink-sp.xml similarity index 100% rename from saml/gatein-saml-plugin/src/test/resources/picketlink-sp.xml rename to sso-saml-plugin/src/test/resources/picketlink-sp.xml