Package org.jboss.seam.security.external.saml.sp

Source Code of org.jboss.seam.security.external.saml.sp.SamlSpSingleSignOnService

package org.jboss.seam.security.external.saml.sp;

import java.util.LinkedList;
import java.util.List;

import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBElement;
import javax.xml.datatype.DatatypeConstants;

import org.jboss.solder.logging.Logger;
import org.jboss.seam.security.external.InvalidRequestException;
import org.jboss.seam.security.external.ResponseHandler;
import org.jboss.seam.security.external.SamlNameIdImpl;
import org.jboss.seam.security.external.SamlPrincipalImpl;
import org.jboss.seam.security.external.dialogues.DialogueBean;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.AssertionType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.AttributeStatementType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.AttributeType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.AuthnStatementType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.NameIDType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.StatementAbstractType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.SubjectConfirmationDataType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.SubjectConfirmationType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.AuthnRequestType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.ResponseType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.StatusResponseType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.StatusType;
import org.jboss.seam.security.external.saml.SamlConstants;
import org.jboss.seam.security.external.saml.SamlDialogue;
import org.jboss.seam.security.external.saml.SamlEntityBean;
import org.jboss.seam.security.external.saml.SamlMessageFactory;
import org.jboss.seam.security.external.saml.SamlMessageSender;
import org.jboss.seam.security.external.saml.SamlProfile;
import org.jboss.seam.security.external.saml.SamlRedirectMessage;
import org.jboss.seam.security.external.saml.SamlServiceType;
import org.jboss.seam.security.external.saml.SamlUtils;
import org.jboss.seam.security.external.spi.SamlServiceProviderSpi;

/**
* @author Marcel Kolsteren
*/
public class SamlSpSingleSignOnService {
    @Inject
    private Logger log;

    @Inject
    private SamlSpSessions samlSpSessions;

    @Inject
    private Instance<SamlServiceProviderSpi> samlServiceProviderSpi;

    @Inject
    private Instance<SamlEntityBean> samlEntityBean;

    @Inject
    private DialogueBean dialogue;

    @Inject
    private SamlMessageSender samlMessageSender;

    @Inject
    private SamlDialogue samlDialogue;

    @Inject
    private SamlMessageFactory samlMessageFactory;

    @Inject
    private ResponseHandler responseHandler;

    public void processIDPResponse(HttpServletRequest httpRequest, HttpServletResponse httpResponse, StatusResponseType statusResponse) throws InvalidRequestException {
        SamlExternalIdentityProvider idp = (SamlExternalIdentityProvider) samlDialogue.getExternalProvider();

        StatusType status = statusResponse.getStatus();
        if (status == null) {
            throw new InvalidRequestException("Response does not contain a status");
        }

        String statusValue = status.getStatusCode().getValue();
        if (!SamlConstants.STATUS_SUCCESS.equals(statusValue)) {
            String statusCodeLevel1 = statusValue;
            String statusCodeLevel2 = null;
            if (status.getStatusCode().getStatusCode() != null) {
                statusCodeLevel2 = status.getStatusCode().getStatusCode().getValue();
            }
            samlServiceProviderSpi.get().loginFailed(statusCodeLevel1, statusCodeLevel2, responseHandler.createResponseHolder(httpResponse));
        }

        if (!(statusResponse instanceof ResponseType)) {
            throw new InvalidRequestException("Response does not have type ResponseType");
        }

        ResponseType response = (ResponseType) statusResponse;

        List<Object> assertions = response.getAssertionOrEncryptedAssertion();
        if (assertions.size() == 0) {
            throw new RuntimeException("IDP response does not contain assertions");
        }

        SamlSpSessionImpl session = createSession(response, idp);
        if (session == null) {
            throw new InvalidRequestException("Not possible to login based on the supplied assertions");
        } else {
            session.setIdentityProvider(idp);
            loginUser(httpRequest, httpResponse, session, statusResponse.getInResponseTo() == null, httpRequest.getParameter(SamlRedirectMessage.QSP_RELAY_STATE));
        }

        dialogue.setFinished(true);
    }

    private SamlSpSessionImpl createSession(ResponseType responseType, SamlExternalIdentityProvider idp) {
        SamlSpSessionImpl session = null;

        for (Object assertion : responseType.getAssertionOrEncryptedAssertion()) {
            if (assertion instanceof AssertionType) {
                SamlSpSessionImpl sessionExtractedFromAssertion = handleAssertion((AssertionType) assertion, idp);
                if (session == null) {
                    session = sessionExtractedFromAssertion;
                } else {
                    log.warn("Multiple authenticated users found in assertions. Using the first one.");
                }
            } else {
                /* assertion instanceof EncryptedElementType */
                log.warn("Encountered encrypted assertion. Skipping it because decryption is not yet supported.");
            }
        }
        return session;
    }

    private SamlSpSessionImpl handleAssertion(AssertionType assertion, SamlExternalIdentityProvider idp) {
        if (SamlUtils.hasAssertionExpired(assertion)) {
            log.warn("Received assertion not processed because it has expired.");
            return null;
        }

        AuthnStatementType authnStatement = extractValidAuthnStatement(assertion);
        if (authnStatement == null) {
            log.warn("Received assertion not processed because it doesn't contain a valid authnStatement.");
            return null;
        }

        NameIDType nameId = validateSubjectAndExtractNameID(assertion);
        if (nameId == null) {
            log.warn("Received assertion not processed because it doesn't contain a valid subject.");
            return null;
        }

        SamlPrincipalImpl principal = new SamlPrincipalImpl();
        principal.setAssertion(assertion);
        principal.setNameId(new SamlNameIdImpl(nameId.getValue(), nameId.getFormat(), nameId.getNameQualifier()));
        SamlSpSessionImpl session = new SamlSpSessionImpl();
        session.setSessionIndex(authnStatement.getSessionIndex());
        session.setPrincipal(principal);
        session.setIdentityProvider(idp);

        for (StatementAbstractType statement : assertion.getStatementOrAuthnStatementOrAuthzDecisionStatement()) {
            if (statement instanceof AttributeStatementType) {
                AttributeStatementType attributeStatement = (AttributeStatementType) statement;
                List<AttributeType> attributes = new LinkedList<AttributeType>();
                for (Object object : attributeStatement.getAttributeOrEncryptedAttribute()) {
                    if (object instanceof AttributeType) {
                        attributes.add((AttributeType) object);
                    } else {
                        log.warn("Encrypted attributes are not supported. Ignoring the attribute.");
                    }
                }
                principal.setAttributes(attributes);
            }
        }

        return session;
    }

    private AuthnStatementType extractValidAuthnStatement(AssertionType assertion) {
        for (StatementAbstractType statement : assertion.getStatementOrAuthnStatementOrAuthzDecisionStatement()) {
            if (statement instanceof AuthnStatementType) {
                AuthnStatementType authnStatement = (AuthnStatementType) statement;
                return authnStatement;
            }
        }

        return null;
    }

    private NameIDType validateSubjectAndExtractNameID(AssertionType assertion) {
        NameIDType nameId = null;
        boolean validConfirmationFound = false;

        for (JAXBElement<?> contentElement : assertion.getSubject().getContent()) {
            if (contentElement.getValue() instanceof NameIDType) {
                nameId = (NameIDType) contentElement.getValue();
            }
            if (contentElement.getValue() instanceof SubjectConfirmationType) {
                SubjectConfirmationType confirmation = (SubjectConfirmationType) contentElement.getValue();
                if (confirmation.getMethod().equals(SamlConstants.CONFIRMATION_METHOD_BEARER)) {
                    SubjectConfirmationDataType confirmationData = confirmation.getSubjectConfirmationData();

                    boolean validRecipient = confirmationData.getRecipient().equals(samlEntityBean.get().getServiceURL(SamlServiceType.SAML_ASSERTION_CONSUMER_SERVICE));

                    boolean notTooLate = confirmationData.getNotOnOrAfter().compare(SamlUtils.getXMLGregorianCalendarNow()) == DatatypeConstants.GREATER;

                    boolean validInResponseTo = confirmationData.getInResponseTo() == null || confirmationData.getInResponseTo().equals(dialogue.getId());

                    if (validRecipient && notTooLate && validInResponseTo) {
                        validConfirmationFound = true;
                    } else {
                        log.debugf("Validation of assertion failed: validRecipient: %b; notTootLate: %b; validInResponseTo: %b", new Object[]{validRecipient, notTooLate, validInResponseTo});
                    }
                }
            }
        }

        if (validConfirmationFound) {
            return nameId;
        } else {
            return null;
        }
    }

    private void loginUser(HttpServletRequest httpRequest, HttpServletResponse response, SamlSpSessionImpl session, boolean unsolicited, String relayState) {
        samlSpSessions.addSession(session);

        if (unsolicited) {
            samlServiceProviderSpi.get().loggedIn(session, relayState, responseHandler.createResponseHolder(response));
        } else {
            samlServiceProviderSpi.get().loginSucceeded(session, responseHandler.createResponseHolder(response));
        }
    }

    public void sendAuthenticationRequestToIDP(SamlExternalIdentityProvider idp, HttpServletResponse response) {
        AuthnRequestType authnRequest = samlMessageFactory.createAuthnRequest();

        samlDialogue.setExternalProvider(idp);

        samlMessageSender.sendRequest(idp, SamlProfile.SINGLE_SIGN_ON, authnRequest, response);
    }
}
TOP

Related Classes of org.jboss.seam.security.external.saml.sp.SamlSpSingleSignOnService

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.