Java tutorial
/* * Asimba Server * * Copyright (C) 2012 Asimba * Copyright (C) 2007-2008 Alfa & Ariss B.V. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see www.gnu.org/licenses * * Asimba - Serious Open Source SSO - More information on www.asimba.org * */ package com.alfaariss.oa.util.saml2.binding.artifact; import java.io.IOException; import java.util.List; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.opensaml.Configuration; import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.SAMLMessageContext; import org.opensaml.common.binding.artifact.SAMLArtifactMap; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.binding.artifact.AbstractSAML2Artifact; import org.opensaml.saml2.binding.artifact.SAML2ArtifactBuilder; import org.opensaml.saml2.binding.artifact.SAML2ArtifactType0004; import org.opensaml.saml2.binding.encoding.BaseSAML2MessageEncoder; import org.opensaml.saml2.core.NameID; import org.opensaml.util.URLBuilder; import org.opensaml.ws.message.MessageContext; import org.opensaml.ws.message.encoder.MessageEncodingException; import org.opensaml.ws.transport.InTransport; import org.opensaml.ws.transport.http.HTTPOutTransport; import org.opensaml.ws.transport.http.HTTPTransportUtils; import org.opensaml.ws.transport.http.HttpServletRequestAdapter; import org.opensaml.ws.transport.http.HttpServletResponseAdapter; import org.opensaml.xml.io.MarshallingException; import org.opensaml.xml.util.Pair; import com.alfaariss.oa.util.saml2.SAML2Constants; /** * JSP base HTTP Artifact encoder. * * Encodes artifacts using HTTP redirect or HTTP POST using a JSP template * instead of the velocity template engine. * * <br><br><i>Partitially based on sources from OpenSAML (www.opensaml.org).</i> * * @author EVB * @author Alfa & Ariss */ public class JSPHTTPArtifactEncoder extends BaseSAML2MessageEncoder { /** logger */ private static final Log _logger = LogFactory.getLog(JSPHTTPArtifactEncoder.class); private final String _sTemplateLocation; /** Use POST encoding instead of GET. */ private boolean _bPostEncoding; /** Artifact map. */ private final SAMLArtifactMap _artifactMap; /** * Create a new <code>JSPHTTPArtifactEncoder</code> with the given template * and redirect encoding. * @param sTemplateLocation The JSp template for POST encoding. * @param map The artifact map to store artifact/message bindings. */ public JSPHTTPArtifactEncoder(String sTemplateLocation, SAMLArtifactMap map) { super(); _bPostEncoding = false; _sTemplateLocation = sTemplateLocation; _artifactMap = map; } /** * Retrieve the post binding value. * @return <code>true</code> if POST encoding will be used, * otherwise <code>false</code>. */ public boolean isPostEncoding() { return _bPostEncoding; } /** * Set the post binding value. * * @param post <code>true</code> if POST encoding shuld be used, * otherwise <code>false</code>. */ public void setPostEncoding(boolean post) { _bPostEncoding = post; } /** * Returns return {@link SAMLConstants#SAML2_ARTIFACT_BINDING_URI}. * @see org.opensaml.common.binding.encoding.SAMLMessageEncoder#getBindingURI() */ @Override public String getBindingURI() { return SAMLConstants.SAML2_ARTIFACT_BINDING_URI; } /** * No message confidentiality. * @see org.opensaml.ws.message.encoder.MessageEncoder#providesMessageConfidentiality(org.opensaml.ws.message.MessageContext) */ @Override public boolean providesMessageConfidentiality(MessageContext arg0) throws MessageEncodingException { return false; } /** * No message integrity. * @see org.opensaml.ws.message.encoder.MessageEncoder#providesMessageIntegrity(org.opensaml.ws.message.MessageContext) */ @Override public boolean providesMessageIntegrity(MessageContext arg0) throws MessageEncodingException { return false; } /** * Encodes the message using Artifact binding. * @see org.opensaml.ws.message.encoder.BaseMessageEncoder#doEncode(org.opensaml.ws.message.MessageContext) */ @SuppressWarnings("unchecked") @Override protected void doEncode(MessageContext messageContext) throws MessageEncodingException { assert messageContext != null : "messageContext is empty"; assert messageContext.getOutboundMessageTransport() != null : "outboundMessageTransport is empty"; try { if (!(messageContext instanceof SAMLMessageContext)) { _logger.error("Invalid message context type:" + messageContext.getClass().getSimpleName()); throw new MessageEncodingException("Invalid message context type"); } if (!(messageContext.getOutboundMessageTransport() instanceof HTTPOutTransport)) { _logger.error("Invalid outbound message transport type:" + messageContext.getOutboundMessageTransport().getClass().getSimpleName()); throw new MessageEncodingException("Invalid outbound message transport type"); } SAMLMessageContext<SAMLObject, SAMLObject, NameID> artifactContext = (SAMLMessageContext<SAMLObject, SAMLObject, NameID>) messageContext; HTTPOutTransport outTransport = (HTTPOutTransport) artifactContext.getOutboundMessageTransport(); outTransport.setCharacterEncoding(SAML2Constants.CHARSET); if (_bPostEncoding) { postEncode(artifactContext, outTransport); } else { getEncode(artifactContext, outTransport); } } catch (MessageEncodingException e) { throw e; } catch (Exception e) { _logger.error("Could not encode messagecontext", e); throw new MessageEncodingException("Internal error while encoding"); } } private void postEncode(SAMLMessageContext<SAMLObject, SAMLObject, NameID> artifactContext, HTTPOutTransport outTransport) throws MessageEncodingException { InTransport inTransport = artifactContext.getInboundMessageTransport(); HttpServletRequest request = ((HttpServletRequestAdapter) inTransport).getWrappedRequest(); HttpServletResponse response = ((HttpServletResponseAdapter) outTransport).getWrappedResponse(); request.setAttribute("action", getEndpointURL(artifactContext)); request.setAttribute("SAMLArt", buildArtifact(artifactContext).base64Encode()); if (checkRelayState(artifactContext.getRelayState())) { request.setAttribute("RelayState", HTTPTransportUtils.urlEncode(artifactContext.getRelayState())); } try { _logger.debug("Forward caller to JSP template"); RequestDispatcher oDispatcher = request.getRequestDispatcher(_sTemplateLocation); oDispatcher.forward(request, response); } catch (ServletException e) { _logger.warn("Could not process forward to JSP due to Servlet Error", e); throw new MessageEncodingException("Could not process forward to JSP"); } catch (IOException e) { _logger.warn("Could not process forward to JSP due to I/O Error", e); throw new MessageEncodingException("Could not process forward to JSP"); } } private void getEncode(SAMLMessageContext<SAMLObject, SAMLObject, NameID> artifactContext, HTTPOutTransport outTransport) throws MessageEncodingException { URLBuilder urlBuilder = getEndpointURL(artifactContext); List<Pair<String, String>> params = urlBuilder.getQueryParams(); params.add(new Pair<String, String>("SAMLart", buildArtifact(artifactContext).base64Encode())); if (checkRelayState(artifactContext.getRelayState())) { params.add(new Pair<String, String>("RelayState", artifactContext.getRelayState())); } outTransport.sendRedirect(urlBuilder.buildURL()); } private AbstractSAML2Artifact buildArtifact(SAMLMessageContext<SAMLObject, SAMLObject, NameID> artifactContext) throws MessageEncodingException { SAML2ArtifactBuilder<?> artifactBuilder; if (artifactContext.getOutboundMessageArtifactType() != null) { artifactBuilder = Configuration.getSAML2ArtifactBuilderFactory() .getArtifactBuilder(artifactContext.getOutboundMessageArtifactType()); } else { artifactBuilder = Configuration.getSAML2ArtifactBuilderFactory() .getArtifactBuilder(SAML2ArtifactType0004.TYPE_CODE); artifactContext.setOutboundMessageArtifactType(SAML2ArtifactType0004.TYPE_CODE); } AbstractSAML2Artifact artifact = artifactBuilder.buildArtifact(artifactContext); String encodedArtifact = artifact.base64Encode(); try { _artifactMap.put(encodedArtifact, artifactContext.getInboundMessageIssuer(), artifactContext.getOutboundMessageIssuer(), artifactContext.getOutboundSAMLMessage()); } catch (MarshallingException e) { _logger.error("Error while marshalling assertion to be represented as an artifact", e); throw new MessageEncodingException("Error while marshalling assertion"); } return artifact; } }