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

Source Code of org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler$SPAuthenticationHandler

/*
* 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 java.net.URI;
import java.security.Principal;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.xml.namespace.QName;

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.SerializablePrincipal;
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.ProcessingException;
import org.picketlink.identity.federation.core.parsers.saml.SAMLParser;
import org.picketlink.identity.federation.core.parsers.util.StaxParserUtil;
import org.picketlink.identity.federation.core.saml.v2.common.IDGenerator;
import org.picketlink.identity.federation.core.saml.v2.constants.JBossSAMLConstants;
import org.picketlink.identity.federation.core.saml.v2.constants.JBossSAMLURIConstants;
import org.picketlink.identity.federation.core.saml.v2.constants.SAMLAuthenticationContextClass;
import org.picketlink.identity.federation.core.saml.v2.exceptions.AssertionExpiredException;
import org.picketlink.identity.federation.core.saml.v2.holders.IDPInfoHolder;
import org.picketlink.identity.federation.core.saml.v2.holders.IssuerInfoHolder;
import org.picketlink.identity.federation.core.saml.v2.holders.SPInfoHolder;
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.AssertionUtil;
import org.picketlink.identity.federation.core.saml.v2.util.DocumentUtil;
import org.picketlink.identity.federation.core.saml.v2.util.StatementUtil;
import org.picketlink.identity.federation.core.saml.v2.util.XMLTimeUtil;
import org.picketlink.identity.federation.core.util.JAXPValidationUtil;
import org.picketlink.identity.federation.core.util.StringUtil;
import org.picketlink.identity.federation.core.util.XMLEncryptionUtil;
import org.picketlink.identity.federation.saml.v2.assertion.AssertionType;
import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType.ASTChoiceType;
import org.picketlink.identity.federation.saml.v2.assertion.AttributeType;
import org.picketlink.identity.federation.saml.v2.assertion.AuthnStatementType;
import org.picketlink.identity.federation.saml.v2.assertion.EncryptedAssertionType;
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.assertion.SubjectType;
import org.picketlink.identity.federation.saml.v2.assertion.SubjectType.STSubType;
import org.picketlink.identity.federation.saml.v2.metadata.EndpointType;
import org.picketlink.identity.federation.saml.v2.metadata.SPSSODescriptorType;
import org.picketlink.identity.federation.saml.v2.protocol.AuthnContextComparisonType;
import org.picketlink.identity.federation.saml.v2.protocol.AuthnRequestType;
import org.picketlink.identity.federation.saml.v2.protocol.RequestedAuthnContextType;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType.RTChoiceType;
import org.picketlink.identity.federation.saml.v2.protocol.StatusType;
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.interfaces.IRoleValidator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
* <p>
* Handles for dealing with SAML2 Authentication
* </p>
* <p>
* Configuration Options:
*
* @see SAML2Handler#CLOCK_SKEW_MILIS: a milisecond value sets a skew for checking the validity of assertion (SP Setting)
* @see SAML2Handler#DISABLE_AUTHN_STATEMENT Setting a value will disable the generation of an AuthnStatement (IDP Setting)
* @see SAML2Handler#DISABLE_SENDING_ROLES Setting any value will disable the generation and return of roles to SP (IDP Setting)
* @see SAML2Handler#USE_MULTI_VALUED_ROLES Setting any value will have an attribute statement with multiple values (IDP Setting)
* @see SAML2Handler#DISABLE_ROLE_PICKING Setting to true will disable picking IDP attribute statements (SP Setting)
* @see SAML2Handler#ROLE_KEY a csv list of strings that represent the roles coming from IDP (SP Setting)
* @see GeneralConstants#NAMEID_FORMAT Setting to a value will provide the nameid format to be sent to IDP (SP Setting)
* @see SAML2Handler#ASSERTION_CONSUMER_URL: the url to be used for assertionConsumerURL (SP Setting)
*      </p>
*
* @author Anil.Saldhana@redhat.com
* @since Oct 8, 2009
*/
public class SAML2AuthenticationHandler extends BaseSAML2Handler {

    private final IDPAuthenticationHandler idp = new IDPAuthenticationHandler();

    private final SPAuthenticationHandler sp = new SPAuthenticationHandler();

    public void handleRequestType(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
        if (request.getSAML2Object() instanceof AuthnRequestType == false)
            return;

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

    @Override
    public void handleStatusResponseType(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
        if (request.getSAML2Object() instanceof ResponseType == false)
            return;

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

    @Override
    public void generateSAMLRequest(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
        if (GENERATE_REQUEST_TYPE.AUTH != request.getTypeOfRequestToBeGenerated())
            return;

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

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

        public void handleStatusResponseType(SAML2HandlerRequest request, SAML2HandlerResponse response)
                throws ProcessingException {
        }

        public void handleRequestType(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
            HTTPContext httpContext = (HTTPContext) request.getContext();
            ServletContext servletContext = httpContext.getServletContext();

            AuthnRequestType art = (AuthnRequestType) request.getSAML2Object();
            if (art == null)
                throw logger.samlHandlerAuthnRequestIsNull();

            String destination = art.getAssertionConsumerServiceURL().toASCIIString();

            logger.trace("Destination = " + destination);

            response.setDestination(destination);

            HttpSession session = BaseSAML2Handler.getHttpSession(request);
            Principal userPrincipal = (Principal) session.getAttribute(GeneralConstants.PRINCIPAL_ID);
            if (userPrincipal == null)
                userPrincipal = httpContext.getRequest().getUserPrincipal();
            /*
             * List<String> roles = (List<String>) session.getAttribute(GeneralConstants.ROLES_ID);
             */
            try {
                /*
                 * Map<String,Object> attribs = (Map<String, Object>) request.getOptions().get(GeneralConstants.ATTRIBUTES);
                 * long assertionValidity = (Long) request.getOptions().get(GeneralConstants.ASSERTIONS_VALIDITY); String
                 * destination = art.getAssertionConsumerServiceURL().toASCIIString(); Document samlResponse =
                 * this.getResponse(destination, userPrincipal, roles, request.getIssuer().getValue(), attribs,
                 * assertionValidity, art.getID());
                 */

                Document samlResponse = this.getResponse(request);

                // Update the Identity Server
                boolean isPost = httpContext.getRequest().getMethod().equalsIgnoreCase("POST");
                IdentityServer identityServer = (IdentityServer) servletContext.getAttribute(GeneralConstants.IDENTITY_SERVER);
                // We will try to find URL for global logout from SP metadata (if they are provided) and use SP logout URL
                // for registration to IdentityServer
                String participantLogoutURL = getParticipantURL(destination, request);

                logger.trace("Participant " + destination + " will be registered to IdentityServer with logout URL "
                        + participantLogoutURL);

                // If URL is null, participant doesn't support global logout
                if (participantLogoutURL != null) {
                    identityServer.stack().register(session.getId(), participantLogoutURL, isPost);
                }

                // Check whether we use POST binding for response
                boolean strictPostBinding = request.getOptions().get(GeneralConstants.SAML_IDP_STRICT_POST_BINDING) != null
                        && (Boolean) request.getOptions().get(GeneralConstants.SAML_IDP_STRICT_POST_BINDING);
                boolean postBindingForResponse = isPost || strictPostBinding;

                response.setResultingDocument(samlResponse);
                response.setRelayState(request.getRelayState());
                response.setPostBindingForResponse(postBindingForResponse);
            } catch (Exception e) {
                logger.samlHandlerAuthenticationError(e);
                throw logger.processingError(e);
            }
        }

        @SuppressWarnings("unchecked")
        public Document getResponse(SAML2HandlerRequest request) throws ConfigurationException, ProcessingException {
            HTTPContext httpContext = (HTTPContext) request.getContext();
            AuthnRequestType art = (AuthnRequestType) request.getSAML2Object();
            HttpSession session = BaseSAML2Handler.getHttpSession(request);
            Principal userPrincipal = (Principal) session.getAttribute(GeneralConstants.PRINCIPAL_ID);
            if (userPrincipal == null)
                userPrincipal = httpContext.getRequest().getUserPrincipal();

            String assertionConsumerURL = art.getAssertionConsumerServiceURL().toASCIIString();
            List<String> roles = (List<String>) session.getAttribute(GeneralConstants.ROLES_ID);
            String identityURL = request.getIssuer().getValue();
            Map<String, Object> attribs = (Map<String, Object>) request.getOptions().get(GeneralConstants.ATTRIBUTES);
            String requestID = art.getID();

            Document samlResponseDocument = null;

            String authMethod = (String) request.getOptions().get(GeneralConstants.LOGIN_TYPE);

            logger.trace("AssertionConsumerURL=" + assertionConsumerURL);

            ResponseType responseType = null;

            SAML2Response saml2Response = new SAML2Response();

            // Create a response type
            String id = IDGenerator.create("ID_");

            IssuerInfoHolder issuerHolder = new IssuerInfoHolder(identityURL);
            issuerHolder.setStatusCode(JBossSAMLURIConstants.STATUS_SUCCESS.get());

            IDPInfoHolder idp = new IDPInfoHolder();
            idp.setNameIDFormatValue(userPrincipal.getName());
            idp.setNameIDFormat(JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get());

            String assertionID = (String) session.getAttribute(GeneralConstants.ASSERTION_ID);

            if (assertionID != null) {
                // Just renew the assertion
                AssertionType latestAssertion = (AssertionType) session.getAttribute(GeneralConstants.ASSERTION);
                if (latestAssertion != null)
                    idp.setAssertion(latestAssertion);
            }

            SPInfoHolder sp = new SPInfoHolder();
            sp.setResponseDestinationURI(assertionConsumerURL);
            sp.setRequestID(requestID);
            sp.setIssuer(art.getIssuer().getValue());
            responseType = saml2Response.createResponseType(id, sp, idp, issuerHolder);

            // Add information on the roles
            AssertionType assertion = responseType.getAssertions().get(0).getAssertion();

            // Create an AuthnStatementType
            if (handlerConfig.getParameter(DISABLE_AUTHN_STATEMENT) == null) {
                String authContextRef = JBossSAMLURIConstants.AC_PASSWORD.get();
                if (StringUtil.isNotNull(authMethod))
                    authContextRef = authMethod;

                AuthnStatementType authnStatement = StatementUtil.createAuthnStatement(XMLTimeUtil.getIssueInstant(),
                        authContextRef);

                authnStatement.setSessionIndex(assertion.getID());

                assertion.addStatement(authnStatement);
            }

            if (handlerConfig.getParameter(DISABLE_SENDING_ROLES) == null && (roles != null && !roles.isEmpty())) {
                AttributeStatementType attrStatement = null;
                if(handlerConfig.getParameter(USE_MULTI_VALUED_ROLES) != null){
                    attrStatement = StatementUtil.createAttributeStatementForRoles(roles,true);
                }else {
                    attrStatement = StatementUtil.createAttributeStatement(roles);
                }
                if(attrStatement != null){
                    assertion.addStatement(attrStatement);  
                }
            }

            // Add in the attributes information
            if (attribs != null && attribs.size() > 0) {
                AttributeStatementType attStatement = StatementUtil.createAttributeStatement(attribs);
                assertion.addStatement(attStatement);
            }

            // Add assertion to the session
            session.setAttribute(GeneralConstants.ASSERTION, assertion);

            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.CREATED_ASSERTION);
                auditEvent.setAssertionID(id);
                auditHelper.audit(auditEvent);
            }

            try {
                samlResponseDocument = saml2Response.convert(responseType);

                if (logger.isTraceEnabled()) {
                    logger.trace("SAML Response Document: " + DocumentUtil.asString(samlResponseDocument));
                }
            } catch (Exception e) {
                throw logger.samlAssertionMarshallError(e);
            }

            return samlResponseDocument;
        }

        private String getParticipantURL(String destination, SAML2HandlerRequest request) {
            SPSSODescriptorType spMetadata = (SPSSODescriptorType) request.getOptions().get(
                    GeneralConstants.SP_SSO_METADATA_DESCRIPTOR);

            // Metadata not found. We will use destination for registration to IdentityServer
            if (spMetadata == null) {
                return destination;
            }

            List<EndpointType> logoutEndpoints = spMetadata.getSingleLogoutService();

            // If endpoint not found, we assume that SP doesn't support logout profile
            if (logoutEndpoints == null || logoutEndpoints.size() == 0) {
                return null;
            }

            // Use first endpoint for now (Maybe later we can find logoutType according to bindingType from SAMLRequest)
            EndpointType logoutEndpoint = logoutEndpoints.get(0);
            return logoutEndpoint.getLocation().toASCIIString();
        }
    }

    private class SPAuthenticationHandler {
        public void generateSAMLRequest(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
            String issuerValue = request.getIssuer().getValue();

            SAML2Request samlRequest = new SAML2Request();
            String id = IDGenerator.create("ID_");

            String assertionConsumerURL = (String) handlerConfig.getParameter(SAML2Handler.ASSERTION_CONSUMER_URL);
            if (StringUtil.isNullOrEmpty(assertionConsumerURL)) {
                assertionConsumerURL = issuerValue;
            }

            // Check if there is a nameid policy
            String nameIDFormat = (String) handlerConfig.getParameter(GeneralConstants.NAMEID_FORMAT);
            if (StringUtil.isNotNull(nameIDFormat)) {
                samlRequest.setNameIDFormat(nameIDFormat);
            }
            try {
                AuthnRequestType authn = samlRequest.createAuthnRequestType(id, assertionConsumerURL,
                        response.getDestination(), issuerValue);

                createRequestAuthnContext(authn);

                String bindingType = getSPConfiguration().getBindingType();
                boolean isIdpUsesPostBinding = getSPConfiguration().isIdpUsesPostBinding();

                if (bindingType != null) {
                    if (bindingType.equals("POST") || isIdpUsesPostBinding) {
                        authn.setProtocolBinding(URI.create(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get()));
                    } else if (bindingType.equals("REDIRECT")) {
                        authn.setProtocolBinding(URI.create(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get()));
                    } else {
                        throw logger.samlInvalidProtocolBinding();
                    }
                }

                response.setResultingDocument(samlRequest.convert(authn));
                response.setSendRequest(true);

                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.CREATED_ASSERTION);
                    auditEvent.setAssertionID(id);
                    auditHelper.audit(auditEvent);
                }

                // Save AuthnRequest ID into sharedState, so that we can later process it by another handler
                request.addOption(GeneralConstants.AUTH_REQUEST_ID, id);
            } catch (Exception e) {
                throw logger.processingError(e);
            }
        }

        public void handleStatusResponseType(SAML2HandlerRequest request, SAML2HandlerResponse response)
                throws ProcessingException {
            HTTPContext httpContext = (HTTPContext) request.getContext();
            ResponseType responseType = (ResponseType) request.getSAML2Object();
            List<RTChoiceType> assertions = responseType.getAssertions();
            if (assertions.size() == 0)
                throw logger.samlHandlerNoAssertionFromIDP();

            PrivateKey privateKey = (PrivateKey) request.getOptions().get(GeneralConstants.DECRYPTING_KEY);

            Object assertion = assertions.get(0).getEncryptedAssertion();
            if (assertion instanceof EncryptedAssertionType) {
                responseType = this.decryptAssertion(responseType, privateKey);
                assertion = responseType.getAssertions().get(0).getAssertion();
            }
            if (assertion == null) {
                assertion = assertions.get(0).getAssertion();
            }

            request.addOption(GeneralConstants.ASSERTION, assertion);

            Principal userPrincipal = handleSAMLResponse(responseType, response);
            if (userPrincipal == null) {
                response.setError(403, "User Principal not determined: Forbidden");
            } else {
                HttpSession session = httpContext.getRequest().getSession(false);

                // add the principal to the session
                session.setAttribute(GeneralConstants.PRINCIPAL_ID, userPrincipal);

                Document assertionDocument = AssertionUtil.asDocument((AssertionType) assertion);
               
                String assertionAttributeName = (String) handlerConfig
                        .getParameter(GeneralConstants.ASSERTION_SESSION_ATTRIBUTE_NAME);
               
                if (assertionAttributeName != null) {
                    session.setAttribute(assertionAttributeName, assertionDocument);
                }
               
                session.setAttribute(GeneralConstants.ASSERTION_SESSION_ATTRIBUTE_NAME, assertionDocument);
            }
        }

        public void handleRequestType(SAML2HandlerRequest request, SAML2HandlerResponse response) throws ProcessingException {
        }

        private ResponseType decryptAssertion(ResponseType responseType, PrivateKey privateKey) throws ProcessingException {
            if (privateKey == null)
                throw logger.nullArgumentError("privateKey");
            SAML2Response saml2Response = new SAML2Response();
            try {
                Document doc = saml2Response.convert(responseType);

                Element enc = DocumentUtil.getElement(doc, new QName(JBossSAMLConstants.ENCRYPTED_ASSERTION.get()));
                if (enc == null)
                    throw logger.samlHandlerNullEncryptedAssertion();
                String oldID = enc.getAttribute(JBossSAMLConstants.ID.get());
                Document newDoc = DocumentUtil.createDocument();
                Node importedNode = newDoc.importNode(enc, true);
                newDoc.appendChild(importedNode);

                Element decryptedDocumentElement = XMLEncryptionUtil.decryptElementInDocument(newDoc, privateKey);
                SAMLParser parser = new SAMLParser();

                JAXPValidationUtil.checkSchemaValidation(decryptedDocumentElement);
                AssertionType assertion = (AssertionType) parser.parse(StaxParserUtil.getXMLEventReader(DocumentUtil
                        .getNodeAsStream(decryptedDocumentElement)));

                responseType.replaceAssertion(oldID, new RTChoiceType(assertion));
                return responseType;
            } catch (Exception e) {
                throw logger.processingError(e);
            }
        }

        private Principal handleSAMLResponse(ResponseType responseType, SAML2HandlerResponse response)
                throws ProcessingException {
            if (responseType == null)
                throw logger.nullArgumentError("response type");

            StatusType statusType = responseType.getStatus();
            if (statusType == null)
                throw logger.nullArgumentError("Status Type from the IDP");

            String statusValue = statusType.getStatusCode().getValue().toASCIIString();
            if (JBossSAMLURIConstants.STATUS_SUCCESS.get().equals(statusValue) == false)
                throw logger.samlHandlerIDPAuthenticationFailedError();

            List<RTChoiceType> assertions = responseType.getAssertions();
            if (assertions.size() == 0)
                throw logger.samlHandlerNoAssertionFromIDP();

            AssertionType assertion = assertions.get(0).getAssertion();
            // Check for validity of assertion
            boolean expiredAssertion;
            try {
                String skew = (String) handlerConfig.getParameter(SAML2Handler.CLOCK_SKEW_MILIS);
                if (StringUtil.isNotNull(skew)) {
                    long skewMilis = Long.parseLong(skew);
                    expiredAssertion = AssertionUtil.hasExpired(assertion, skewMilis);
                } else
                    expiredAssertion = AssertionUtil.hasExpired(assertion);
            } catch (ConfigurationException e) {
                throw new ProcessingException(e);
            }
            if (expiredAssertion) {
                AssertionExpiredException aee = new AssertionExpiredException();
                aee.setId(assertion.getID());
                throw logger.assertionExpiredError(aee);
            }

            SubjectType subject = assertion.getSubject();
            /*
             * JAXBElement<NameIDType> jnameID = (JAXBElement<NameIDType>) subject.getContent().get(0); NameIDType nameID =
             * jnameID.getValue();
             */
            if (subject == null)
                throw logger.nullValueError("Subject in the assertion");

            STSubType subType = subject.getSubType();
            if (subType == null)
                throw logger.nullValueError("Unable to find subtype via subject");
            NameIDType nameID = (NameIDType) subType.getBaseID();

            if (nameID == null)
                throw logger.nullValueError("Unable to find username via subject");

            final String userName = nameID.getValue();
            List<String> roles = new ArrayList<String>();

            // Let us get the roles
            Set<StatementAbstractType> statements = assertion.getStatements();
            for (StatementAbstractType statement : statements) {
                if (statement instanceof AttributeStatementType) {
                    AttributeStatementType attributeStatement = (AttributeStatementType) statement;
                    roles.addAll(getRoles(attributeStatement));
                }
            }

            response.setRoles(roles);

            Principal principal = new SerializablePrincipal(userName);

            if (handlerChainConfig.getParameter(GeneralConstants.ROLE_VALIDATOR_IGNORE) == null) {
                // Validate the roles
                IRoleValidator roleValidator = (IRoleValidator) handlerChainConfig
                        .getParameter(GeneralConstants.ROLE_VALIDATOR);
                if (roleValidator == null)
                    throw logger.nullValueError("Role Validator");

                boolean validRole = roleValidator.userInRole(principal, roles);

                if (!validRole) {
                    logger.trace("Invalid role: " + roles);
                    principal = null;
                }
            }
            return principal;
        }

        /**
         * Get the roles from the attribute statement
         *
         * @param attributeStatement
         * @return
         */
        private List<String> getRoles(AttributeStatementType attributeStatement) {
            List<String> roles = new ArrayList<String>();

            // PLFED-141: Disable role picking from IDP response
            if (handlerConfig.containsKey(DISABLE_ROLE_PICKING)) {
                String val = (String) handlerConfig.getParameter(DISABLE_ROLE_PICKING);
                if (StringUtil.isNotNull(val) && "true".equalsIgnoreCase(val))
                    return roles;
            }

            // PLFED-140: which of the attribute statements represent roles?
            List<String> roleKeys = new ArrayList<String>();

            if (handlerConfig.containsKey(ROLE_KEY)) {
                String roleKey = (String) handlerConfig.getParameter(ROLE_KEY);
                if (StringUtil.isNotNull(roleKey)) {
                    roleKeys.addAll(StringUtil.tokenize(roleKey));
                }
            }

            List<ASTChoiceType> attList = attributeStatement.getAttributes();
            for (ASTChoiceType obj : attList) {
                AttributeType attr = obj.getAttribute();
                if (roleKeys.size() > 0) {
                    if (!roleKeys.contains(attr.getName()))
                        continue;
                }
                List<Object> attributeValues = attr.getAttributeValue();
                if (attributeValues != null) {
                    for (Object attrValue : attributeValues) {
                        if (attrValue instanceof String) {
                            roles.add((String) attrValue);
                        } else if (attrValue instanceof Node) {
                            Node roleNode = (Node) attrValue;
                            roles.add(roleNode.getFirstChild().getNodeValue());
                        } else
                            throw logger.unsupportedRoleType(attrValue);
                    }
                }
            }
            return roles;
        }

        private SPType getSPConfiguration() {
            SPType spConfiguration = (SPType) handlerChainConfig.getParameter(GeneralConstants.CONFIGURATION);

            if (spConfiguration == null) {
                throw logger.samlHandlerServiceProviderConfigNotFound();
            }

            return spConfiguration;
        }
    }

    private void createRequestAuthnContext(final AuthnRequestType authn) {
        String authnContextClasses = (String) handlerConfig.getParameter(GeneralConstants.AUTHN_CONTEXT_CLASSES);

        if (StringUtil.isNotNull(authnContextClasses)) {
            RequestedAuthnContextType requestAuthnContext = new RequestedAuthnContextType();

            for (String contextClass: authnContextClasses.split(",")) {
                SAMLAuthenticationContextClass standardClass = SAMLAuthenticationContextClass.forAlias(contextClass);

                if (standardClass != null) {
                    contextClass = standardClass.getFqn();
                }

                requestAuthnContext.addAuthnContextClassRef(contextClass);
            }

            if (!requestAuthnContext.getAuthnContextClassRef().isEmpty()) {
                authn.setRequestedAuthnContext(requestAuthnContext);

                String comparison = (String) handlerConfig.getParameter(GeneralConstants.REQUESTED_AUTHN_CONTEXT_COMPARISON);

                if (StringUtil.isNotNull(comparison)) {
                    requestAuthnContext.setComparison(AuthnContextComparisonType.fromValue(comparison));
                }
            } else {
                logger.debug("RequestedAuthnContext not set for AuthnRequest. No context class was provided.");
            }
        }
    }

}
TOP

Related Classes of org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler$SPAuthenticationHandler

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.