/* * 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 java.io.IOException; import java.io.InputStream; import java.util.Set; import java.util.concurrent.locks.Lock; import javax.servlet.http.HttpServletResponse; import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request; 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.saml.v2.common.SAMLDocumentHolder; import org.picketlink.identity.federation.core.saml.v2.holders.DestinationInfoHolder; 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.SAML2HandlerRequest; import org.picketlink.identity.federation.core.saml.v2.interfaces.SAML2HandlerResponse; import org.picketlink.identity.federation.core.saml.v2.util.DocumentUtil; import org.picketlink.identity.federation.saml.v2.SAML2Object; import org.picketlink.identity.federation.web.core.HTTPContext; import org.picketlink.identity.federation.web.util.HTTPRedirectUtil; import org.picketlink.identity.federation.web.util.PostBindingUtil; import org.picketlink.identity.federation.web.util.RedirectBindingUtil; import org.picketlink.identity.federation.web.util.RedirectBindingUtil.RedirectBindingUtilDestHolder; import org.w3c.dom.Document; /** * Utility Class to handle processing of an SAML Request Message * * @author Anil.Saldhana@redhat.com * @since Oct 27, 2009 */ public class ServiceProviderSAMLRequestProcessor extends ServiceProviderBaseProcessor { /** * Construct * * @param postBinding Whether it is the Post Binding * @param serviceURL Service URL of the SP */ public ServiceProviderSAMLRequestProcessor(boolean postBinding, String serviceURL) { super(postBinding, serviceURL); } /** * Process the message * * @param samlRequest * @param httpContext * @param handlers * @param chainLock A Lock on the chain of handlers that needs to be used for locking * @return * @throws ProcessingException * @throws IOException * @throws ParsingException * @throws ConfigurationException */ public boolean process(String samlRequest, HTTPContext httpContext, Set<SAML2Handler> handlers, Lock chainLock) throws ProcessingException, IOException, ParsingException, ConfigurationException { SAML2Request saml2Request = new SAML2Request(); SAML2HandlerResponse saml2HandlerResponse = null; SAML2Object samlObject = null; SAMLDocumentHolder documentHolder = null; if (this.postBinding) { // we got a logout request from IDP InputStream is = PostBindingUtil.base64DecodeAsStream(samlRequest); samlObject = saml2Request.getSAML2ObjectFromStream(is); } else { InputStream is = RedirectBindingUtil.base64DeflateDecode(samlRequest); samlObject = saml2Request.getSAML2ObjectFromStream(is); } documentHolder = saml2Request.getSamlDocumentHolder(); // Create the request/response SAML2HandlerRequest saml2HandlerRequest = getSAML2HandlerRequest(documentHolder, httpContext); saml2HandlerResponse = new DefaultSAML2HandlerResponse(); saml2HandlerResponse.setPostBindingForResponse(postBinding); SAMLHandlerChainProcessor chainProcessor = new SAMLHandlerChainProcessor(handlers); // Set some request options setRequestOptions(saml2HandlerRequest); chainProcessor.callHandlerChain(samlObject, saml2HandlerRequest, saml2HandlerResponse, httpContext, chainLock); Document samlResponseDocument = saml2HandlerResponse.getResultingDocument(); String relayState = saml2HandlerResponse.getRelayState(); String destination = saml2HandlerResponse.getDestination(); boolean willSendRequest = saml2HandlerResponse.getSendRequest(); if (destination != null && samlResponseDocument != null) { if (postBinding) { sendRequestToIDP(destination, samlResponseDocument, relayState, httpContext.getResponse(), willSendRequest); } else { String destinationQuery = saml2HandlerResponse.getDestinationQueryStringWithSignature(); // This is the case with signatures disabled if (destinationQuery == null) { boolean areWeSendingRequest = saml2HandlerResponse.getSendRequest(); String samlMsg = DocumentUtil.getDocumentAsString(samlResponseDocument); String base64Request = RedirectBindingUtil.deflateBase64URLEncode(samlMsg.getBytes("UTF-8")); destinationQuery = RedirectBindingUtil.getDestinationQueryString(base64Request, relayState, areWeSendingRequest); } RedirectBindingUtilDestHolder holder = new RedirectBindingUtilDestHolder(); holder.setDestination(destination).setDestinationQueryString(destinationQuery); String destinationURL = RedirectBindingUtil.getDestinationURL(holder); HTTPRedirectUtil.sendRedirectForRequestor(destinationURL, httpContext.getResponse()); } return true; } return false; } /** * Send the request to the IDP * * @param destination idp url * @param samlDocument request or response document * @param relayState * @param response * @param willSendRequest are we sending Request or Response to IDP * @throws ProcessingException * @throws ConfigurationException * @throws IOException */ protected void sendRequestToIDP(String destination, Document samlDocument, String relayState, HttpServletResponse response, boolean willSendRequest) throws ProcessingException, ConfigurationException, IOException { String samlMessage = DocumentUtil.getDocumentAsString(samlDocument); samlMessage = PostBindingUtil.base64Encode(samlMessage); PostBindingUtil.sendPost(new DestinationInfoHolder(destination, samlMessage, relayState), response, willSendRequest); } }