/* * 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.process; import static org.picketlink.identity.federation.core.util.StringUtil.isNotNull; import java.io.IOException; import java.net.URL; import java.security.PublicKey; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.locks.Lock; import javax.servlet.http.HttpServletRequest; import org.picketlink.identity.federation.PicketLinkLogger; import org.picketlink.identity.federation.PicketLinkLoggerFactory; import org.picketlink.identity.federation.core.audit.PicketLinkAuditHelper; import org.picketlink.identity.federation.core.config.ProviderType; import org.picketlink.identity.federation.core.config.SPType; import org.picketlink.identity.federation.core.exceptions.ConfigurationException; import org.picketlink.identity.federation.core.exceptions.ParsingException; import org.picketlink.identity.federation.core.exceptions.ProcessingException; import org.picketlink.identity.federation.core.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.SAMLDocumentHolder; import org.picketlink.identity.federation.core.saml.v2.holders.IssuerInfoHolder; 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.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.util.StringUtil; import org.picketlink.identity.federation.web.constants.GeneralConstants; import org.picketlink.identity.federation.web.core.HTTPContext; /** * A processor util at the SP * * @author Anil.Saldhana@redhat.com * @since Oct 27, 2009 */ public class ServiceProviderBaseProcessor { protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); protected boolean postBinding; protected String serviceURL; protected String identityURL; protected ProviderType spConfiguration; protected TrustKeyManager keyManager; protected String issuer = null; protected PicketLinkAuditHelper auditHelper = null; public static final String IDP_KEY = "idp.key"; /** * Construct * * @param postBinding Whether it is the Post Binding * @param serviceURL Service URL of the SP */ public ServiceProviderBaseProcessor(boolean postBinding, String serviceURL) { this.postBinding = postBinding; this.serviceURL = serviceURL; } /** * Set the SP configuration * * @param sp */ public void setConfiguration(ProviderType sp) { this.spConfiguration = sp; } /** * Set the {@code TrustKeyManager} * * @param tkm */ public void setTrustKeyManager(TrustKeyManager tkm) { this.keyManager = tkm; } /** * Set the Identity URL * * @param identityURL */ public void setIdentityURL(String identityURL) { this.identityURL = identityURL; } /** * Set a separate issuer that is different from the service url * * @param issuer */ public void setIssuer(String issuer) { this.issuer = issuer; } /** * Set the {@link PicketLinkAuditHelper} * @param helper */ public void setAuditHelper(PicketLinkAuditHelper helper){ this.auditHelper = helper; } public SAML2HandlerResponse process(HTTPContext httpContext, Set<SAML2Handler> handlers, Lock chainLock) throws ProcessingException, IOException, ParsingException, ConfigurationException { logger.trace("SAML Handlers are: " + handlers); // Neither saml request nor response from IDP // So this is a user request // Ask the handler chain to generate the saml request // Create the request/response SAML2HandlerRequest saml2HandlerRequest = getSAML2HandlerRequest(null, httpContext); saml2HandlerRequest.addOption(GeneralConstants.CONTEXT_PATH, httpContext.getServletContext().getContextPath()); saml2HandlerRequest.addOption(GeneralConstants.SUPPORTS_SIGNATURES, this.spConfiguration.isSupportsSignature()); SAML2HandlerResponse saml2HandlerResponse = new DefaultSAML2HandlerResponse(); saml2HandlerResponse.setPostBindingForResponse(postBinding); saml2HandlerResponse.setDestination(identityURL); // if the request is a GLO. Check if there is a specific URL for logout. if (isLogOutRequest(httpContext)) { String logoutUrl = ((SPType) this.spConfiguration).getLogoutUrl(); if (logoutUrl != null) { saml2HandlerResponse.setDestination(logoutUrl); } } // Reset the state try { chainLock.lock(); for (SAML2Handler handler : handlers) { handler.reset(); if (saml2HandlerResponse.isInError()) { httpContext.getResponse().sendError(saml2HandlerResponse.getErrorCode()); break; } if (isLogOutRequest(httpContext)) saml2HandlerRequest.setTypeOfRequestToBeGenerated(GENERATE_REQUEST_TYPE.LOGOUT); else saml2HandlerRequest.setTypeOfRequestToBeGenerated(GENERATE_REQUEST_TYPE.AUTH); handler.generateSAMLRequest(saml2HandlerRequest, saml2HandlerResponse); logger.trace("Finished Processing handler: " + handler.getClass().getCanonicalName()); } } catch (ProcessingException pe) { logger.error(pe); throw logger.samlHandlerChainProcessingError(pe); } finally { chainLock.unlock(); } return saml2HandlerResponse; } protected SAML2HandlerRequest getSAML2HandlerRequest(SAMLDocumentHolder documentHolder, HTTPContext httpContext) { IssuerInfoHolder holder = null; if (issuer == null) { holder = new IssuerInfoHolder(this.serviceURL); } else { holder = new IssuerInfoHolder(issuer); } return new DefaultSAML2HandlerRequest(httpContext, holder.getIssuer(), documentHolder, HANDLER_TYPE.SP); } protected boolean isLogOutRequest(HTTPContext httpContext) { HttpServletRequest request = httpContext.getRequest(); String gloStr = request.getParameter(GeneralConstants.GLOBAL_LOGOUT); return isNotNull(gloStr) && "true".equalsIgnoreCase(gloStr); } protected URL safeURL(String urlString) { try { return new URL(urlString); } catch (Exception e) { } return null; } /** * <p> * Returns the PublicKey to be used to verify signatures for SAML tokens issued by the IDP. * </p> * * @return * @throws org.picketlink.identity.federation.core.interfaces.TrustKeyConfigurationException * @throws org.picketlink.identity.federation.core.interfaces.TrustKeyProcessingException */ protected PublicKey getIDPPublicKey() throws TrustKeyConfigurationException, TrustKeyProcessingException { if (this.keyManager == null) { throw logger.trustKeyManagerMissing(); } String idpValidatingAlias = (String) this.keyManager.getAdditionalOption(ServiceProviderBaseProcessor.IDP_KEY); if (StringUtil.isNullOrEmpty(idpValidatingAlias)) { idpValidatingAlias = safeURL(spConfiguration.getIdentityURL()).getHost(); } return keyManager.getValidatingKey(idpValidatingAlias); } protected void setRequestOptions(SAML2HandlerRequest saml2HandlerRequest) throws TrustKeyConfigurationException, TrustKeyProcessingException { if (spConfiguration != null) { Map<String, Object> requestOptions = new HashMap<String, Object>(); requestOptions.put(GeneralConstants.CONFIGURATION, spConfiguration); if(auditHelper != null){ requestOptions.put(GeneralConstants.AUDIT_HELPER, auditHelper); } if (keyManager != null) { PublicKey validatingKey = getIDPPublicKey(); requestOptions.put(GeneralConstants.SENDER_PUBLIC_KEY, validatingKey); requestOptions.put(GeneralConstants.DECRYPTING_KEY, keyManager.getSigningKey()); } requestOptions.put(GeneralConstants.SUPPORTS_SIGNATURES, this.spConfiguration.isSupportsSignature()); saml2HandlerRequest.setOptions(requestOptions); } } }