at.gv.egovernment.moa.id.protocols.pvp2x.builder.SingleLogOutBuilder.java Source code

Java tutorial

Introduction

Here is the source code for at.gv.egovernment.moa.id.protocols.pvp2x.builder.SingleLogOutBuilder.java

Source

/*
 * Copyright 2014 Federal Chancellery Austria
 * MOA-ID has been developed in a cooperation between BRZ, the Federal
 * Chancellery Austria - ICT staff unit, and Graz University of Technology.
 *
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
 * the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * http://www.osor.eu/eupl/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 *
 * This product combines work with different licenses. See the "NOTICE" text
 * file for details on the various modules and licenses.
 * The "NOTICE" text file is part of the distribution. Any derivative works
 * that you distribute must include a readable copy of the "NOTICE" text file.
 */
package at.gv.egovernment.moa.id.protocols.pvp2x.builder;

import java.security.NoSuchAlgorithmException;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.joda.time.DateTime;
import org.opensaml.common.SAMLObject;
import org.opensaml.common.binding.BasicSAMLMessageContext;
import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.core.Issuer;
import org.opensaml.saml2.core.LogoutRequest;
import org.opensaml.saml2.core.LogoutResponse;
import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.RequestAbstractType;
import org.opensaml.saml2.core.Status;
import org.opensaml.saml2.core.StatusCode;
import org.opensaml.saml2.core.StatusMessage;
import org.opensaml.saml2.core.StatusResponseType;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.IDPSSODescriptor;
import org.opensaml.saml2.metadata.SPSSODescriptor;
import org.opensaml.saml2.metadata.SSODescriptor;
import org.opensaml.saml2.metadata.SingleLogoutService;
import org.opensaml.saml2.metadata.impl.SingleLogoutServiceBuilder;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.opensaml.ws.message.encoder.MessageEncodingException;
import org.opensaml.xml.security.SecurityException;
import org.opensaml.xml.security.x509.X509Credential;

import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.config.ConfigurationException;
import at.gv.egovernment.moa.id.data.SLOInformationContainer;
import at.gv.egovernment.moa.id.data.SLOInformationImpl;
import at.gv.egovernment.moa.id.opemsaml.MOAStringRedirectDeflateEncoder;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding;
import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding;
import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NOSLOServiceDescriptorException;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoMetadataInformationException;
import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest;
import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider;
import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider;
import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils;
import at.gv.egovernment.moa.id.util.MOAIDMessageProvider;
import at.gv.egovernment.moa.logging.Logger;

/**
 * @author tlenz
 *
 */
public class SingleLogOutBuilder {

    public static void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) {
        Status status = logOutResp.getStatus();
        if (!status.getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {
            String message = " Message: ";
            if (status.getStatusMessage() != null)
                message += status.getStatusMessage().getMessage();
            Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue() + " FAILED. (ResponseCode: "
                    + status.getStatusCode().getValue() + message + ")");
            sloContainer.putFailedOA(logOutResp.getIssuer().getValue());

        } else
            sloContainer.removeFrontChannelOA(logOutResp.getIssuer().getValue());
        Logger.debug("Single LogOut for OA " + logOutResp.getIssuer().getValue() + " SUCCESS");

    }

    /**
     * @param serviceURL
     * @param binding
     * @param sloReq
     * @param httpReq
     * @param httpResp
     * @param relayState
     * @return 
     */
    public static String getFrontChannelSLOMessageURL(String serviceURL, String bindingType,
            RequestAbstractType sloReq, HttpServletRequest httpReq, HttpServletResponse httpResp, String relayState)
            throws MOAIDException {

        try {
            X509Credential credentials = CredentialProvider.getIDPAssertionSigningCredential();

            Logger.debug("create SAML RedirectBinding response");

            MOAStringRedirectDeflateEncoder encoder = new MOAStringRedirectDeflateEncoder();
            BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
            SingleLogoutService service = new SingleLogoutServiceBuilder().buildObject();
            service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
            service.setLocation(serviceURL);
            context.setOutboundSAMLMessageSigningCredential(credentials);
            context.setPeerEntityEndpoint(service);
            context.setOutboundSAMLMessage(sloReq);
            context.setRelayState(relayState);

            encoder.encode(context);

            return encoder.getRedirectURL();

        } catch (MessageEncodingException e) {
            Logger.error("Message Encoding exception", e);
            throw new MOAIDException("pvp2.01", null, e);

        }
    }

    public static String getFrontChannelSLOMessageURL(SingleLogoutService service, StatusResponseType sloResp,
            HttpServletRequest httpReq, HttpServletResponse httpResp, String relayState) throws MOAIDException {

        try {
            X509Credential credentials = CredentialProvider.getIDPAssertionSigningCredential();

            Logger.debug("create SAML RedirectBinding response");

            MOAStringRedirectDeflateEncoder encoder = new MOAStringRedirectDeflateEncoder();
            BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
            context.setOutboundSAMLMessageSigningCredential(credentials);
            context.setPeerEntityEndpoint(service);
            context.setOutboundSAMLMessage(sloResp);
            context.setRelayState(relayState);

            encoder.encode(context);

            return encoder.getRedirectURL();

        } catch (MessageEncodingException e) {
            Logger.error("Message Encoding exception", e);
            throw new MOAIDException("pvp2.01", null, e);

        }
    }

    public static void sendFrontChannelSLOMessage(SingleLogoutService consumerService, LogoutResponse sloResp,
            HttpServletRequest req, HttpServletResponse resp, String relayState) throws MOAIDException {
        IEncoder binding = null;
        if (consumerService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
            binding = new RedirectBinding();

        } else if (consumerService.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) {
            binding = new PostBinding();

        }

        if (binding == null) {
            throw new BindingNotSupportedException(consumerService.getBinding());
        }

        try {
            binding.encodeRespone(req, resp, sloResp, consumerService.getLocation(), relayState);

        } catch (MessageEncodingException e) {
            Logger.error("Message Encoding exception", e);
            throw new MOAIDException("pvp2.01", null, e);

        } catch (SecurityException e) {
            Logger.error("Security exception", e);
            throw new MOAIDException("pvp2.01", null, e);

        }
    }

    public static LogoutRequest buildSLORequestMessage(SLOInformationImpl sloInfo)
            throws ConfigurationException, MOAIDException {
        LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class);

        SecureRandomIdentifierGenerator gen;
        try {
            gen = new SecureRandomIdentifierGenerator();
            sloReq.setID(gen.generateIdentifier());

        } catch (NoSuchAlgorithmException e) {
            Logger.error("Internal server error", e);
            throw new AuthenticationException("pvp2.13", new Object[] {});

        }

        DateTime now = new DateTime();
        Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
        issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath());
        issuer.setFormat(NameID.ENTITY);
        sloReq.setIssuer(issuer);
        sloReq.setIssueInstant(now);
        sloReq.setNotOnOrAfter(now.plusMinutes(5));

        sloReq.setDestination(sloInfo.getServiceURL());

        NameID nameID = SAML2Utils.createSAMLObject(NameID.class);
        nameID.setFormat(sloInfo.getUserNameIDFormat());
        nameID.setValue(sloInfo.getUserNameIdentifier());
        sloReq.setNameID(nameID);

        return sloReq;
    }

    public static LogoutResponse buildSLOErrorResponse(SingleLogoutService sloService,
            PVPTargetConfiguration spRequest, String firstLevelStatusCode)
            throws ConfigurationException, MOAIDException {
        LogoutResponse sloResp = buildBasicResponse(sloService, spRequest);

        Status status = SAML2Utils.createSAMLObject(Status.class);
        StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class);
        StatusMessage statusMessage = SAML2Utils.createSAMLObject(StatusMessage.class);
        statusCode.setValue(firstLevelStatusCode);
        statusMessage.setMessage(MOAIDMessageProvider.getInstance().getMessage("pvp2.18", null));
        StatusCode secondLevelCode = SAML2Utils.createSAMLObject(StatusCode.class);
        secondLevelCode.setValue(StatusCode.PARTIAL_LOGOUT_URI);
        statusCode.setStatusCode(secondLevelCode);
        status.setStatusCode(statusCode);
        status.setStatusMessage(statusMessage);
        sloResp.setStatus(status);
        return sloResp;
    }

    public static LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService,
            PVPTargetConfiguration spRequest, List<String> failedOAs) throws MOAIDException {
        LogoutResponse sloResp = buildBasicResponse(sloService, spRequest);

        Status status;
        if (failedOAs == null || failedOAs.size() == 0) {
            status = SAML2Utils.getSuccessStatus();

        } else {
            status = SAML2Utils.createSAMLObject(Status.class);
            StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class);
            StatusMessage statusMessage = SAML2Utils.createSAMLObject(StatusMessage.class);
            statusCode.setValue(StatusCode.SUCCESS_URI);
            statusMessage.setMessage(MOAIDMessageProvider.getInstance().getMessage("pvp2.18", null));
            StatusCode secondLevelCode = SAML2Utils.createSAMLObject(StatusCode.class);
            secondLevelCode.setValue(StatusCode.PARTIAL_LOGOUT_URI);
            statusCode.setStatusCode(secondLevelCode);
            status.setStatusCode(statusCode);
            status.setStatusMessage(statusMessage);

        }
        sloResp.setStatus(status);
        return sloResp;

    }

    private static LogoutResponse buildBasicResponse(SingleLogoutService sloService,
            PVPTargetConfiguration spRequest) throws ConfigurationException, MOAIDException {
        LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class);
        Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);
        issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath());
        issuer.setFormat(NameID.ENTITY);
        sloResp.setIssuer(issuer);
        sloResp.setIssueInstant(new DateTime());
        sloResp.setDestination(sloService.getLocation());

        SecureRandomIdentifierGenerator gen;
        try {
            gen = new SecureRandomIdentifierGenerator();
            sloResp.setID(gen.generateIdentifier());

        } catch (NoSuchAlgorithmException e) {
            Logger.error("Internal server error", e);
            throw new AuthenticationException("pvp2.13", new Object[] {});

        }

        if (spRequest.getRequest() instanceof MOARequest
                && ((MOARequest) spRequest.getRequest()).getSamlRequest() instanceof LogoutRequest) {
            LogoutRequest sloReq = (LogoutRequest) ((MOARequest) spRequest.getRequest()).getSamlRequest();
            sloResp.setInResponseTo(sloReq.getID());

        }

        return sloResp;

    }

    public static SingleLogoutService getRequestSLODescriptor(String entityID)
            throws NOSLOServiceDescriptorException {
        try {
            EntityDescriptor entity = MOAMetadataProvider.getInstance().getEntityDescriptor(entityID);
            SSODescriptor spsso = entity.getSPSSODescriptor(SAMLConstants.SAML20P_NS);

            SingleLogoutService sloService = null;
            for (SingleLogoutService el : spsso.getSingleLogoutServices()) {
                if (el.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI))
                    sloService = el;

                else if (el.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) && ((sloService != null
                        && !sloService.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI))
                        || sloService == null))
                    sloService = el;

                //            else  if (el.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)
                //                  && (
                //                        (sloService != null 
                //                           && !sloService.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)
                //                           && !sloService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) 
                //                        || sloService == null)
                //                  )
                //               sloService = el;            
            }

            if (sloService == null) {
                Logger.error("Found no valid SLO ServiceDescriptor in Metadata");
                throw new NOSLOServiceDescriptorException("NO valid SLO ServiceDescriptor", null);

            }
            return sloService;

        } catch (MetadataProviderException e) {
            Logger.error("Found no SLO ServiceDescriptor in Metadata");
            throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null);
        }

    }

    public static SingleLogoutService getResponseSLODescriptor(PVPTargetConfiguration spRequest)
            throws NoMetadataInformationException, NOSLOServiceDescriptorException {
        MOARequest moaReq = (MOARequest) spRequest.getRequest();
        EntityDescriptor metadata = moaReq.getEntityMetadata();
        SSODescriptor ssodesc = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS);

        if (ssodesc == null) {
            Logger.debug("No PVP SPSSO descriptor found --> search IDPSSO descriptor");
            ssodesc = metadata.getIDPSSODescriptor(SAMLConstants.SAML20P_NS);

        }

        if (ssodesc == null) {
            Logger.error("Found no SLO ServiceDescriptor in Metadata");
            throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null);

        }

        SingleLogoutService sloService = null;
        for (SingleLogoutService el : ssodesc.getSingleLogoutServices()) {
            if (el.getBinding().equals(spRequest.getBinding()))
                sloService = el;
        }

        if (sloService == null) {
            if (ssodesc.getSingleLogoutServices().size() != 0)
                sloService = ssodesc.getSingleLogoutServices().get(0);

            else {
                Logger.error("Found no SLO ServiceDescriptor in Metadata");
                throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null);
            }
        }

        return sloService;
    }

}