Package org.jboss.seam.security.external.saml

Source Code of org.jboss.seam.security.external.saml.SamlMessageSender

package org.jboss.seam.security.external.saml;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.Binder;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.jboss.solder.logging.Logger;
import org.jboss.seam.security.external.Base64;
import org.jboss.seam.security.external.JaxbContext;
import org.jboss.seam.security.external.ResponseHandler;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.AuthnRequestType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.LogoutRequestType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.ObjectFactory;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.RequestAbstractType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.ResponseType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.StatusResponseType;
import org.jboss.seam.security.external.saml.api.SamlBinding;
import org.jboss.seam.security.external.saml.sp.SamlExternalIdentityProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
* @author Marcel Kolsteren
*/
@ApplicationScoped
public class SamlMessageSender {
    @Inject
    private Logger log;

    @Inject
    private Instance<SamlEntityBean> samlEntityBean;

    @Inject
    private SamlSignatureUtilForPostBinding signatureUtilForPostBinding;

    @Inject
    private SamlSignatureUtilForRedirectBinding samlSignatureUtilForRedirectBinding;

    @Inject
    private ResponseHandler responseHandler;

    @Inject
    @JaxbContext({RequestAbstractType.class, StatusResponseType.class})
    private JAXBContext jaxbContext;

    @Inject
    private Instance<SamlDialogue> samlDialogue;

    public void sendRequest(SamlExternalEntity samlProvider, SamlProfile profile, RequestAbstractType samlRequest, HttpServletResponse response) {
        Document message = null;

        SamlService service = samlProvider.getService(profile);
        SamlEndpoint endpoint = getEndpoint(service);

        try {
            samlRequest.setDestination(endpoint.getLocation());

            JAXBElement<?> requestElement;
            if (samlRequest instanceof AuthnRequestType) {
                AuthnRequestType authnRequest = (AuthnRequestType) samlRequest;
                requestElement = new ObjectFactory().createAuthnRequest(authnRequest);
            } else if (samlRequest instanceof LogoutRequestType) {
                LogoutRequestType logoutRequest = (LogoutRequestType) samlRequest;
                requestElement = new ObjectFactory().createLogoutRequest(logoutRequest);
            } else {
                throw new RuntimeException("Currently only authentication and logout requests can be sent");
            }

            Binder<Node> binder = jaxbContext.createBinder();

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            factory.setXIncludeAware(true);
            DocumentBuilder builder;
            builder = factory.newDocumentBuilder();
            message = builder.newDocument();

            binder.marshal(requestElement, message);
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }

        sendMessage(samlProvider, message, SamlRequestOrResponse.REQUEST, endpoint, response);
    }

    public void sendResponse(SamlExternalEntity samlProvider, StatusResponseType samlResponse, SamlProfile profile, HttpServletResponse response) {
        Document message = null;

        SamlService service = samlProvider.getService(profile);
        SamlEndpoint endpoint = getEndpoint(service);

        try {
            samlResponse.setDestination(endpoint.getResponseLocation());

            JAXBElement<? extends StatusResponseType> responseElement;
            if (endpoint.getService().getProfile().equals(SamlProfile.SINGLE_LOGOUT)) {
                responseElement = new ObjectFactory().createLogoutResponse(samlResponse);
            } else {
                responseElement = new ObjectFactory().createResponse((ResponseType) samlResponse);
            }

            Binder<Node> binder = jaxbContext.createBinder();

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            factory.setXIncludeAware(true);
            DocumentBuilder builder;
            builder = factory.newDocumentBuilder();
            message = builder.newDocument();

            binder.marshal(responseElement, message);
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }

        sendMessage(samlDialogue.get().getExternalProvider(), message, SamlRequestOrResponse.RESPONSE, endpoint, response);
    }

    public SamlEndpoint getEndpoint(SamlService service) {
        SamlEndpoint endpoint = service.getEndpointForBinding(samlEntityBean.get().getPreferredBinding());
        if (endpoint == null) {
            // Preferred binding not available. Use the other binding.
            endpoint = service.getEndpointForBinding(samlEntityBean.get().getPreferredBinding() == SamlBinding.HTTP_Post ? SamlBinding.HTTP_Redirect : SamlBinding.HTTP_Post);
        }
        if (endpoint == null) {
            throw new RuntimeException("No endpoint found for profile " + service.getProfile());
        }
        return endpoint;
    }

    private void sendMessage(SamlExternalEntity samlProvider, Document message, SamlRequestOrResponse samlRequestOrResponse, SamlEndpoint endpoint, HttpServletResponse response) {
        log.debug("Sending " + samlRequestOrResponse + ": " + SamlUtils.getDocumentAsString(message));

        try {
            boolean signMessage;

            if (endpoint.getService().getProfile() == SamlProfile.SINGLE_SIGN_ON) {
                if (samlEntityBean.get().getIdpOrSp() == SamlIdpOrSp.SP) {
                    signMessage = ((SamlExternalIdentityProvider) samlProvider).isWantAuthnRequestsSigned();
                } else {
                    signMessage = true;
                }
            } else {
                signMessage = samlEntityBean.get().isSingleLogoutMessagesSigned();
            }

            if (endpoint.getBinding() == SamlBinding.HTTP_Redirect) {
                byte[] responseBytes = SamlUtils.getDocumentAsString(message).getBytes("UTF-8");

                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                Deflater deflater = new Deflater(Deflater.DEFLATED, true);
                DeflaterOutputStream deflaterStream = new DeflaterOutputStream(baos, deflater);
                deflaterStream.write(responseBytes);
                deflaterStream.finish();

                byte[] deflatedMsg = baos.toByteArray();
                String base64EncodedResponse = Base64.encodeBytes(deflatedMsg, Base64.DONT_BREAK_LINES);

                PrivateKey privateKey = null;
                if (signMessage) {
                    privateKey = samlEntityBean.get().getSigningKey().getPrivateKey();
                }
                sendSamlRedirect(base64EncodedResponse, signMessage, samlRequestOrResponse, privateKey, endpoint, response);
            } else {
                if (signMessage) {
                    PublicKey publicKey = samlEntityBean.get().getSigningKey().getCertificate().getPublicKey();
                    PrivateKey privateKey = samlEntityBean.get().getSigningKey().getPrivateKey();
                    signatureUtilForPostBinding.sign(message, new KeyPair(publicKey, privateKey));
                }
                byte[] messageBytes = SamlUtils.getDocumentAsString(message).getBytes("UTF-8");

                String base64EncodedMessage = Base64.encodeBytes(messageBytes, Base64.DONT_BREAK_LINES);

                SamlPostMessage samlPostMessage = new SamlPostMessage();
                samlPostMessage.setRequestOrResponse(samlRequestOrResponse);
                samlPostMessage.setSamlMessage(base64EncodedMessage);
                samlPostMessage.setRelayState(samlDialogue.get().getExternalProviderRelayState());
                responseHandler.sendFormToUserAgent(endpoint.getLocation(), samlPostMessage, response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void sendSamlRedirect(String base64EncodedSamlMessage, boolean sign, SamlRequestOrResponse samlRequestOrResponse, PrivateKey signingKey, SamlEndpoint endpoint, HttpServletResponse response) {
        SamlRedirectMessage redirectMessage = new SamlRedirectMessage();

        if (sign) {
            try {
                redirectMessage.setRequestOrResponse(samlRequestOrResponse);
                redirectMessage.setSamlMessage(base64EncodedSamlMessage);
                redirectMessage.setRelayState(samlDialogue.get().getExternalProviderRelayState());

                samlSignatureUtilForRedirectBinding.sign(redirectMessage, signingKey);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            }
        } else {
            redirectMessage.setRequestOrResponse(samlRequestOrResponse);
            redirectMessage.setSamlMessage(base64EncodedSamlMessage);
        }

        responseHandler.sendHttpRedirectToUserAgent(endpoint.getLocation(), redirectMessage, response);
    }

}
TOP

Related Classes of org.jboss.seam.security.external.saml.SamlMessageSender

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.