/*
* 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.sso.saml.ui;
import org.apache.axis2.context.ConfigurationContext;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.identity.sso.saml.stub.IdentityException;
import org.wso2.carbon.identity.sso.saml.stub.types.SAMLSSOAuthnReqDTO;
import org.wso2.carbon.identity.sso.saml.stub.types.SAMLSSOReqValidationResponseDTO;
import org.wso2.carbon.identity.sso.saml.stub.types.SAMLSSORespDTO;
import org.wso2.carbon.identity.sso.saml.ui.client.SAMLSSOServiceClient;
import org.wso2.carbon.identity.sso.saml.ui.logout.LogoutRequestSender;
import org.wso2.carbon.identity.sso.saml.ui.session.mgt.FESessionBean;
import org.wso2.carbon.identity.sso.saml.ui.session.mgt.FESessionManager;
import org.wso2.carbon.ui.CarbonUIUtil;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class SAMLSSOProvider extends HttpServlet {
/**
* session timeout happens in 10 hours
*/
private static final int SSO_SESSION_EXPIRE = 36000;
@Override
protected void doGet(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws ServletException, IOException {
doPost(httpServletRequest, httpServletResponse);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter(SAMLSSOProviderConstants.USERNAME);
String password = request.getParameter(SAMLSSOProviderConstants.PASSWORD);
HttpSession session = request.getSession();
// Use sessionID as the tokenID, if cookie is not set.
String ssoTokenID = session.getId();
Cookie tokenCookie = getSSOTokenCookie(request);
if (tokenCookie != null) {
ssoTokenID = tokenCookie.getValue();
}
String serverURL = CarbonUIUtil.getServerURL(session.getServletContext(), session);
ConfigurationContext configContext = (ConfigurationContext) session.getServletContext()
.getAttribute(CarbonConstants.CONFIGURATION_CONTEXT);
SAMLSSOServiceClient ssoServiceClient = new SAMLSSOServiceClient(serverURL, configContext);
try {
if (username == null && password == null) { // First request without credentials. Should redirect to login page
String samlRequest = request.getParameter("SAMLRequest");
String authMode = SAMLSSOProviderConstants.AuthnModes.USERNAME_PASSWORD;
if(request.getParameter("authMode") != null &&
SAMLSSOProviderConstants.AuthnModes.OPENID.equals(request.getParameter("authMode"))){
authMode = SAMLSSOProviderConstants.AuthnModes.OPENID;
}
String relayState = request.getParameter(SAMLSSOProviderConstants.RELAY_STATE);
if (samlRequest != null) { // this is a login request
handleSAMLRequest(request, response,
session, ssoTokenID, ssoServiceClient, samlRequest, relayState, authMode);
} else { // Non-SAML request are assumed to be logout requests
handleLogout(request, response);
}
} else { // Request coming from login page with username and password
handleRequestFromLoginPage(request, response,
username, password, ssoTokenID,
ssoServiceClient);
}
} catch (IdentityException e) { // in case of an error, redirect them to notifications page with an error msg.
FESessionManager sessionManager = FESessionManager.getInstance();
String authSessionID = sessionManager.addNewSession(new FESessionBean("Server Error", "Please try again later."));
response.sendRedirect(getAdminConsoleURL(request) + "sso-saml/notification_page.jsp?" +
SAMLSSOProviderConstants.FE_SESSION_KEY + "=" + authSessionID);
}
}
private void handleRequestFromLoginPage(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
String username, String password,
String ssoTokenID,
SAMLSSOServiceClient ssoServiceClient)
throws IdentityException, IOException {
FESessionManager sessionManager = FESessionManager.getInstance();
String authSessionID = httpServletRequest.getParameter(SAMLSSOProviderConstants.FE_SESSION_KEY);
FESessionBean sessionBean = sessionManager.getFESessionBean(authSessionID);
SAMLSSOReqValidationResponseDTO validationResponseDTO = null;
if (sessionBean != null) {
if (sessionBean.getSessionBean() instanceof SAMLSSOReqValidationResponseDTO) {
validationResponseDTO = (SAMLSSOReqValidationResponseDTO) sessionBean.getSessionBean();
}
}
else{
String errorSessionId = sessionManager.addNewSession(new FESessionBean("This authenticated session is expired.", "Please sign-in again."));
httpServletResponse.sendRedirect(getAdminConsoleURL(httpServletRequest) + "sso-saml/notification_page.jsp?" +
SAMLSSOProviderConstants.FE_SESSION_KEY + "=" + errorSessionId);
return;
}
// Create SAMLSSOAuthnReqDTO using a SAMLSSOReqValidationResponseDTO
SAMLSSOAuthnReqDTO authnReqDTO = new SAMLSSOAuthnReqDTO();
authnReqDTO.setAssertionConsumerURL(validationResponseDTO.getAssertionConsumerURL());
authnReqDTO.setId(validationResponseDTO.getId());
authnReqDTO.setIssuer(validationResponseDTO.getIssuer());
authnReqDTO.setPassword(password);
authnReqDTO.setUsername(username);
authnReqDTO.setSubject(validationResponseDTO.getSubject());
authnReqDTO.setRpSessionId(validationResponseDTO.getRpSessionId());
authnReqDTO.setAssertionString(validationResponseDTO.getAssertionString());
// authenticate the user
SAMLSSORespDTO authRespDTO = ssoServiceClient.authenticate(authnReqDTO, ssoTokenID);
if (authRespDTO.getSessionEstablished()) { // authentication is SUCCESSFUL
storeSSOTokenCookie(ssoTokenID, httpServletRequest, httpServletResponse);
String respSessionAuthID = sessionManager.addNewSession(new FESessionBean(authRespDTO, sessionBean.getRelayState()));
sessionManager.removeSession(authSessionID); // remove the SAMLSSORespDTO
httpServletResponse.sendRedirect(getAdminConsoleURL(httpServletRequest) + "sso-saml/redirect_ajaxprocessor.jsp?" + SAMLSSOProviderConstants.FE_SESSION_KEY + "=" + respSessionAuthID);
} else { // authentication FAILURE
validationResponseDTO.setValid(false);
httpServletResponse.sendRedirect(calculateLoginPage(
getAdminConsoleURL(httpServletRequest), authRespDTO.getLoginPageURL())+ "?" + SAMLSSOProviderConstants.FE_SESSION_KEY + "=" + authSessionID);
}
}
private void handleLogout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
throws IdentityException, IOException {
FESessionManager sessionManager = FESessionManager.getInstance();
String sessionId = sessionManager.addNewSession(new FESessionBean("You have been successfully signed out."
, "All the other authenticated sessions are terminated."));
httpServletResponse.sendRedirect(getAdminConsoleURL(httpServletRequest) + "sso-saml/notification_page.jsp?" +
SAMLSSOProviderConstants.FE_SESSION_KEY + "=" + sessionId);
}
private void handleSAMLRequest(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, HttpSession session,
String ssoTokenID, SAMLSSOServiceClient ssoServiceClient,
String samlRequest, String relayState, String authMode)
throws IdentityException, IOException {
String rpSessionId = httpServletRequest.getParameter(MultitenantConstants.SSO_AUTH_SESSION_ID);
SAMLSSOReqValidationResponseDTO signInRespDTO = ssoServiceClient.validate(samlRequest, ssoTokenID, rpSessionId, authMode);
FESessionManager sessionManager = FESessionManager.getInstance();
// If it is a login request.
if (!signInRespDTO.getLogOutReq()) {
// an authentication context has not been already established, redirect user to a login page.
if (signInRespDTO.getValid() && signInRespDTO.getResponse() == null) {
String sessionID = sessionManager.addNewSession(new FESessionBean(signInRespDTO, relayState));
httpServletResponse.sendRedirect(calculateLoginPage(
getAdminConsoleURL(httpServletRequest), signInRespDTO.getLoginPageURL())+ "?" +
SAMLSSOProviderConstants.FE_SESSION_KEY + "=" + sessionID);
// an auth. context has been already established. So redirect users back to ACS.
} else if (signInRespDTO.getResponse() != null) {
String sessionID = sessionManager.addNewSession(new FESessionBean(signInRespDTO, relayState));
if(SAMLSSOProviderConstants.AuthnModes.OPENID.equals(authMode)){
storeSSOTokenCookie(ssoTokenID, httpServletRequest, httpServletResponse);
}
httpServletResponse.sendRedirect(getAdminConsoleURL(httpServletRequest) + "sso-saml/redirect_ajaxprocessor.jsp?" + SAMLSSOProviderConstants.FE_SESSION_KEY + "=" + sessionID);
}
} else { // in case of a logout request
String sessionID = sessionManager.addNewSession(new FESessionBean(signInRespDTO, relayState));
LogoutRequestSender.getInstance().sendLogoutRequests(signInRespDTO.getLogoutRespDTO());
httpServletResponse.sendRedirect(getAdminConsoleURL(httpServletRequest) + "sso-saml/redirect_ajaxprocessor.jsp?" + SAMLSSOProviderConstants.FE_SESSION_KEY + "=" + sessionID);
}
}
private String getAdminConsoleURL(HttpServletRequest request) {
String url = CarbonUIUtil.getAdminConsoleURL(request);
if (url.indexOf("/samlsso") != -1) {
url = url.replace("/samlsso", "");
}
return url;
}
private Cookie getSSOTokenCookie(HttpServletRequest req) {
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(SAMLSSOProviderConstants.SSO_TOKEN_ID)) {
return cookie;
}
}
}
return null;
}
private void storeSSOTokenCookie(String ssoTokenID, HttpServletRequest req,
HttpServletResponse resp) {
Cookie ssoTokenCookie = getSSOTokenCookie(req);
if (ssoTokenCookie == null) {
ssoTokenCookie = new Cookie(SAMLSSOProviderConstants.SSO_TOKEN_ID, ssoTokenID);
}
ssoTokenCookie.setMaxAge(SSO_SESSION_EXPIRE);
resp.addCookie(ssoTokenCookie);
}
private String calculateLoginPage(String adminConsoleURL, String customLoginPage){
if(customLoginPage != null){
return adminConsoleURL + customLoginPage.trim();
}
else{
return adminConsoleURL + "sso-saml/login.jsp";
}
}
}