PostBinding.java 9.17 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  javax.servlet.ServletOutputStream
 *  javax.servlet.http.HttpServletRequest
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.xml.security.exceptions.Base64DecodingException
 *  org.apache.xml.security.utils.Base64
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.auth.saml.binding;

import com.adobe.granite.auth.saml.binding.MessageContext;
import com.adobe.granite.auth.saml.binding.RequestBinding;
import com.adobe.granite.auth.saml.binding.ResponseBinding;
import com.adobe.granite.auth.saml.configuration.IdpConfiguration;
import com.adobe.granite.auth.saml.configuration.SpConfiguration;
import com.adobe.granite.auth.saml.model.AuthnRequest;
import com.adobe.granite.auth.saml.model.LogoutRequest;
import com.adobe.granite.auth.saml.model.LogoutResponse;
import com.adobe.granite.auth.saml.model.Message;
import com.adobe.granite.auth.saml.util.SamlReader;
import com.adobe.granite.auth.saml.util.SamlReaderException;
import com.adobe.granite.auth.saml.util.SamlWriter;
import com.adobe.granite.auth.saml.util.SamlWriterException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.PublicKey;
import java.security.cert.Certificate;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.xml.security.exceptions.Base64DecodingException;
import org.apache.xml.security.utils.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PostBinding
implements RequestBinding,
ResponseBinding {
    public static final String SAML_RESPONSE_PARAM = "SAMLResponse";
    public static final String SAML_REQUEST_PARAM = "SAMLRequest";
    public static final String RELAY_STATE_PARAM = "RelayState";
    public static final String ANCHOR_COOKIE = "anchor_backup";
    public static final String REQUEST_PATH_COOKIE = "saml_request_path";
    private SamlWriter samlWriter;
    private SamlReader samlReader;
    private final Logger log;

    public PostBinding() {
        this.log = LoggerFactory.getLogger(this.getClass());
        this.samlWriter = new SamlWriter();
        this.samlReader = new SamlReader();
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    @Override
    public MessageContext receive(MessageContext messageContext, HttpServletRequest httpRequest, KeyStore trustStore, KeyStore keyStore) throws IOException {
        String samlMessage = null;
        boolean isSamlRequest = false;
        if (httpRequest.getParameter("SAMLResponse") != null) {
            samlMessage = httpRequest.getParameter("SAMLResponse");
        } else if (httpRequest.getParameter("SAMLRequest") != null) {
            samlMessage = httpRequest.getParameter("SAMLRequest");
            isSamlRequest = true;
        }
        if (null == samlMessage || samlMessage.isEmpty()) {
            return null;
        }
        ByteArrayInputStream input = null;
        try {
            byte[] decodedResponse = Base64.decode((String)samlMessage);
            input = new ByteArrayInputStream(decodedResponse);
            Certificate cert = messageContext.getIdpConfiguration().getCertificate(trustStore);
            if (cert != null) {
                PublicKey idpPublicKey = cert.getPublicKey();
                Key decryptionKey = null;
                if (messageContext.getSpConfiguration().getUseEncryption()) {
                    decryptionKey = messageContext.getSpConfiguration().getDecryptionKey(keyStore);
                }
                Message response = this.samlReader.read(input, decryptionKey, idpPublicKey, isSamlRequest);
                messageContext.setMessage(response);
                String relayState = httpRequest.getParameter("RelayState");
                if (null != relayState) {
                    messageContext.setRelayState(relayState.getBytes());
                }
                MessageContext messageContext2 = messageContext;
                return messageContext2;
            }
            this.log.error("Unable to receive SAML message. Could not read IdP certificate from truststore.");
            MessageContext idpPublicKey = null;
            return idpPublicKey;
        }
        catch (Base64DecodingException e) {
            MessageContext response = null;
            return response;
        }
        catch (SamlReaderException e) {
            this.log.error("Unable to read SAML message.", (Throwable)e);
            MessageContext response = null;
            return response;
        }
        finally {
            if (null != input) {
                try {
                    input.close();
                }
                catch (IOException e) {
                    this.log.warn("Unable to close input stream while receiving SAML message.");
                }
            }
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    @Override
    public void send(MessageContext messageContext, HttpServletResponse httpResponse, Key privateKey) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            String postUrl;
            Message message = messageContext.getMessage();
            String parameterName = "SAMLRequest";
            if (message instanceof AuthnRequest) {
                postUrl = messageContext.getIdpConfiguration().getIdpPostUrl();
            } else if (message instanceof LogoutRequest) {
                postUrl = messageContext.getIdpConfiguration().getIdpLogoutPostUrl();
            } else if (message instanceof LogoutResponse) {
                postUrl = messageContext.getIdpConfiguration().getIdpLogoutPostUrl();
                parameterName = "SAMLResponse";
            } else {
                throw new RuntimeException("Messages of type " + message.getClass().getName() + " are not currently supported.");
            }
            this.samlWriter.write(message, out, privateKey);
            String encodedRequest = Base64.encode((byte[])out.toByteArray());
            StringBuilder builder = new StringBuilder();
            builder.append("<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>");
            builder.append("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>");
            builder.append("<head>");
            builder.append("<meta http-equiv='content-type' content='text/html; charset=utf-8' />");
            builder.append("<title>POST data</title>");
            builder.append("<script>    function setRequestPathCookies() {       var requestPath = escape(document.location.pathname);       var query = escape(document.location.search);       if (query) requestPath += \"?\"+query;       var hash = escape(document.location.hash.substring(1));       if (hash) document.cookie = \"anchor_backup=\"+hash+\";path=/;\";       document.cookie = \"saml_request_path=\"+requestPath+\";path=/;\";   }</script>");
            builder.append("</head>");
            builder.append("<body onload='setRequestPathCookies(); document.forms[0].submit();'>");
            builder.append("<noscript>");
            builder.append("<p><strong>Note:</strong> Since your browser does not support JavaScript, you must press the button below once to proceed.</p>");
            builder.append("</noscript>");
            builder.append("<form method='post' action='");
            builder.append(postUrl);
            builder.append("'>");
            byte[] relayState = messageContext.getRelayState();
            if (null != relayState && 0 < relayState.length) {
                builder.append("<input type='hidden' name='");
                builder.append("RelayState");
                builder.append("' value='");
                builder.append(new String(relayState));
                builder.append("' />");
            }
            builder.append("<input type='hidden' name='");
            builder.append(parameterName);
            builder.append("' value='");
            builder.append(encodedRequest);
            builder.append("' />");
            builder.append("<noscript><input type='submit' value='Submit' /></noscript>");
            builder.append("</form>");
            builder.append("</body>");
            builder.append("</html>");
            httpResponse.setContentType("text/html");
            httpResponse.addHeader("cache-control", "private, max-age=0, no-cache, no-store");
            httpResponse.getOutputStream().print(builder.toString());
            httpResponse.flushBuffer();
        }
        catch (SamlWriterException e) {
            this.log.error("Fatal error while sending Authn request.", (Throwable)e);
            httpResponse.sendError(500, "Internal server error, please contact your administrator");
        }
        finally {
            try {
                out.close();
            }
            catch (IOException e) {
                this.log.warn("Could not close output stream while sending Authn request.");
            }
        }
    }
}