private void handleLogoutResponseFromFramework( HttpServletRequest request, HttpServletResponse response, SAMLSSOSessionDTO sessionDTO) throws ServletException, IOException, IdentityException { SAMLSSOReqValidationResponseDTO validationResponseDTO = sessionDTO.getValidationRespDTO(); if (validationResponseDTO != null) { // sending LogoutRequests to other session participants LogoutRequestSender.getInstance() .sendLogoutRequests(validationResponseDTO.getLogoutRespDTO()); SAMLSSOUtil.removeSession(sessionDTO.getSessionId(), validationResponseDTO.getIssuer()); removeSessionDataFromCache( CharacterEncoder.getSafeText(request.getParameter("sessionDataKey"))); if (validationResponseDTO.isIdPInitSLO()) { // redirecting to the return URL or IS logout page response.sendRedirect(validationResponseDTO.getReturnToURL()); } else { // sending LogoutResponse back to the initiator sendResponse( request, response, sessionDTO.getRelayState(), validationResponseDTO.getLogoutResponse(), validationResponseDTO.getAssertionConsumerURL(), validationResponseDTO.getSubject(), null, sessionDTO.getTenantDomain()); } } else { try { samlSsoService.doSingleLogout(request.getSession().getId()); } catch (IdentityException e) { log.error("Error when processing the logout request!", e); } String errorResp = SAMLSSOUtil.buildErrorResponse( SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR, "Invalid request", sessionDTO.getAssertionConsumerURL()); sendNotification( errorResp, SAMLSSOConstants.Notification.INVALID_MESSAGE_STATUS, SAMLSSOConstants.Notification.INVALID_MESSAGE_MESSAGE, sessionDTO.getAssertionConsumerURL(), request, response); } }
/** * @param req * @param authnReqDTO */ private void populateAuthnReqDTO( HttpServletRequest req, SAMLSSOAuthnReqDTO authnReqDTO, SAMLSSOSessionDTO sessionDTO, AuthenticationResult authResult) throws UserStoreException, IdentityException { authnReqDTO.setAssertionConsumerURL(sessionDTO.getAssertionConsumerURL()); authnReqDTO.setId(sessionDTO.getRequestID()); authnReqDTO.setIssuer(sessionDTO.getIssuer()); authnReqDTO.setSubject(sessionDTO.getSubject()); authnReqDTO.setRpSessionId(sessionDTO.getRelyingPartySessionId()); authnReqDTO.setRequestMessageString(sessionDTO.getRequestMessageString()); authnReqDTO.setQueryString(sessionDTO.getHttpQueryString()); authnReqDTO.setDestination(sessionDTO.getDestination()); authnReqDTO.setUser(authResult.getSubject()); authnReqDTO.setIdPInitSSOEnabled(sessionDTO.isIdPInitSSO()); authnReqDTO.setClaimMapping(authResult.getClaimMapping()); authnReqDTO.setTenantDomain(sessionDTO.getTenantDomain()); authnReqDTO.setIdPInitSLOEnabled(sessionDTO.isIdPInitSLO()); SAMLSSOUtil.setIsSaaSApplication(authResult.isSaaSApp()); SAMLSSOUtil.setUserTenantDomain(authResult.getSubject().getTenantDomain()); }
/** * Sends the user for authentication to the login page * * @param req * @param resp * @param signInRespDTO * @param relayState * @throws ServletException * @throws IOException */ private void sendToFrameworkForAuthentication( HttpServletRequest req, HttpServletResponse resp, SAMLSSOReqValidationResponseDTO signInRespDTO, String relayState, boolean isPost) throws ServletException, IOException, UserStoreException, IdentityException { SAMLSSOSessionDTO sessionDTO = new SAMLSSOSessionDTO(); sessionDTO.setHttpQueryString(req.getQueryString()); sessionDTO.setDestination(signInRespDTO.getDestination()); sessionDTO.setRelayState(relayState); sessionDTO.setRequestMessageString(signInRespDTO.getRequestMessageString()); sessionDTO.setIssuer(signInRespDTO.getIssuer()); sessionDTO.setRequestID(signInRespDTO.getId()); sessionDTO.setSubject(signInRespDTO.getSubject()); sessionDTO.setRelyingPartySessionId(signInRespDTO.getRpSessionId()); sessionDTO.setAssertionConsumerURL(signInRespDTO.getAssertionConsumerURL()); sessionDTO.setTenantDomain(SAMLSSOUtil.getTenantDomainFromThreadLocal()); if (sessionDTO.getTenantDomain() == null) { String[] splitIssuer = sessionDTO.getIssuer().split("@"); if (splitIssuer != null && splitIssuer.length == 2 && !splitIssuer[0].trim().isEmpty() && !splitIssuer[1].trim().isEmpty()) { sessionDTO.setTenantDomain(splitIssuer[1]); } else { sessionDTO.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); } } SAMLSSOUtil.setTenantDomainInThreadLocal(sessionDTO.getTenantDomain()); sessionDTO.setForceAuth(signInRespDTO.isForceAuthn()); sessionDTO.setPassiveAuth(signInRespDTO.isPassive()); sessionDTO.setValidationRespDTO(signInRespDTO); sessionDTO.setIdPInitSSO(signInRespDTO.isIdPInitSSO()); String sessionDataKey = UUIDGenerator.generateUUID(); addSessionDataToCache( sessionDataKey, sessionDTO, IdPManagementUtil.getIdleSessionTimeOut(sessionDTO.getTenantDomain())); String commonAuthURL = CarbonUIUtil.getAdminConsoleURL(req); commonAuthURL = commonAuthURL.replace( FrameworkConstants.RequestType.CLAIM_TYPE_SAML_SSO + "/" + FrameworkConstants.CARBON + "/", FrameworkConstants.COMMONAUTH); String selfPath = URLEncoder.encode("/" + FrameworkConstants.RequestType.CLAIM_TYPE_SAML_SSO, "UTF-8"); // Setting authentication request context AuthenticationRequest authenticationRequest = new AuthenticationRequest(); // Adding query parameters authenticationRequest.appendRequestQueryParams(req.getParameterMap()); for (Enumeration headerNames = req.getHeaderNames(); headerNames.hasMoreElements(); ) { String headerName = headerNames.nextElement().toString(); authenticationRequest.addHeader(headerName, req.getHeader(headerName)); } authenticationRequest.setRelyingParty(signInRespDTO.getIssuer()); authenticationRequest.setCommonAuthCallerPath(selfPath); authenticationRequest.setForceAuth(signInRespDTO.isForceAuthn()); if (!authenticationRequest.getForceAuth() && authenticationRequest.getRequestQueryParam("forceAuth") != null) { String[] forceAuth = authenticationRequest.getRequestQueryParam("forceAuth"); if (!forceAuth[0].trim().isEmpty() && Boolean.parseBoolean(forceAuth[0].trim())) { authenticationRequest.setForceAuth(Boolean.parseBoolean(forceAuth[0].trim())); } } authenticationRequest.setPassiveAuth(signInRespDTO.isPassive()); authenticationRequest.setTenantDomain(sessionDTO.getTenantDomain()); authenticationRequest.setPost(isPost); // Creating cache entry and adding entry to the cache before calling to commonauth AuthenticationRequestCacheEntry authRequest = new AuthenticationRequestCacheEntry(authenticationRequest); FrameworkUtils.addAuthenticationRequestToCache( sessionDataKey, authRequest, IdPManagementUtil.getIdleSessionTimeOut(sessionDTO.getTenantDomain())); StringBuilder queryStringBuilder = new StringBuilder(); queryStringBuilder .append(commonAuthURL) .append("?") .append(SAMLSSOConstants.SESSION_DATA_KEY) .append("=") .append(sessionDataKey) .append("&") .append(FrameworkConstants.RequestParams.TYPE) .append("=") .append(FrameworkConstants.RequestType.CLAIM_TYPE_SAML_SSO); FrameworkUtils.setRequestPathCredentials(req); resp.sendRedirect(queryStringBuilder.toString()); }
/** * This method handles authentication and sends authentication Response message back to the * Service Provider after successful authentication. In case of authentication failure the user is * prompted back for authentication. * * @param req * @param resp * @param sessionId * @throws IdentityException * @throws IOException * @throws ServletException */ private void handleAuthenticationReponseFromFramework( HttpServletRequest req, HttpServletResponse resp, String sessionId, SAMLSSOSessionDTO sessionDTO) throws UserStoreException, IdentityException, IOException, ServletException { String sessionDataKey = CharacterEncoder.getSafeText(req.getParameter("sessionDataKey")); AuthenticationResult authResult = getAuthenticationResultFromCache(sessionDataKey); if (log.isDebugEnabled() && authResult == null) { log.debug("Session data is not found for key : " + sessionDataKey); } SAMLSSOReqValidationResponseDTO reqValidationDTO = sessionDTO.getValidationRespDTO(); SAMLSSOAuthnReqDTO authnReqDTO = new SAMLSSOAuthnReqDTO(); if (authResult == null || !authResult.isAuthenticated()) { if (log.isDebugEnabled() && authResult != null) { log.debug("Unauthenticated User"); } if (reqValidationDTO.isPassive()) { // if passive List<String> statusCodes = new ArrayList<String>(); statusCodes.add(SAMLSSOConstants.StatusCodes.NO_PASSIVE); statusCodes.add(SAMLSSOConstants.StatusCodes.IDENTITY_PROVIDER_ERROR); String destination = reqValidationDTO.getDestination(); reqValidationDTO.setResponse( SAMLSSOUtil.buildErrorResponse( reqValidationDTO.getId(), statusCodes, "Cannot authenticate Subject in Passive Mode", destination)); sendResponse( req, resp, sessionDTO.getRelayState(), reqValidationDTO.getResponse(), reqValidationDTO.getAssertionConsumerURL(), reqValidationDTO.getSubject(), null, sessionDTO.getTenantDomain()); return; } else { // if forceAuthn or normal flow // TODO send a saml response with a status message. if (!authResult.isAuthenticated()) { String destination = reqValidationDTO.getDestination(); String errorResp = SAMLSSOUtil.buildErrorResponse( SAMLSSOConstants.StatusCodes.AUTHN_FAILURE, "User authentication failed", destination); sendNotification( errorResp, SAMLSSOConstants.Notification.EXCEPTION_STATUS, SAMLSSOConstants.Notification.EXCEPTION_MESSAGE, reqValidationDTO.getAssertionConsumerURL(), req, resp); return; } else { throw new IdentityException("Session data is not found for authenticated user"); } } } else { populateAuthnReqDTO(req, authnReqDTO, sessionDTO, authResult); req.setAttribute(SAMLSSOConstants.AUTHENTICATION_RESULT, authResult); String relayState = null; if (req.getParameter(SAMLSSOConstants.RELAY_STATE) != null) { relayState = req.getParameter(SAMLSSOConstants.RELAY_STATE); } else { relayState = sessionDTO.getRelayState(); } startTenantFlow(authnReqDTO.getTenantDomain()); if (sessionId == null) { sessionId = UUIDGenerator.generateUUID(); } SAMLSSOService samlSSOService = new SAMLSSOService(); SAMLSSORespDTO authRespDTO = samlSSOService.authenticate( authnReqDTO, sessionId, authResult.isAuthenticated(), authResult.getAuthenticatedAuthenticators(), SAMLSSOConstants.AuthnModes.USERNAME_PASSWORD); if (authRespDTO.isSessionEstablished()) { // authenticated storeTokenIdCookie(sessionId, req, resp, authnReqDTO.getTenantDomain()); removeSessionDataFromCache( CharacterEncoder.getSafeText(req.getParameter("sessionDataKey"))); sendResponse( req, resp, relayState, authRespDTO.getRespString(), authRespDTO.getAssertionConsumerURL(), authRespDTO.getSubject().getAuthenticatedSubjectIdentifier(), authResult.getAuthenticatedIdPs(), sessionDTO.getTenantDomain()); } else { // authentication FAILURE String errorResp = authRespDTO.getRespString(); sendNotification( errorResp, SAMLSSOConstants.Notification.EXCEPTION_STATUS, SAMLSSOConstants.Notification.EXCEPTION_MESSAGE, authRespDTO.getAssertionConsumerURL(), req, resp); } } }
/** * All requests are handled by this handleRequest method. In case of SAMLRequest the user will be * redirected to commonAuth servlet for authentication. Based on successful authentication of the * user a SAMLResponse is sent back to service provider. In case of logout requests, the IDP will * send logout requests to the other session participants and then send the logout response back * to the initiator. * * @param req * @param resp * @throws ServletException * @throws IOException */ private void handleRequest(HttpServletRequest req, HttpServletResponse resp, boolean isPost) throws ServletException, IOException { String sessionId = null; Cookie ssoTokenIdCookie = getTokenIdCookie(req); if (ssoTokenIdCookie != null) { sessionId = ssoTokenIdCookie.getValue(); } String queryString = req.getQueryString(); if (log.isDebugEnabled()) { log.debug("Query string : " + queryString); } // if an openid authentication or password authentication String authMode = CharacterEncoder.getSafeText(req.getParameter("authMode")); if (!SAMLSSOConstants.AuthnModes.OPENID.equals(authMode)) { authMode = SAMLSSOConstants.AuthnModes.USERNAME_PASSWORD; } String relayState = CharacterEncoder.getSafeText(req.getParameter(SAMLSSOConstants.RELAY_STATE)); String spEntityID = CharacterEncoder.getSafeText( req.getParameter(SAMLSSOConstants.QueryParameter.SP_ENTITY_ID.toString())); String samlRequest = CharacterEncoder.getSafeText(req.getParameter("SAMLRequest")); String sessionDataKey = CharacterEncoder.getSafeText(req.getParameter("sessionDataKey")); String slo = CharacterEncoder.getSafeText( req.getParameter(SAMLSSOConstants.QueryParameter.SLO.toString())); boolean isExpFired = false; try { String tenantDomain = CharacterEncoder.getSafeText(req.getParameter("tenantDomain")); SAMLSSOUtil.setTenantDomainInThreadLocal(tenantDomain); if (sessionDataKey != null) { // Response from common authentication framework. SAMLSSOSessionDTO sessionDTO = getSessionDataFromCache(sessionDataKey); if (sessionDTO != null) { SAMLSSOUtil.setTenantDomainInThreadLocal(sessionDTO.getTenantDomain()); if (sessionDTO.isInvalidLogout()) { log.warn("Redirecting to default logout page due to an invalid logout request"); String serverUrl = CarbonUIUtil.getAdminConsoleURL(req); resp.sendRedirect( serverUrl.replace( SAMLSSOConstants.SAML_ENDPOINT, SAMLSSOConstants.DEFAULT_LOGOUT_LOCATION)); } else if (sessionDTO.isLogoutReq()) { handleLogoutResponseFromFramework(req, resp, sessionDTO); } else { handleAuthenticationReponseFromFramework(req, resp, sessionId, sessionDTO); } removeAuthenticationResultFromCache(sessionDataKey); } else { log.error("Failed to retrieve sessionDTO from the cache for key " + sessionDataKey); String errorResp = SAMLSSOUtil.buildErrorResponse( SAMLSSOConstants.StatusCodes.IDENTITY_PROVIDER_ERROR, SAMLSSOConstants.Notification.EXCEPTION_STATUS, null); sendNotification( errorResp, SAMLSSOConstants.Notification.EXCEPTION_STATUS, SAMLSSOConstants.Notification.EXCEPTION_MESSAGE, null, req, resp); return; } } else if (spEntityID != null || slo != null) { // idp initiated SSO/SLO handleIdPInitSSO( req, resp, relayState, queryString, authMode, sessionId, isPost, (slo != null)); } else if (samlRequest != null) { // SAMLRequest received. SP initiated SSO handleSPInitSSO( req, resp, queryString, relayState, authMode, samlRequest, sessionId, isPost); } else { log.debug("Invalid request message or single logout message "); if (sessionId == null) { String errorResp = SAMLSSOUtil.buildErrorResponse( SAMLSSOConstants.StatusCodes.REQUESTOR_ERROR, "Invalid request message", null); sendNotification( errorResp, SAMLSSOConstants.Notification.INVALID_MESSAGE_STATUS, SAMLSSOConstants.Notification.INVALID_MESSAGE_MESSAGE, null, req, resp); } else { // Non-SAML request are assumed to be logout requests sendToFrameworkForLogout(req, resp, null, null, sessionId, true, false); } } } catch (UserStoreException e) { if (log.isDebugEnabled()) { log.debug("Error occurred while handling SAML2 SSO request", e); } String errorResp = null; try { errorResp = SAMLSSOUtil.buildErrorResponse( SAMLSSOConstants.StatusCodes.IDENTITY_PROVIDER_ERROR, "Error occurred while handling SAML2 SSO request", null); } catch (IdentityException e1) { log.error("Error while building SAML response", e1); } sendNotification( errorResp, SAMLSSOConstants.Notification.EXCEPTION_STATUS, SAMLSSOConstants.Notification.EXCEPTION_MESSAGE, null, req, resp); } catch (IdentityException e) { log.error("Error when processing the authentication request!", e); String errorResp = null; try { errorResp = SAMLSSOUtil.buildErrorResponse( SAMLSSOConstants.StatusCodes.IDENTITY_PROVIDER_ERROR, "Error when processing the authentication request", null); } catch (IdentityException e1) { log.error("Error while building SAML response", e1); } sendNotification( errorResp, SAMLSSOConstants.Notification.EXCEPTION_STATUS, SAMLSSOConstants.Notification.EXCEPTION_MESSAGE, null, req, resp); } }