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

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

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

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
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.InvalidRequestException;
import org.jboss.seam.security.external.JaxbContext;
import org.jboss.seam.security.external.dialogues.api.DialogueManager;
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.idp.SamlIdpBeanApi;
import org.jboss.seam.security.external.saml.idp.SamlIdpSingleLogoutService;
import org.jboss.seam.security.external.saml.idp.SamlIdpSingleSignOnService;
import org.jboss.seam.security.external.saml.sp.SamlSpBeanApi;
import org.jboss.seam.security.external.saml.sp.SamlSpSingleLogoutService;
import org.jboss.seam.security.external.saml.sp.SamlSpSingleSignOnService;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

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

    @Inject
    private DialogueManager dialogueManager;

    @Inject
    private Instance<SamlDialogue> samlDialogue;

    @Inject
    private SamlSpSingleLogoutService samlSpSingleLogoutService;

    @Inject
    private SamlIdpSingleLogoutService samlIdpSingleLogoutService;

    @Inject
    private SamlSpSingleSignOnService samlSpSingleSignOnService;

    @Inject
    private SamlIdpSingleSignOnService samlIdpSingleSignOnService;

    @Inject
    private Instance<SamlEntityBean> samlEntityBean;

    @Inject
    private Instance<SamlSpBeanApi> samlSpBean;

    @Inject
    private Instance<SamlIdpBeanApi> samlIdpBean;

    @Inject
    private SamlSignatureUtilForPostBinding signatureUtilForPostBinding;

    @Inject
    private SamlSignatureUtilForRedirectBinding signatureUtilForRedirectBinding;

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

    public void handleIncomingSamlMessage(SamlServiceType service, HttpServletRequest httpRequest, HttpServletResponse httpResponse, SamlIdpOrSp idpOrSp) throws InvalidRequestException {
        String samlRequestParam = httpRequest.getParameter(SamlRedirectMessage.QSP_SAML_REQUEST);
        String samlResponseParam = httpRequest.getParameter(SamlRedirectMessage.QSP_SAML_RESPONSE);

        SamlRequestOrResponse samlRequestOrResponse;
        String samlMessage;

        if (samlRequestParam != null && samlResponseParam == null) {
            samlMessage = samlRequestParam;
            samlRequestOrResponse = SamlRequestOrResponse.REQUEST;
        } else if (samlRequestParam == null && samlResponseParam != null) {
            samlMessage = samlResponseParam;
            samlRequestOrResponse = SamlRequestOrResponse.RESPONSE;
        } else {
            throw new InvalidRequestException("SAML message should either have a SAMLRequest parameter or a SAMLResponse parameter");
        }

        InputStream is;
        if (httpRequest.getMethod().equals("POST")) {
            byte[] decodedMessage = Base64.decode(samlMessage);
            is = new ByteArrayInputStream(decodedMessage);
        } else {
            byte[] base64Decoded = Base64.decode(samlMessage);
            ByteArrayInputStream bais = new ByteArrayInputStream(base64Decoded);
            is = new InflaterInputStream(bais, new Inflater(true));
        }

        Document document = getDocument(is);
        String issuerEntityId;
        RequestAbstractType samlRequestMessage = null;
        StatusResponseType samlResponseMessage = null;
        if (samlRequestOrResponse.isRequest()) {
            samlRequestMessage = getSamlRequest(document);
            issuerEntityId = samlRequestMessage.getIssuer().getValue();
        } else {
            samlResponseMessage = getSamlResponse(document);
            issuerEntityId = samlResponseMessage.getIssuer().getValue();
        }
        log.debug("Received: " + SamlUtils.getDocumentAsString(document));

        try {
            if (samlRequestOrResponse.isRequest() || samlResponseMessage.getInResponseTo() == null) {
                // Request or unsolicited response

                String destination = samlRequestOrResponse.isRequest() ? samlRequestMessage.getDestination() : samlResponseMessage.getDestination();
                if (!samlEntityBean.get().getServiceURL(service).equals(destination)) {
                    throw new InvalidRequestException("Destination (" + destination + ") is not valid.");
                }

                dialogueManager.beginDialogue();
                samlDialogue.get().setExternalProviderMessageId(samlRequestOrResponse.isRequest() ? samlRequestMessage.getID() : samlResponseMessage.getID());
                SamlExternalEntity externalProvider = samlEntityBean.get().getExternalSamlEntityByEntityId(issuerEntityId);
                if (externalProvider == null) {
                    throw new InvalidRequestException("Received message from unknown entity id " + issuerEntityId);
                }
                samlDialogue.get().setExternalProvider(externalProvider);
            } else {
                String dialogueId = samlResponseMessage.getInResponseTo();
                if (!dialogueManager.isExistingDialogue(dialogueId)) {
                    throw new InvalidRequestException("No request that corresponds with the received response");
                }

                dialogueManager.attachDialogue(dialogueId);
                if (!(samlDialogue.get().getExternalProvider().getEntityId().equals(issuerEntityId))) {
                    throw new InvalidRequestException("Identity samlEntityBean of request and response do not match");
                }
            }

            SamlExternalEntity externalProvider = samlEntityBean.get().getExternalSamlEntityByEntityId(issuerEntityId);

            boolean validate;
            if (samlRequestOrResponse.isRequest()) {
                if (service.getProfile() == SamlProfile.SINGLE_SIGN_ON) {
                    if (idpOrSp == SamlIdpOrSp.IDP) {
                        validate = samlIdpBean.get().isWantAuthnRequestsSigned();
                    } else {
                        validate = samlSpBean.get().isWantAssertionsSigned();
                    }
                } else {
                    if (idpOrSp == SamlIdpOrSp.IDP) {
                        validate = samlIdpBean.get().isWantSingleLogoutMessagesSigned();
                    } else {
                        validate = samlSpBean.get().isWantSingleLogoutMessagesSigned();
                    }
                }
            } else {
                validate = samlResponseMessage instanceof ResponseType;
            }

            if (validate) {
                if (httpRequest.getMethod().equals("POST")) {
                    signatureUtilForPostBinding.validateSignature(externalProvider.getPublicKey(), document);
                } else {
                    SamlRedirectMessage redirectMessage = new SamlRedirectMessage(samlRequestOrResponse, httpRequest);
                    signatureUtilForRedirectBinding.validateSignature(redirectMessage, externalProvider.getPublicKey());
                }
            }

            if (service.getProfile() == SamlProfile.SINGLE_SIGN_ON) {
                if (samlRequestOrResponse.isRequest()) {
                    samlIdpSingleSignOnService.processSPRequest(httpRequest, httpResponse, samlRequestMessage);
                } else {
                    samlSpSingleSignOnService.processIDPResponse(httpRequest, httpResponse, samlResponseMessage);
                }
            } else {
                if (samlRequestOrResponse.isRequest()) {
                    if (idpOrSp == SamlIdpOrSp.IDP) {
                        samlIdpSingleLogoutService.processSPRequest(httpRequest, httpResponse, samlRequestMessage);
                    } else {
                        samlSpSingleLogoutService.processIDPRequest(httpRequest, httpResponse, samlRequestMessage);
                    }
                } else {
                    if (idpOrSp == SamlIdpOrSp.IDP) {
                        samlIdpSingleLogoutService.processSPResponse(httpRequest, httpResponse, samlResponseMessage);
                    } else {
                        samlSpSingleLogoutService.processIDPResponse(httpRequest, httpResponse, samlResponseMessage);
                    }
                }
            }
        } catch (Exception e) {
            if (dialogueManager.isAttached()) {
                dialogueManager.endDialogue();
            }
            throw new RuntimeException(e);
        }

        dialogueManager.detachDialogue();
    }

    private RequestAbstractType getSamlRequest(Document document) throws InvalidRequestException {
        try {
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            @SuppressWarnings("unchecked")
            JAXBElement<RequestAbstractType> jaxbRequest = (JAXBElement<RequestAbstractType>) unmarshaller.unmarshal(document);
            RequestAbstractType request = jaxbRequest.getValue();
            return request;
        } catch (JAXBException e) {
            throw new InvalidRequestException("SAML message could not be parsed", e);
        }
    }

    private StatusResponseType getSamlResponse(Document document) throws InvalidRequestException {
        try {
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            @SuppressWarnings("unchecked")
            JAXBElement<StatusResponseType> jaxbResponseType = (JAXBElement<StatusResponseType>) unmarshaller.unmarshal(document);
            StatusResponseType statusResponse = jaxbResponseType.getValue();
            return statusResponse;
        } catch (JAXBException e) {
            throw new InvalidRequestException("SAML message could not be parsed", e);
        }
    }

    private Document getDocument(InputStream is) throws InvalidRequestException {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            factory.setXIncludeAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            return builder.parse(is);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new InvalidRequestException("SAML request could not be parsed", e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
TOP

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

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.