/* * Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.identity.authenticator.saml2.sso.ui.authenticator; import org.apache.axis2.client.ServiceClient; import org.apache.axis2.context.ConfigurationContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.opensaml.saml2.core.Assertion; import org.opensaml.saml2.core.AuthnStatement; import org.opensaml.saml2.core.Response; import org.wso2.carbon.CarbonConstants; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.core.common.AuthenticationException; import org.wso2.carbon.core.security.AuthenticatorsConfiguration; import org.wso2.carbon.identity.authenticator.saml2.sso.common.SAML2SSOAuthenticatorConstants; import org.wso2.carbon.identity.authenticator.saml2.sso.common.SAML2SSOUIAuthenticatorException; import org.wso2.carbon.identity.authenticator.saml2.sso.common.Util; import org.wso2.carbon.identity.authenticator.saml2.sso.ui.client.SAML2SSOAuthenticationClient; import org.wso2.carbon.identity.authenticator.saml2.sso.ui.internal.SAML2SSOAuthFEDataHolder; import org.wso2.carbon.identity.authenticator.saml2.sso.ui.session.SSOSessionManager; import org.wso2.carbon.ui.AbstractCarbonUIAuthenticator; import org.wso2.carbon.ui.CarbonSSOSessionManager; import org.wso2.carbon.ui.CarbonUIUtil; import org.wso2.carbon.user.core.UserCoreConstants; import org.wso2.carbon.utils.ServerConstants; import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.util.List; import java.util.Map; public class SAML2SSOUIAuthenticator extends AbstractCarbonUIAuthenticator { public static final Log log = LogFactory.getLog(SAML2SSOUIAuthenticator.class); private static final Log AUDIT_LOG = CarbonConstants.AUDIT_LOG; private static final int DEFAULT_PRIORITY_LEVEL = 50; private static final String AUTHENTICATOR_NAME = "SAML2SSOUIAuthenticator"; public boolean canHandle(HttpServletRequest request) { String relayState = request.getParameter(SAML2SSOAuthenticatorConstants.HTTP_POST_PARAM_RELAY_STATE); Object samlResponse = request.getAttribute(SAML2SSOAuthenticatorConstants.HTTP_ATTR_SAML2_RESP_TOKEN); // if it is a logout request, do not check for Response and Relay State if (request.getRequestURI().indexOf("/carbon/admin/logout_action.jsp") > -1) { return true; } // in case of a login request, check for Response and Relay State if (samlResponse != null && samlResponse instanceof Response && relayState != null) { return true; } return false; } public void authenticate(HttpServletRequest request) throws AuthenticationException { boolean isAuthenticated = false; String auditResult = SAML2SSOAuthenticatorConstants.AUDIT_RESULT_FAILED; HttpSession session = request.getSession(); Response samlResponse = (Response) request.getAttribute(SAML2SSOAuthenticatorConstants.HTTP_ATTR_SAML2_RESP_TOKEN); String responseStr = request.getParameter(SAML2SSOAuthenticatorConstants.HTTP_POST_PARAM_SAML2_RESP); String username = Util.getUsernameFromResponse(samlResponse); ServletContext servletContext = request.getSession().getServletContext(); ConfigurationContext configContext = (ConfigurationContext) servletContext.getAttribute( CarbonConstants.CONFIGURATION_CONTEXT); String backEndServerURL = request.getParameter("backendURL"); if (backEndServerURL == null) { backEndServerURL = CarbonUIUtil.getServerURL(servletContext, session); } session.setAttribute(CarbonConstants.SERVER_URL, backEndServerURL); String cookie = (String) session.getAttribute(ServerConstants.ADMIN_SERVICE_AUTH_TOKEN); // authorize the user with the back-end SAML2SSOAuthenticationClient authenticationClient = null; try { if (log.isDebugEnabled()) { log.debug("Invoking the SAML2 SSO Authenticator BE for the Response : " + responseStr); } authenticationClient = new SAML2SSOAuthenticationClient( configContext, backEndServerURL, cookie, session); isAuthenticated = authenticationClient.login(responseStr, username); // add an entry to CarbonSSOSessionManager : IdpSessionIndex --> localSessionId if (isAuthenticated) { CarbonSSOSessionManager ssoSessionManager = SAML2SSOAuthFEDataHolder.getInstance().getCarbonSSOSessionManager(); String sessionId = getSessionIndexFromResponse(samlResponse); if (sessionId != null) { // Session id is provided only when Single Logout enabled at the IdP. ssoSessionManager.addSessionMapping(getSessionIndexFromResponse(samlResponse), session.getId()); request.getSession().setAttribute(SAML2SSOAuthenticatorConstants.IDP_SESSION_INDEX, sessionId); SSOSessionManager.getInstance().addSession(sessionId, request.getSession()); } onSuccessAdminLogin(request, username); auditResult = SAML2SSOAuthenticatorConstants.AUDIT_RESULT_SUCCESS; } else { log.error("Authentication failed."); } } catch (SAML2SSOUIAuthenticatorException e) { log.error("Error when authenticating the user : " + username, e); throw new AuthenticationException("Error when authenticating the user : " + username, e); } catch (Exception e) { log.error("Error when creating SAML2SSOAuthenticationClient.", e); throw new AuthenticationException("Error when creating SAML2SSOAuthenticationClient.", e); } if (username != null && username.trim().length() > 0 && AUDIT_LOG.isInfoEnabled()) { String tenantAwareUsername = MultitenantUtils.getTenantAwareUsername(username); String tenantDomain = MultitenantUtils.getTenantDomain(username); String auditInitiator = tenantAwareUsername + UserCoreConstants.TENANT_DOMAIN_COMBINER + tenantDomain; String auditData = ""; AUDIT_LOG.info(String.format(SAML2SSOAuthenticatorConstants.AUDIT_MESSAGE, auditInitiator, SAML2SSOAuthenticatorConstants.AUDIT_ACTION_LOGIN, AUTHENTICATOR_NAME, auditData, auditResult)); } if (!isAuthenticated) { throw new AuthenticationException("Authentication failure " + username); } } public void unauthenticate(Object o) throws Exception { String auditResult = SAML2SSOAuthenticatorConstants.AUDIT_RESULT_FAILED; HttpServletRequest request = null; HttpSession session = null; if (o instanceof HttpSession) { session = (HttpSession) o; } else { request = (HttpServletRequest) o; session = request.getSession(); } String username = (String) session.getAttribute(CarbonConstants.LOGGED_USER); ServletContext servletContext = session.getServletContext(); ConfigurationContext configContext = (ConfigurationContext) servletContext .getAttribute(CarbonConstants.CONFIGURATION_CONTEXT); String backendServerURL = CarbonUIUtil.getServerURL(servletContext, session); try { String cookie = (String) session.getAttribute(ServerConstants.ADMIN_SERVICE_AUTH_TOKEN); SAML2SSOAuthenticationClient authClient = new SAML2SSOAuthenticationClient(configContext, backendServerURL, cookie, session); authClient.logout(session); // // memory cleanup : remove the invalid session from the invalid session list at the SSOSessionManager // CarbonSSOSessionManager ssoSessionManager = // SAML2SSOAuthFEDataHolder.getInstance().getCarbonSSOSessionManager(); // ssoSessionManager.removeInvalidSession(session.getId()); if (request != null) { // this attribute is used to avoid generate the logout request request.setAttribute(SAML2SSOAuthenticatorConstants.HTTP_ATTR_IS_LOGOUT_REQ, Boolean.valueOf(true)); request.setAttribute(SAML2SSOAuthenticatorConstants.LOGGED_IN_USER, session.getAttribute( "logged-user")); if(!Util.isLogoutSupportedIDP()) { request.setAttribute(SAML2SSOAuthenticatorConstants.EXTERNAL_LOGOUT_PAGE, Util.getExternalLogoutPage()); } } auditResult = SAML2SSOAuthenticatorConstants.AUDIT_RESULT_SUCCESS; if(username != null && !"".equals(username.trim()) && request != null && "true".equalsIgnoreCase(request.getParameter("logoutcomplete"))) { if(session.getAttribute("tenantDomain") != null) { // Build username for authorized user login // username in the session is in tenantAware manner username = username + UserCoreConstants.TENANT_DOMAIN_COMBINER + PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); } else { // Keep same username for unauthorized user login } log.info(username + " successfully logged out"); } } catch (Exception ignored) { String msg = "Configuration context is null."; log.error(msg); throw new Exception(msg); } finally { if (username != null && username.trim().length() > 0 && AUDIT_LOG.isInfoEnabled() && request != null && "true".equalsIgnoreCase(request.getParameter("logoutcomplete"))) { // use the username built above (when printing info log) String auditInitiator = username; String auditData = ""; AUDIT_LOG.info(String.format(SAML2SSOAuthenticatorConstants.AUDIT_MESSAGE, auditInitiator, SAML2SSOAuthenticatorConstants.AUDIT_ACTION_LOGOUT, AUTHENTICATOR_NAME, auditData, auditResult)); } } } public int getPriority() { AuthenticatorsConfiguration authenticatorsConfiguration = AuthenticatorsConfiguration.getInstance(); AuthenticatorsConfiguration.AuthenticatorConfig authenticatorConfig = authenticatorsConfiguration.getAuthenticatorConfig(SAML2SSOAuthenticatorConstants.AUTHENTICATOR_NAME); if (authenticatorConfig != null && authenticatorConfig.getPriority() > 0) { return authenticatorConfig.getPriority(); } return DEFAULT_PRIORITY_LEVEL; } public String getAuthenticatorName() { return SAML2SSOAuthenticatorConstants.AUTHENTICATOR_NAME; } public boolean isDisabled() { AuthenticatorsConfiguration authenticatorsConfiguration = AuthenticatorsConfiguration.getInstance(); AuthenticatorsConfiguration.AuthenticatorConfig authenticatorConfig = authenticatorsConfiguration.getAuthenticatorConfig(SAML2SSOAuthenticatorConstants.AUTHENTICATOR_NAME); if (authenticatorConfig != null) { return authenticatorConfig.isDisabled(); } return false; } /** * Get the username from the SAML2 Response * * @param response SAML2 Response * @return username username contained in the SAML Response */ private String getUsernameFromResponse(Response response) { List<Assertion> assertions = response.getAssertions(); Assertion assertion = null; if (assertions != null && assertions.size() > 0) { // There can be only one assertion in a SAML Response, so get the first one assertion = assertions.get(0); return assertion.getSubject().getNameID().getValue(); } return null; } /** * Read the session index from a Response * * @param response SAML Response * @return Session Index value contained in the Response */ private String getSessionIndexFromResponse(Response response) { List<Assertion> assertions = response.getAssertions(); String sessionIndex = null; if (assertions != null && assertions.size() > 0) { // There can be only one assertion in a SAML Response, so get the first one List<AuthnStatement> authnStatements = assertions.get(0).getAuthnStatements(); if (authnStatements != null && authnStatements.size() > 0) { // There can be only one authentication stmt inside the SAML assertion of a SAML Response AuthnStatement authStmt = authnStatements.get(0); sessionIndex = authStmt.getSessionIndex(); } } return sessionIndex; } public boolean reAuthenticateOnSessionExpire(Object object) throws AuthenticationException { return false; } @Override public void authenticateWithCookie(HttpServletRequest request) throws AuthenticationException { // TODO Auto-generated method stub } @Override public String doAuthentication(Object credentials, boolean isRememberMe, ServiceClient client, HttpServletRequest request) throws AuthenticationException { // TODO Auto-generated method stub return null; } @Override public void handleRememberMe(Map transportHeaders, HttpServletRequest httpServletRequest) throws AuthenticationException { // TODO Auto-generated method stub } }