All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opensaml.saml.saml2.binding.encoding.impl.HTTPPostEncoder Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the University Corporation for Advanced Internet Development,
 * Inc. (UCAID) under one or more contributor license agreements.  See the
 * NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The UCAID licenses this file to You under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.opensaml.saml.saml2.binding.encoding.impl;

import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;

import javax.servlet.http.HttpServletResponse;

import net.shibboleth.utilities.java.support.codec.Base64Support;
import net.shibboleth.utilities.java.support.codec.EncodingException;
import net.shibboleth.utilities.java.support.codec.HTMLEncoder;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.net.HttpServletSupport;
import net.shibboleth.utilities.java.support.xml.SerializeSupport;

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.encoder.MessageEncodingException;
import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.common.binding.SAMLBindingSupport;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.core.RequestAbstractType;
import org.opensaml.saml.saml2.core.StatusResponseType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;

/**
 * SAML 2.0 HTTP Post binding message encoder.
 */
public class HTTPPostEncoder extends BaseSAML2MessageEncoder {
    
    /** Default template ID. */
    public static final String DEFAULT_TEMPLATE_ID = "/templates/saml2-post-binding.vm";

    /** Class logger. */
    private final Logger log = LoggerFactory.getLogger(HTTPPostEncoder.class);

    /** Velocity engine used to evaluate the template when performing POST encoding. */
    private VelocityEngine velocityEngine;

    /** ID of the Velocity template used when performing POST encoding. */
    private String velocityTemplateId;
    
    /** Constructor. */
    public HTTPPostEncoder() {
        setVelocityTemplateId(DEFAULT_TEMPLATE_ID);
    }

    /** {@inheritDoc} */
    public String getBindingURI() {
        return SAMLConstants.SAML2_POST_BINDING_URI;
    }
    
    /**
     * Get the VelocityEngine instance.
     * 
     * @return return the VelocityEngine instance
     */
    public VelocityEngine getVelocityEngine() {
        return velocityEngine;
    }

    /**
     * Set the VelocityEngine instance.
     * 
     * @param newVelocityEngine the new VelocityEngine instane
     */
    public void setVelocityEngine(final VelocityEngine newVelocityEngine) {
        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
        velocityEngine = newVelocityEngine;
    }
    
    /**
     * Get the Velocity template id.
     * 
     * 

Defaults to {@link #DEFAULT_TEMPLATE_ID}.

* * @return return the Velocity template id */ public String getVelocityTemplateId() { return velocityTemplateId; } /** * Set the Velocity template id. * *

Defaults to {@link #DEFAULT_TEMPLATE_ID}.

* * @param newVelocityTemplateId the new Velocity template id */ public void setVelocityTemplateId(final String newVelocityTemplateId) { ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this); ComponentSupport.ifDestroyedThrowDestroyedComponentException(this); velocityTemplateId = newVelocityTemplateId; } /** {@inheritDoc} */ protected void doDestroy() { velocityEngine = null; velocityTemplateId = null; super.doDestroy(); } /** {@inheritDoc} */ protected void doInitialize() throws ComponentInitializationException { super.doInitialize(); if (velocityEngine == null) { throw new ComponentInitializationException("VelocityEngine must be supplied"); } if (velocityTemplateId == null) { throw new ComponentInitializationException("Velocity template id must be supplied"); } } /** {@inheritDoc} */ protected void doEncode() throws MessageEncodingException { final MessageContext messageContext = getMessageContext(); final Object outboundMessage = messageContext.getMessage(); if (outboundMessage == null || !(outboundMessage instanceof SAMLObject)) { throw new MessageEncodingException("No outbound SAML message contained in message context"); } final String endpointURL = getEndpointURL(messageContext).toString(); postEncode(messageContext, endpointURL); } /** * Base64 and POST encodes the outbound message and writes it to the outbound transport. * * @param messageContext current message context * @param endpointURL endpoint URL to which to encode message * * @throws MessageEncodingException thrown if there is a problem encoding the message */ protected void postEncode(final MessageContext messageContext, final String endpointURL) throws MessageEncodingException { log.debug("Invoking Velocity template to create POST body"); try { final VelocityContext context = new VelocityContext(); populateVelocityContext(context, messageContext, endpointURL); final HttpServletResponse response = getHttpServletResponse(); HttpServletSupport.addNoCacheHeaders(response); HttpServletSupport.setUTF8Encoding(response); HttpServletSupport.setContentType(response, "text/html"); try (final Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8")) { velocityEngine.mergeTemplate(velocityTemplateId, "UTF-8", context, out); out.flush(); } } catch (final Exception e) { log.error("Error invoking Velocity template: {}", e.getMessage()); throw new MessageEncodingException("Error creating output document", e); } } /** * Populate the Velocity context instance which will be used to render the POST body. * * @param velocityContext the Velocity context instance to populate with data * @param messageContext the SAML message context source of data * @param endpointURL endpoint URL to which to encode message * @throws MessageEncodingException thrown if there is a problem encoding the message */ protected void populateVelocityContext(final VelocityContext velocityContext, final MessageContext messageContext, final String endpointURL) throws MessageEncodingException { final String encodedEndpointURL = HTMLEncoder.encodeForHTMLAttribute(endpointURL); log.debug("Encoding action url of '{}' with encoded value '{}'", endpointURL, encodedEndpointURL); velocityContext.put("action", encodedEndpointURL); velocityContext.put("binding", getBindingURI()); final SAMLObject outboundMessage = (SAMLObject) messageContext.getMessage(); log.debug("Marshalling and Base64 encoding SAML message"); final Element domMessage = marshallMessage(outboundMessage); try { final String messageXML = SerializeSupport.nodeToString(domMessage); final String encodedMessage = Base64Support.encode(messageXML.getBytes("UTF-8"), Base64Support.UNCHUNKED); if (outboundMessage instanceof RequestAbstractType) { velocityContext.put("SAMLRequest", encodedMessage); } else if (outboundMessage instanceof StatusResponseType) { velocityContext.put("SAMLResponse", encodedMessage); } else { throw new MessageEncodingException( "SAML message is neither a SAML RequestAbstractType or StatusResponseType"); } } catch (final UnsupportedEncodingException e) { log.error("UTF-8 encoding is not supported, this VM is not Java compliant"); throw new MessageEncodingException("Unable to encode message, UTF-8 encoding is not supported"); } catch (final EncodingException e) { log.error("Unable to base64 encode SAML message: {}",e.getMessage()); throw new MessageEncodingException("Unable to base64 encode SAML message",e); } final String relayState = SAMLBindingSupport.getRelayState(messageContext); if (SAMLBindingSupport.checkRelayState(relayState)) { final String encodedRelayState = HTMLEncoder.encodeForHTMLAttribute(relayState); log.debug("Setting RelayState parameter to: '{}', encoded as '{}'", relayState, encodedRelayState); velocityContext.put("RelayState", encodedRelayState); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy