/*
* 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.");
}
}
}
}