Package org.picketlink.identity.federation.web.handlers.saml2

Source Code of org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler$IDPLogOutHandler

/*
* 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.web.handlers.saml2;

import org.jboss.security.audit.AuditLevel;
import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request;
import org.picketlink.identity.federation.api.saml.v2.response.SAML2Response;
import org.picketlink.identity.federation.core.audit.PicketLinkAuditEvent;
import org.picketlink.identity.federation.core.audit.PicketLinkAuditEventType;
import org.picketlink.identity.federation.core.audit.PicketLinkAuditHelper;
import org.picketlink.identity.federation.core.config.SPType;
import org.picketlink.identity.federation.core.exceptions.ConfigurationException;
import org.picketlink.identity.federation.core.exceptions.ParsingException;
import org.picketlink.identity.federation.core.exceptions.ProcessingException;
import org.picketlink.identity.federation.core.saml.v2.common.IDGenerator;
import org.picketlink.identity.federation.core.saml.v2.common.SAMLProtocolContext;
import org.picketlink.identity.federation.core.saml.v2.constants.JBossSAMLURIConstants;
import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler;
import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerRequest;
import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerRequest.GENERATE_REQUEST_TYPE;
import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerResponse;
import org.picketlink.identity.federation.core.saml.v2.util.XMLTimeUtil;
import org.picketlink.identity.federation.core.sts.PicketLinkCoreSTS;
import org.picketlink.identity.federation.core.wstrust.plugins.saml.SAMLUtil;
import org.picketlink.identity.federation.saml.v2.SAML2Object;
import org.picketlink.identity.federation.saml.v2.assertion.AssertionType;
import org.picketlink.identity.federation.saml.v2.assertion.AuthnStatementType;
import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
import org.picketlink.identity.federation.saml.v2.assertion.StatementAbstractType;
import org.picketlink.identity.federation.saml.v2.protocol.*;
import org.picketlink.identity.federation.web.constants.GeneralConstants;
import org.picketlink.identity.federation.web.core.HTTPContext;
import org.picketlink.identity.federation.web.core.IdentityServer;
import org.picketlink.identity.federation.web.util.RedirectBindingUtil;
import org.w3c.dom.Document;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.net.URI;
import java.security.Principal;
import java.util.Map;
import java.util.Set;

/**
* SAML2 LogOut Profile
*
* @author Anil.Saldhana@redhat.com
* @since Sep 17, 2009
*/
public class SAML2LogOutHandler extends BaseSAML2Handler {

    private final IDPLogOutHandler idp = new IDPLogOutHandler();

    private final SPLogOutHandler sp = new SPLogOutHandler();

    /**
     * @see SAML2Handler#generateSAMLRequest(SAML2HandlerRequest, SAML2HandlerResponse)
     */
    public void generateSAMLRequest(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
        if (request.getTypeOfRequestToBeGenerated() == null) {
            return;
        }
        if (GENERATE_REQUEST_TYPE.LOGOUT != request.getTypeOfRequestToBeGenerated())
            return;

        if (getType() == HANDLER_TYPE.IDP) {
            idp.generateSAMLRequest(request, response);
        } else {
            sp.generateSAMLRequest(request, response);
        }
    }

    /**
     * @see SAML2Handler#handleRequestType(RequestAbstractType)
     */
    public void handleRequestType(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
        if (request.getSAML2Object() instanceof LogoutRequestType == false)
            return;

        if (getType() == HANDLER_TYPE.IDP) {
            idp.handleRequestType(request, response);
        } else {
            sp.handleRequestType(request, response);
        }
    }

    /**
     * @see SAML2Handler#handleStatusResponseType(StatusResponseType, Document resultingDocument)
     */
    public void handleStatusResponseType(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
        // we do not handle any ResponseType (authentication etc)
        if (request.getSAML2Object() instanceof ResponseType)
            return;

        if (request.getSAML2Object() instanceof StatusResponseType == false)
            return;

        if (getType() == HANDLER_TYPE.IDP) {
            idp.handleStatusResponseType(request, response);
        } else {
            sp.handleStatusResponseType(request, response);
        }
    }

    private class IDPLogOutHandler {
        public void generateSAMLRequest(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
        }

        public void handleStatusResponseType(SAML2HandlerRequest request, SAML2HandlerResponse response)
                throws ProcessingException {
            // we got a logout response from a SP
            SAML2Object samlObject = request.getSAML2Object();
            StatusResponseType statusResponseType = (StatusResponseType) samlObject;

            HTTPContext httpContext = (HTTPContext) request.getContext();
            HttpServletRequest httpRequest = httpContext.getRequest();
            HttpSession httpSession = httpRequest.getSession(false);

            String relayState = request.getRelayState();

            String decodedRelayState = relayState;
            try{
                decodedRelayState = RedirectBindingUtil.urlDecode(relayState);
            }catch(IOException ignore){
                decodedRelayState = relayState;
            }

            ServletContext servletCtx = httpContext.getServletContext();
            IdentityServer server = (IdentityServer) servletCtx.getAttribute("IDENTITY_SERVER");

            if (server == null)
                throw logger.samlHandlerIdentityServerNotFoundError();

            String sessionID = httpSession.getId();

            String statusIssuer = statusResponseType.getIssuer().getValue();
            server.stack().deRegisterTransitParticipant(sessionID, statusIssuer);

            String nextParticipant = this.getParticipant(server, sessionID, decodedRelayState);
            if (nextParticipant == null || nextParticipant.equals(decodedRelayState)) {
                // we are done with logout - First ask STS to cancel the token
                AssertionType assertion = (AssertionType) httpSession.getAttribute(GeneralConstants.ASSERTION);
                if (assertion != null) {
                    PicketLinkCoreSTS sts = PicketLinkCoreSTS.instance();
                    SAMLProtocolContext samlProtocolContext = new SAMLProtocolContext();
                    samlProtocolContext.setIssuedAssertion(assertion);
                    sts.cancelToken(samlProtocolContext);
                    httpSession.removeAttribute(GeneralConstants.ASSERTION);
                }

                // TODO: check the in transit map for partial logouts

                try {
                    generateSuccessStatusResponseType(statusResponseType.getInResponseTo(), request, response, relayState);

                    boolean isPost = isPostBindingForResponse(server, relayState, request);
                    response.setPostBindingForResponse(isPost);
                } catch (Exception e) {
                    throw logger.processingError(e);
                }
                Map<String, Object> requestOptions = request.getOptions();
                PicketLinkAuditHelper auditHelper = (PicketLinkAuditHelper) requestOptions.get(GeneralConstants.AUDIT_HELPER);
                if (auditHelper != null) {
                    PicketLinkAuditEvent auditEvent = new PicketLinkAuditEvent(AuditLevel.INFO);
                    auditEvent.setWhoIsAuditing((String) requestOptions.get(GeneralConstants.CONTEXT_PATH));
                    auditEvent.setType(PicketLinkAuditEventType.INVALIDATE_HTTP_SESSION);
                    auditEvent.setHttpSessionID(httpSession.getId());
                    auditHelper.audit(auditEvent);
                }
                httpSession.invalidate(); // We are done with the logout interaction
            } else {
                // Put the participant in transit mode
                server.stack().registerTransitParticipant(sessionID, nextParticipant);

                boolean isPost = isPostBindingForResponse(server, nextParticipant, request);
                response.setPostBindingForResponse(isPost);

                // send logout request to participant with relaystate to orig
                response.setRelayState(relayState);

                response.setDestination(nextParticipant);

                SAML2Request saml2Request = new SAML2Request();
                try {
                    LogoutRequestType lort = saml2Request.createLogoutRequest(request.getIssuer().getValue());
                    response.setResultingDocument(saml2Request.convert(lort));
                    response.setSendRequest(true);
                } catch (Exception e) {
                    throw logger.processingError(e);
                }
            }
        }

        public void handleRequestType(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
            HTTPContext httpContext = (HTTPContext) request.getContext();
            HttpServletRequest httpServletRequest = httpContext.getRequest();
            HttpSession session = httpServletRequest.getSession(false);
            String sessionID = session.getId();

            String relayState = httpContext.getRequest().getParameter(GeneralConstants.RELAY_STATE);

            LogoutRequestType logOutRequest = (LogoutRequestType) request.getSAML2Object();
            String issuer = logOutRequest.getIssuer().getValue();
            try {
                SAML2Request saml2Request = new SAML2Request();

                ServletContext servletCtx = httpContext.getServletContext();
                IdentityServer server = (IdentityServer) servletCtx.getAttribute(GeneralConstants.IDENTITY_SERVER);

                if (server == null)
                    throw logger.samlHandlerIdentityServerNotFoundError();

                String originalIssuer = (relayState == null) ? issuer : relayState;

                String participant = this.getParticipant(server, sessionID, originalIssuer);

                if (participant == null || participant.equals(originalIssuer)) {
                    // All log out is done
                    session.invalidate();
                    server.stack().pop(sessionID);

                    generateSuccessStatusResponseType(logOutRequest.getID(), request, response, originalIssuer);

                    boolean isPost = isPostBindingForResponse(server, participant, request);
                    response.setPostBindingForResponse(isPost);

                    response.setSendRequest(false);
                } else {
                    // Put the participant in transit mode
                    server.stack().registerTransitParticipant(sessionID, participant);

                    if (relayState == null) {
                         relayState = originalIssuer;
                    }

                    // send logout request to participant with relaystate to orig
                    response.setRelayState(originalIssuer);

                    response.setDestination(participant);

                    boolean isPost = isPostBindingForResponse(server, participant, request);
                    response.setPostBindingForResponse(isPost);

                    LogoutRequestType lort = saml2Request.createLogoutRequest(request.getIssuer().getValue());

                    Principal userPrincipal = httpServletRequest.getUserPrincipal();
                    if (userPrincipal == null) {
                        throw logger.samlHandlerPrincipalNotFoundError();
                    }
                    NameIDType nameID = new NameIDType();
                    nameID.setValue(userPrincipal.getName());
                    lort.setNameID(nameID);

                    long assertionValidity = PicketLinkCoreSTS.instance().getConfiguration().getIssuedTokenTimeout();

                    lort.setNotOnOrAfter(XMLTimeUtil.add(lort.getIssueInstant(), assertionValidity));
                    lort.setDestination(URI.create(participant));

                    response.setResultingDocument(saml2Request.convert(lort));
                    response.setSendRequest(true);
                }
            } catch (ParserConfigurationException pe) {
                throw logger.processingError(pe);
            } catch (ConfigurationException pe) {
                throw logger.processingError(pe);
            } catch (ParsingException e) {
                throw logger.processingError(e);
            }

            return;
        }

        private void generateSuccessStatusResponseType(String logOutRequestID, SAML2HandlerRequest request,
                SAML2HandlerResponse response, String originalIssuer) throws ConfigurationException,
                ParserConfigurationException, ProcessingException {

            logger.trace("Generating Success Status Response for " + originalIssuer);

            StatusResponseType statusResponse = new StatusResponseType(IDGenerator.create("ID_"), XMLTimeUtil.getIssueInstant());

            // Status
            StatusType statusType = new StatusType();
            StatusCodeType statusCodeType = new StatusCodeType();
            statusCodeType.setValue(URI.create(JBossSAMLURIConstants.STATUS_SUCCESS.get()));
            statusType.setStatusCode(statusCodeType);

            statusResponse.setStatus(statusType);

            statusResponse.setInResponseTo(logOutRequestID);

            statusResponse.setIssuer(request.getIssuer());

            try {
                SAML2Response saml2Response = new SAML2Response();
                response.setResultingDocument(saml2Response.convert(statusResponse));
            } catch (ParsingException je) {
                throw logger.processingError(je);
            }

            response.setDestination(originalIssuer);
        }

        private String getParticipant(IdentityServer server, String sessionID, String originalRequestor) {
            int participants = server.stack().getParticipants(sessionID);

            String participant = originalRequestor;
            // Get a participant who is not equal to the original issuer of the logout request
            if (participants > 0) {
                do {
                    participant = server.stack().pop(sessionID);
                    --participants;
                } while (participants > 0 && participant.equals(originalRequestor));
            }

            return participant;
        }

        private boolean isPostBindingForResponse(IdentityServer server, String participant, SAML2HandlerRequest request) {
            Boolean isPostParticipant = server.stack().getBinding(participant);
            if (isPostParticipant == null)
                isPostParticipant = Boolean.TRUE;

            Boolean isStrictPostBindingForResponse = (Boolean) request.getOptions().get(
                    GeneralConstants.SAML_IDP_STRICT_POST_BINDING);
            if (isStrictPostBindingForResponse == null)
                isStrictPostBindingForResponse = Boolean.FALSE;

            return isPostParticipant || isStrictPostBindingForResponse;
        }
    }

    private class SPLogOutHandler {
        public void generateSAMLRequest(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
            // Generate the LogOut Request
            SAML2Request samlRequest = new SAML2Request();

            HTTPContext httpContext = (HTTPContext) request.getContext();
            HttpServletRequest httpRequest = httpContext.getRequest();
      Principal userPrincipal = (Principal) httpRequest.getSession()
          .getAttribute(GeneralConstants.PRINCIPAL_ID);

      if (userPrincipal == null) {
        userPrincipal = httpRequest.getUserPrincipal();
            }

            if (userPrincipal == null) {
                throw logger.samlHandlerPrincipalNotFoundError();
            }

      try {
                LogoutRequestType lot = samlRequest.createLogoutRequest(request.getIssuer().getValue());

                NameIDType nameID = new NameIDType();
                nameID.setValue(userPrincipal.getName());
                lot.setNameID(nameID);
               
                SPType spConfiguration = (SPType) getProviderconfig();
                String logoutUrl = spConfiguration.getLogoutUrl();
               
                if (logoutUrl == null) {
                    logoutUrl = spConfiguration.getIdentityURL();
                }
               
                lot.setDestination(URI.create(logoutUrl));
               
                populateSessionIndex(httpRequest, lot);
               
                response.setResultingDocument(samlRequest.convert(lot));
                response.setSendRequest(true);
            } catch (Exception e) {
                throw logger.processingError(e);
            }
        }

        private void populateSessionIndex(HttpServletRequest httpRequest, LogoutRequestType lot) throws ProcessingException,
                ConfigurationException, ParsingException {
            Document currentAssertion = (Document) httpRequest.getSession().getAttribute(GeneralConstants.ASSERTION_SESSION_ATTRIBUTE_NAME);
           
            if (currentAssertion != null) {
                AssertionType assertionType = SAMLUtil.fromElement(currentAssertion.getDocumentElement());
               
                Set<StatementAbstractType> statements = assertionType.getStatements();
               
                for (StatementAbstractType statementAbstractType : statements) {
                    if (AuthnStatementType.class.isInstance(statementAbstractType)) {
                        AuthnStatementType authnStatement = (AuthnStatementType) statementAbstractType;
                       
                        String sessionIndex = authnStatement.getSessionIndex();
                       
                        if (sessionIndex != null) {
                            lot.addSessionIndex(sessionIndex);
                        }
                       
                        break;
                    }
                }
            }
        }

        public void handleStatusResponseType(SAML2HandlerRequest request, SAML2HandlerResponse response)
                throws ProcessingException {
            // Handler a log out response from IDP
            StatusResponseType statusResponseType = (StatusResponseType) request.getSAML2Object();

            HTTPContext httpContext = (HTTPContext) request.getContext();
            HttpServletRequest servletRequest = httpContext.getRequest();
            HttpSession session = servletRequest.getSession(false);

            // TODO: Deal with partial logout report

            StatusType statusType = statusResponseType.getStatus();
            StatusCodeType statusCode = statusType.getStatusCode();
            URI statusCodeValueURI = statusCode.getValue();
            boolean success = false;
            if(statusCodeValueURI != null){
                String statusCodeValue = statusCodeValueURI.toString();
                if(JBossSAMLURIConstants.STATUS_SUCCESS.get().equals(statusCodeValue)){
                    success = true;
                }
            }
            if(success){
                // we are successfully logged out
                session.invalidate();
            } else {
                StatusCodeType secondLevelstatusCode = statusCode.getStatusCode();
                if (secondLevelstatusCode != null && secondLevelstatusCode.getValue().toString().equals(JBossSAMLURIConstants.STATUS_SUCCESS.get())) {
                    // we are successfully logged out
                    session.invalidate();
                }
            }
        }

        public void handleRequestType(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
            SAML2Object samlObject = request.getSAML2Object();
            if (samlObject instanceof LogoutRequestType == false)
                return;
            //get the configuration to handle a logout request from idp and set the correct response location
            SPType spConfiguration = (SPType) getProviderconfig();
           
            LogoutRequestType logOutRequest = (LogoutRequestType) samlObject;
            HTTPContext httpContext = (HTTPContext) request.getContext();
            HttpServletRequest servletRequest = httpContext.getRequest();
            HttpSession session = servletRequest.getSession(false);

            String relayState = servletRequest.getParameter("RelayState");

            session.invalidate(); // Invalidate the current session at the SP

            // Generate a Logout Response
            StatusResponseType statusResponse = null;
            try {
                statusResponse = new StatusResponseType(IDGenerator.create("ID_"), XMLTimeUtil.getIssueInstant());
            } catch (ConfigurationException e) {
                throw logger.processingError(e);
            }

            // Status
            StatusType statusType = new StatusType();
            StatusCodeType statusCodeType = new StatusCodeType();
            statusCodeType.setValue(URI.create(JBossSAMLURIConstants.STATUS_SUCCESS.get()));
            statusType.setStatusCode(statusCodeType);

            statusResponse.setStatus(statusType);

            statusResponse.setInResponseTo(logOutRequest.getID());

            statusResponse.setIssuer(request.getIssuer());
           
            String logoutResponseLocation = spConfiguration.getLogoutResponseLocation();
            if(logoutResponseLocation == null) {
              response.setDestination(logOutRequest.getIssuer().getValue());
            } else {
              response.setDestination(logoutResponseLocation);
            }
           
            statusResponse.setDestination(response.getDestination());

            SAML2Response saml2Response = new SAML2Response();
            try {
                response.setResultingDocument(saml2Response.convert(statusResponse));
            } catch (Exception je) {
                throw logger.processingError(je);
            }

            response.setRelayState(relayState);
            response.setSendRequest(false);
        }
    }
}
TOP

Related Classes of org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler$IDPLogOutHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.