/* * 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.filters; import static org.picketlink.identity.federation.core.util.StringUtil.isNotNull; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.Principal; import java.security.PublicKey; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.xml.crypto.MarshalException; import javax.xml.crypto.dsig.CanonicalizationMethod; import javax.xml.crypto.dsig.XMLSignatureException; import org.apache.log4j.Logger; 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.api.saml.v2.sig.SAML2Signature; import org.picketlink.identity.federation.core.ErrorCodes; import org.picketlink.identity.federation.core.config.AuthPropertyType; import org.picketlink.identity.federation.core.config.KeyProviderType; import org.picketlink.identity.federation.core.config.PicketLinkType; import org.picketlink.identity.federation.core.config.SPType; import org.picketlink.identity.federation.core.config.TrustType; 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.handler.config.Handlers; import org.picketlink.identity.federation.core.interfaces.ProtocolContext; import org.picketlink.identity.federation.core.interfaces.TrustKeyConfigurationException; import org.picketlink.identity.federation.core.interfaces.TrustKeyManager; import org.picketlink.identity.federation.core.interfaces.TrustKeyProcessingException; import org.picketlink.identity.federation.core.saml.v2.common.IDGenerator; import org.picketlink.identity.federation.core.saml.v2.common.SAMLDocumentHolder; import org.picketlink.identity.federation.core.saml.v2.constants.JBossSAMLURIConstants; import org.picketlink.identity.federation.core.saml.v2.exceptions.AssertionExpiredException; import org.picketlink.identity.federation.core.saml.v2.exceptions.IssuerNotTrustedException; import org.picketlink.identity.federation.core.saml.v2.factories.SAML2HandlerChainFactory; import org.picketlink.identity.federation.core.saml.v2.holders.DestinationInfoHolder; import org.picketlink.identity.federation.core.saml.v2.holders.IssuerInfoHolder; import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerChainConfig; import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerRequest; import org.picketlink.identity.federation.core.saml.v2.impl.DefaultSAML2HandlerResponse; import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler; import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2Handler.HANDLER_TYPE; import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerChain; import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerChainConfig; 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.HandlerUtil; import org.picketlink.identity.federation.core.util.CoreConfigUtil; import org.picketlink.identity.federation.core.util.StringUtil; import org.picketlink.identity.federation.core.util.XMLSignatureUtil; 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.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.NameIDType; import org.picketlink.identity.federation.saml.v2.assertion.SubjectType; import org.picketlink.identity.federation.saml.v2.protocol.AuthnRequestType; import org.picketlink.identity.federation.saml.v2.protocol.RequestAbstractType; import org.picketlink.identity.federation.saml.v2.protocol.ResponseType; import org.picketlink.identity.federation.saml.v2.protocol.StatusResponseType; 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.interfaces.IRoleValidator; import org.picketlink.identity.federation.web.roles.DefaultRoleValidator; import org.picketlink.identity.federation.web.util.ConfigurationUtil; import org.picketlink.identity.federation.web.util.PostBindingUtil; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.SAXException; /** * A service provider filter for web container agnostic providers * * @author Anil.Saldhana@redhat.com * @since Aug 21, 2009 */ public class SPFilter implements Filter { private static Logger log = Logger.getLogger(SPFilter.class); private final boolean trace = log.isTraceEnabled(); protected SPType spConfiguration = null; protected PicketLinkType picketLinkConfiguration = null; protected String configFile = GeneralConstants.CONFIG_FILE_LOCATION; protected String serviceURL = null; protected String identityURL = null; private TrustKeyManager keyManager; private ServletContext context = null; private transient SAML2HandlerChain chain = null; protected boolean ignoreSignatures = false; private IRoleValidator roleValidator = new DefaultRoleValidator(); private String logOutPage = GeneralConstants.LOGOUT_PAGE_NAME; protected String canonicalizationMethod = CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS; public void destroy() { } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; boolean postMethod = "POST".equalsIgnoreCase(request.getMethod()); HttpSession session = request.getSession(); Principal userPrincipal = (Principal) session.getAttribute(GeneralConstants.PRINCIPAL_ID); String samlRequest = request.getParameter(GeneralConstants.SAML_REQUEST_KEY); String samlResponse = request.getParameter(GeneralConstants.SAML_RESPONSE_KEY); // Eagerly look for Global LogOut String gloStr = request.getParameter(GeneralConstants.GLOBAL_LOGOUT); boolean logOutRequest = isNotNull(gloStr) && "true".equalsIgnoreCase(gloStr); if (!postMethod && !logOutRequest) { // Check if we are already authenticated if (userPrincipal != null) { filterChain.doFilter(servletRequest, servletResponse); return; } // We need to send request to IDP if (userPrincipal == null) { String relayState = null; try { // TODO: use the handlers to generate the request AuthnRequestType authnRequest = createSAMLRequest(serviceURL, identityURL); sendRequestToIDP(authnRequest, relayState, response); } catch (Exception e) { throw new ServletException(e); } return; } } else { if (!isNotNull(samlRequest) && !isNotNull(samlResponse)) { // Neither saml request nor response from IDP // So this is a user request // Ask the handler chain to generate the saml request Set<SAML2Handler> handlers = chain.handlers(); IssuerInfoHolder holder = new IssuerInfoHolder(this.serviceURL); ProtocolContext protocolContext = new HTTPContext(request, response, context); // Create the request/response SAML2HandlerRequest saml2HandlerRequest = new DefaultSAML2HandlerRequest(protocolContext, holder.getIssuer(), null, HANDLER_TYPE.SP); SAML2HandlerResponse saml2HandlerResponse = new DefaultSAML2HandlerResponse(); saml2HandlerResponse.setDestination(identityURL); // Reset the state try { for (SAML2Handler handler : handlers) { handler.reset(); if (saml2HandlerResponse.isInError()) { response.sendError(saml2HandlerResponse.getErrorCode()); break; } if (logOutRequest) saml2HandlerRequest.setTypeOfRequestToBeGenerated(GENERATE_REQUEST_TYPE.LOGOUT); else saml2HandlerRequest.setTypeOfRequestToBeGenerated(GENERATE_REQUEST_TYPE.AUTH); handler.generateSAMLRequest(saml2HandlerRequest, saml2HandlerResponse); } } catch (ProcessingException pe) { throw new RuntimeException(pe); } Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); String relayState = saml2HandlerResponse.getRelayState(); String destination = saml2HandlerResponse.getDestination(); if (destination != null && samlResponseDocument != null) { try { this.sendToDestination(samlResponseDocument, relayState, destination, response, saml2HandlerResponse.getSendRequest()); } catch (Exception e) { if (trace) log.trace("Exception:", e); throw new ServletException(ErrorCodes.SERVICE_PROVIDER_SERVER_EXCEPTION + "Server Error"); } return; } } // See if we got a response from IDP if (isNotNull(samlResponse)) { boolean isValid = false; try { isValid = this.validate(request); } catch (Exception e) { throw new ServletException(e); } if (!isValid) throw new ServletException(ErrorCodes.VALIDATION_CHECK_FAILED + "Validity check failed"); // deal with SAML response from IDP byte[] base64DecodedResponse = PostBindingUtil.base64Decode(samlResponse); InputStream is = new ByteArrayInputStream(base64DecodedResponse); // Are we going to send Request to IDP? boolean willSendRequest = true; try { SAML2Response saml2Response = new SAML2Response(); SAML2Object samlObject = saml2Response.getSAML2ObjectFromStream(is); SAMLDocumentHolder documentHolder = saml2Response.getSamlDocumentHolder(); if (!ignoreSignatures) { if (!verifySignature(documentHolder)) throw new ServletException(ErrorCodes.INVALID_DIGITAL_SIGNATURE + "Cannot verify sender"); } Set<SAML2Handler> handlers = chain.handlers(); IssuerInfoHolder holder = new IssuerInfoHolder(this.serviceURL); ProtocolContext protocolContext = new HTTPContext(request, response, context); // Create the request/response SAML2HandlerRequest saml2HandlerRequest = new DefaultSAML2HandlerRequest(protocolContext, holder.getIssuer(), documentHolder, HANDLER_TYPE.SP); if (keyManager != null) saml2HandlerRequest.addOption(GeneralConstants.DECRYPTING_KEY, keyManager.getSigningKey()); SAML2HandlerResponse saml2HandlerResponse = new DefaultSAML2HandlerResponse(); // Deal with handler chains for (SAML2Handler handler : handlers) { if (saml2HandlerResponse.isInError()) { response.sendError(saml2HandlerResponse.getErrorCode()); break; } if (samlObject instanceof RequestAbstractType) { handler.handleRequestType(saml2HandlerRequest, saml2HandlerResponse); willSendRequest = false; } else { handler.handleStatusResponseType(saml2HandlerRequest, saml2HandlerResponse); } } Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); String relayState = saml2HandlerResponse.getRelayState(); String destination = saml2HandlerResponse.getDestination(); if (destination != null && samlResponseDocument != null) { this.sendToDestination(samlResponseDocument, relayState, destination, response, willSendRequest); return; } // See if the session has been invalidated try { session.isNew(); } catch (IllegalStateException ise) { // we are invalidated. RequestDispatcher dispatch = context.getRequestDispatcher(this.logOutPage); if (dispatch == null) log.error("Cannot dispatch to the logout page: no request dispatcher:" + this.logOutPage); else dispatch.forward(request, response); return; } filterChain.doFilter(request, servletResponse); } catch (Exception e) { log.error("Server Exception:", e); throw new ServletException(ErrorCodes.SERVICE_PROVIDER_SERVER_EXCEPTION); } } if (isNotNull(samlRequest)) { // we got a logout request // deal with SAML response from IDP byte[] base64DecodedRequest = PostBindingUtil.base64Decode(samlRequest); InputStream is = new ByteArrayInputStream(base64DecodedRequest); // Are we going to send Request to IDP? boolean willSendRequest = false; try { SAML2Request saml2Request = new SAML2Request(); SAML2Object samlObject = saml2Request.getSAML2ObjectFromStream(is); SAMLDocumentHolder documentHolder = saml2Request.getSamlDocumentHolder(); if (!ignoreSignatures) { if (!verifySignature(documentHolder)) throw new ServletException(ErrorCodes.INVALID_DIGITAL_SIGNATURE + "Cannot verify sender"); } Set<SAML2Handler> handlers = chain.handlers(); IssuerInfoHolder holder = new IssuerInfoHolder(this.serviceURL); ProtocolContext protocolContext = new HTTPContext(request, response, context); // Create the request/response SAML2HandlerRequest saml2HandlerRequest = new DefaultSAML2HandlerRequest(protocolContext, holder.getIssuer(), documentHolder, HANDLER_TYPE.SP); if (keyManager != null) saml2HandlerRequest.addOption(GeneralConstants.DECRYPTING_KEY, keyManager.getSigningKey()); SAML2HandlerResponse saml2HandlerResponse = new DefaultSAML2HandlerResponse(); // Deal with handler chains for (SAML2Handler handler : handlers) { if (saml2HandlerResponse.isInError()) { response.sendError(saml2HandlerResponse.getErrorCode()); break; } if (samlObject instanceof RequestAbstractType) { handler.handleRequestType(saml2HandlerRequest, saml2HandlerResponse); willSendRequest = false; } else { handler.handleStatusResponseType(saml2HandlerRequest, saml2HandlerResponse); } } Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); String relayState = saml2HandlerResponse.getRelayState(); String destination = saml2HandlerResponse.getDestination(); if (destination != null && samlResponseDocument != null) { this.sendToDestination(samlResponseDocument, relayState, destination, response, willSendRequest); return; } } catch (Exception e) { if (trace) log.trace("Server Exception:", e); throw new ServletException(ErrorCodes.SERVICE_PROVIDER_SERVER_EXCEPTION + "Server Exception"); } } } } public void init(FilterConfig filterConfig) throws ServletException { this.context = filterConfig.getServletContext(); InputStream is = context.getResourceAsStream(configFile); if (is != null) { try { picketLinkConfiguration = ConfigurationUtil.getConfiguration(is); spConfiguration = (SPType) picketLinkConfiguration.getIdpOrSP(); } catch (ParsingException e) { throw new RuntimeException(e); } } else { is = context.getResourceAsStream(GeneralConstants.DEPRECATED_CONFIG_FILE_LOCATION); if (is == null) throw new RuntimeException(ErrorCodes.SERVICE_PROVIDER_CONF_FILE_MISSING + configFile + " missing"); try { spConfiguration = ConfigurationUtil.getSPConfiguration(is); } catch (ParsingException e) { throw new RuntimeException(e); } } try { this.identityURL = spConfiguration.getIdentityURL(); this.serviceURL = spConfiguration.getServiceURL(); this.canonicalizationMethod = spConfiguration.getCanonicalizationMethod(); log.info("SPFilter:: Setting the CanonicalizationMethod on XMLSignatureUtil::" + canonicalizationMethod); XMLSignatureUtil.setCanonicalizationMethodType(canonicalizationMethod); log.trace("Identity Provider URL=" + this.identityURL); } catch (Exception e) { throw new RuntimeException(e); } // Get the Role Validator if configured String roleValidatorName = filterConfig.getInitParameter(GeneralConstants.ROLE_VALIDATOR); if (roleValidatorName != null && !"".equals(roleValidatorName)) { try { Class<?> clazz = SecurityActions.loadClass(getClass(), roleValidatorName); this.roleValidator = (IRoleValidator) clazz.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } Map<String, String> options = new HashMap<String, String>(); String roles = filterConfig.getInitParameter(GeneralConstants.ROLES); if (trace) log.trace("Found Roles in SPFilter config=" + roles); if (roles != null) { options.put("ROLES", roles); } this.roleValidator.intialize(options); String samlHandlerChainClass = filterConfig.getInitParameter("SAML_HANDLER_CHAIN_CLASS"); // Get the chain from config if (StringUtil.isNullOrEmpty(samlHandlerChainClass)) chain = SAML2HandlerChainFactory.createChain(); else try { chain = SAML2HandlerChainFactory.createChain(samlHandlerChainClass); } catch (ProcessingException e1) { throw new ServletException(e1); } try { // Get the handlers String handlerConfigFileName = GeneralConstants.HANDLER_CONFIG_FILE_LOCATION; Handlers handlers = null; if (picketLinkConfiguration != null) { handlers = picketLinkConfiguration.getHandlers(); } else { handlers = ConfigurationUtil.getHandlers(context.getResourceAsStream(handlerConfigFileName)); } chain.addAll(HandlerUtil.getHandlers(handlers)); Map<String, Object> chainConfigOptions = new HashMap<String, Object>(); chainConfigOptions.put(GeneralConstants.CONFIGURATION, spConfiguration); chainConfigOptions.put(GeneralConstants.ROLE_VALIDATOR, roleValidator); SAML2HandlerChainConfig handlerChainConfig = new DefaultSAML2HandlerChainConfig(chainConfigOptions); Set<SAML2Handler> samlHandlers = chain.handlers(); for (SAML2Handler handler : samlHandlers) { handler.initChainConfig(handlerChainConfig); } } catch (Exception e) { throw new RuntimeException(e); } String ignoreSigString = filterConfig.getInitParameter(GeneralConstants.IGNORE_SIGNATURES); if (ignoreSigString != null && !"".equals(ignoreSigString)) { this.ignoreSignatures = Boolean.parseBoolean(ignoreSigString); } if (ignoreSignatures == false) { KeyProviderType keyProvider = this.spConfiguration.getKeyProvider(); if (keyProvider == null) throw new RuntimeException(ErrorCodes.NULL_VALUE + "KeyProvider"); try { String keyManagerClassName = keyProvider.getClassName(); if (keyManagerClassName == null) throw new RuntimeException(ErrorCodes.NULL_VALUE + "KeyManager class name"); Class<?> clazz = SecurityActions.loadClass(getClass(), keyManagerClassName); this.keyManager = (TrustKeyManager) clazz.newInstance(); List<AuthPropertyType> authProperties = CoreConfigUtil.getKeyProviderProperties(keyProvider); keyManager.setAuthProperties(authProperties); keyManager.setValidatingAlias(keyProvider.getValidatingAlias()); } catch (Exception e) { log.error("Exception reading configuration:", e); throw new RuntimeException(e.getLocalizedMessage()); } log.trace("Key Provider=" + keyProvider.getClassName()); } // see if a global logout page has been configured String gloPage = filterConfig.getInitParameter(GeneralConstants.LOGOUT_PAGE); if (gloPage != null && !"".equals(gloPage)) this.logOutPage = gloPage; } /** * Create a SAML2 auth request * * @param serviceURL URL of the service * @param identityURL URL of the identity provider * @return * @throws ConfigurationException */ private AuthnRequestType createSAMLRequest(String serviceURL, String identityURL) throws ConfigurationException { if (serviceURL == null) throw new IllegalArgumentException(ErrorCodes.NULL_ARGUMENT + "serviceURL"); if (identityURL == null) throw new IllegalArgumentException(ErrorCodes.NULL_ARGUMENT + "identityURL"); SAML2Request saml2Request = new SAML2Request(); String id = IDGenerator.create("ID_"); return saml2Request.createAuthnRequestType(id, serviceURL, identityURL, serviceURL); } protected void sendRequestToIDP(AuthnRequestType authnRequest, String relayState, HttpServletResponse response) throws IOException, SAXException, GeneralSecurityException { SAML2Request saml2Request = new SAML2Request(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); saml2Request.marshall(authnRequest, baos); String samlMessage = PostBindingUtil.base64Encode(baos.toString()); String destination = authnRequest.getDestination().toASCIIString(); PostBindingUtil.sendPost(new DestinationInfoHolder(destination, samlMessage, relayState), response, true); } protected void sendToDestination(Document samlDocument, String relayState, String destination, HttpServletResponse response, boolean request) throws IOException, SAXException, GeneralSecurityException { if (!ignoreSignatures) { SAML2Signature samlSignature = new SAML2Signature(); Node nextSibling = samlSignature.getNextSiblingOfIssuer(samlDocument); if (nextSibling != null) { samlSignature.setNextSibling(nextSibling); } KeyPair keypair = keyManager.getSigningKeyPair(); samlSignature.signSAMLDocument(samlDocument, keypair); } String samlMessage = PostBindingUtil.base64Encode(DocumentUtil.getDocumentAsString(samlDocument)); PostBindingUtil.sendPost(new DestinationInfoHolder(destination, samlMessage, relayState), response, request); } protected boolean validate(HttpServletRequest request) throws IOException, GeneralSecurityException { return request.getParameter("SAMLResponse") != null; } protected boolean verifySignature(SAMLDocumentHolder samlDocumentHolder) throws IssuerNotTrustedException { Document samlResponse = samlDocumentHolder.getSamlDocument(); SAML2Object samlObject = samlDocumentHolder.getSamlObject(); String issuerID = null; if (samlObject instanceof StatusResponseType) { issuerID = ((StatusResponseType) samlObject).getIssuer().getValue(); } else { issuerID = ((RequestAbstractType) samlObject).getIssuer().getValue(); } if (issuerID == null) throw new IssuerNotTrustedException(ErrorCodes.NULL_VALUE + "IssuerID missing"); URL issuerURL; try { issuerURL = new URL(issuerID); } catch (MalformedURLException e1) { throw new IssuerNotTrustedException(e1); } try { PublicKey publicKey = keyManager.getValidatingKey(issuerURL.getHost()); log.trace("Going to verify signature in the saml response from IDP"); boolean sigResult = XMLSignatureUtil.validate(samlResponse, publicKey); log.trace("Signature verification=" + sigResult); return sigResult; } catch (TrustKeyConfigurationException e) { log.error("Unable to verify signature", e); } catch (TrustKeyProcessingException e) { log.error("Unable to verify signature", e); } catch (MarshalException e) { log.error("Unable to verify signature", e); } catch (XMLSignatureException e) { log.error("Unable to verify signature", e); } return false; } protected void isTrusted(String issuer) throws IssuerNotTrustedException { try { URL url = new URL(issuer); String issuerDomain = url.getHost(); TrustType idpTrust = spConfiguration.getTrust(); if (idpTrust != null) { String domainsTrusted = idpTrust.getDomains(); if (domainsTrusted.indexOf(issuerDomain) < 0) throw new IssuerNotTrustedException(issuer); } } catch (Exception e) { throw new IssuerNotTrustedException(e.getLocalizedMessage(), e); } } protected ResponseType decryptAssertion(ResponseType responseType) { throw new RuntimeException(ErrorCodes.PROCESSING_EXCEPTION + "This filter does not handle encryption"); } /** * Handle the SAMLResponse from the IDP * * @param request entire request from IDP * @param responseType ResponseType that has been generated * @param serverEnvironment tomcat,jboss etc * @return * @throws AssertionExpiredException */ public Principal handleSAMLResponse(HttpServletRequest request, ResponseType responseType) throws ConfigurationException, AssertionExpiredException { if (request == null) throw new IllegalArgumentException(ErrorCodes.NULL_ARGUMENT + "request"); if (responseType == null) throw new IllegalArgumentException(ErrorCodes.NULL_ARGUMENT + "response type"); StatusType statusType = responseType.getStatus(); if (statusType == null) throw new IllegalArgumentException(ErrorCodes.NULL_VALUE + "Status Type from the IDP"); String statusValue = statusType.getStatusCode().getValue().toASCIIString(); if (JBossSAMLURIConstants.STATUS_SUCCESS.get().equals(statusValue) == false) throw new SecurityException(ErrorCodes.IDP_AUTH_FAILED + "IDP forbid the user"); List<org.picketlink.identity.federation.saml.v2.protocol.ResponseType.RTChoiceType> assertions = responseType .getAssertions(); if (assertions.size() == 0) throw new IllegalStateException(ErrorCodes.NULL_VALUE + "No assertions in reply from IDP"); AssertionType assertion = assertions.get(0).getAssertion(); // Check for validity of assertion boolean expiredAssertion = AssertionUtil.hasExpired(assertion); if (expiredAssertion) throw new AssertionExpiredException(ErrorCodes.EXPIRED_ASSERTION); SubjectType subject = assertion.getSubject(); /* * JAXBElement<NameIDType> jnameID = (JAXBElement<NameIDType>) subject.getContent().get(0); NameIDType nameID = * jnameID.getValue(); */ NameIDType nameID = (NameIDType) subject.getSubType().getBaseID(); final String userName = nameID.getValue(); List<String> roles = new ArrayList<String>(); // Let us get the roles AttributeStatementType attributeStatement = (AttributeStatementType) assertion.getStatements().iterator().next(); List<ASTChoiceType> attList = attributeStatement.getAttributes(); for (ASTChoiceType obj : attList) { AttributeType attr = obj.getAttribute(); String roleName = (String) attr.getAttributeValue().get(0); roles.add(roleName); } Principal principal = new Principal() { public String getName() { return userName; } }; // Validate the roles boolean validRole = roleValidator.userInRole(principal, roles); if (!validRole) { if (trace) log.trace("Invalid role:" + roles); principal = null; } return principal; } }