at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.SLOBasicServlet.java Source code

Java tutorial

Introduction

Here is the source code for at.gv.egovernment.moa.id.configuration.auth.pvp2.servlets.SLOBasicServlet.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.configuration.auth.pvp2.servlets;

import java.security.NoSuchAlgorithmException;

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

import org.joda.time.DateTime;
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.NameIDType;
import org.opensaml.saml2.core.Status;
import org.opensaml.saml2.core.StatusCode;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.SingleLogoutService;
import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.gv.egovernment.moa.id.configuration.Constants;
import at.gv.egovernment.moa.id.configuration.auth.AuthenticatedUser;
import at.gv.egovernment.moa.id.configuration.auth.AuthenticationManager;
import at.gv.egovernment.moa.id.configuration.config.ConfigurationProvider;
import at.gv.egovernment.moa.id.configuration.exception.ConfigurationException;
import at.gv.egovernment.moa.id.configuration.exception.PVP2Exception;
import at.gv.egovernment.moa.id.configuration.exception.SLOException;
import at.gv.egovernment.moa.id.configuration.helper.LanguageHelper;
import at.gv.egovernment.moa.id.configuration.utils.SAML2Utils;
import at.gv.egovernment.moa.util.MiscUtil;

/**
 * @author tlenz
 *
 */
public class SLOBasicServlet extends HttpServlet {
    private static final long serialVersionUID = -4547240664871845098L;
    private static final Logger log = LoggerFactory.getLogger(SLOBasicServlet.class);

    private ConfigurationProvider config;

    public SLOBasicServlet() throws ConfigurationException {
        config = ConfigurationProvider.getInstance();
        config.initializePVP2Login();
    }

    protected LogoutRequest createLogOutRequest(String nameID, String nameIDFormat, HttpServletRequest request)
            throws SLOException {
        try {
            LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class);
            SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator();
            sloReq.setID(gen.generateIdentifier());
            sloReq.setIssueInstant(new DateTime());
            NameID name = SAML2Utils.createSAMLObject(NameID.class);
            Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);

            String serviceURL = config.getPublicUrlPreFix(request);
            if (!serviceURL.endsWith("/"))
                serviceURL = serviceURL + "/";
            name.setValue(serviceURL);
            issuer.setValue(serviceURL);
            issuer.setFormat(NameIDType.ENTITY);
            sloReq.setIssuer(issuer);

            NameID userNameID = SAML2Utils.createSAMLObject(NameID.class);
            sloReq.setNameID(userNameID);
            userNameID.setFormat(nameIDFormat);
            userNameID.setValue(nameID);

            return sloReq;

        } catch (NoSuchAlgorithmException e) {
            log.warn("Single LogOut request createn FAILED. ", e);
            throw new SLOException();

        }

    }

    protected LogoutResponse processLogOutRequest(LogoutRequest sloReq, HttpServletRequest request)
            throws NoSuchAlgorithmException {
        //check response destination
        String serviceURL = config.getPublicUrlPreFix(request);
        if (!serviceURL.endsWith("/"))
            serviceURL = serviceURL + "/";

        String responseDestination = sloReq.getDestination();
        if (MiscUtil.isEmpty(responseDestination) || !responseDestination.startsWith(serviceURL)) {
            log.warn("PVPResponse destination does not match requested destination");
            return createSLOResponse(sloReq, StatusCode.REQUESTER_URI, request);
        }

        AuthenticationManager authManager = AuthenticationManager.getInstance();
        if (authManager.isActiveUser(sloReq.getNameID().getValue())) {
            AuthenticatedUser authUser = authManager.getActiveUser(sloReq.getNameID().getValue());
            log.info("User " + authUser.getGivenName() + " " + authUser.getFamilyName() + " with nameID:"
                    + authUser.getNameID() + " get logged out by Single LogOut request.");
            authManager.removeActiveUser(authUser);
            HttpSession session = request.getSession(false);
            if (session != null)
                session.invalidate();
            return createSLOResponse(sloReq, StatusCode.SUCCESS_URI, request);

        } else {
            log.debug("Single LogOut not possible! User with nameID:" + sloReq.getNameID().getValue()
                    + " is not found.");
            return createSLOResponse(sloReq, StatusCode.PARTIAL_LOGOUT_URI, request);

        }

    }

    private LogoutResponse createSLOResponse(LogoutRequest sloReq, String statusCodeURI, HttpServletRequest request)
            throws NoSuchAlgorithmException {
        LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class);
        SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator();
        sloResp.setID(gen.generateIdentifier());
        sloResp.setInResponseTo(sloReq.getID());
        sloResp.setIssueInstant(new DateTime());
        NameID name = SAML2Utils.createSAMLObject(NameID.class);
        Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);

        String serviceURL = config.getPublicUrlPreFix(request);
        if (!serviceURL.endsWith("/"))
            serviceURL = serviceURL + "/";
        name.setValue(serviceURL);
        issuer.setValue(serviceURL);
        issuer.setFormat(NameIDType.ENTITY);
        sloResp.setIssuer(issuer);

        Status status = SAML2Utils.createSAMLObject(Status.class);
        sloResp.setStatus(status);
        StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class);
        statusCode.setValue(statusCodeURI);
        status.setStatusCode(statusCode);

        return sloResp;
    }

    protected void validateLogOutResponse(LogoutResponse sloResp, String reqID, HttpServletRequest request,
            HttpServletResponse response) throws PVP2Exception {
        //ckeck InResponseTo matchs requestID 
        if (MiscUtil.isEmpty(reqID)) {
            log.info("NO Sigle LogOut request ID");
            throw new PVP2Exception("NO Sigle LogOut request ID");
        }

        if (!reqID.equals(sloResp.getInResponseTo())) {
            log.warn("SLORequestID does not match SLO Response ID!");
            throw new PVP2Exception("SLORequestID does not match SLO Response ID!");

        }

        //check response destination
        String serviceURL = config.getPublicUrlPreFix(request);
        if (!serviceURL.endsWith("/"))
            serviceURL = serviceURL + "/";

        String responseDestination = sloResp.getDestination();
        if (MiscUtil.isEmpty(responseDestination) || !responseDestination.startsWith(serviceURL)) {
            log.warn("PVPResponse destination does not match requested destination");
            throw new PVP2Exception("SLO response destination does not match requested destination");
        }

        request.getSession().invalidate();

        if (sloResp.getStatus().getStatusCode().getValue().equals(StatusCode.PARTIAL_LOGOUT_URI)) {
            log.warn("Single LogOut process is not completed.");
            request.getSession().setAttribute(Constants.SESSION_SLOERROR,
                    LanguageHelper.getErrorString("webpages.slo.error", request));

        } else if (sloResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {

            if (sloResp.getStatus().getStatusCode().getStatusCode() != null
                    && !sloResp.getStatus().getStatusCode().getStatusCode().equals(StatusCode.PARTIAL_LOGOUT_URI)) {
                log.info("Single LogOut process complete.");
                request.getSession().setAttribute(Constants.SESSION_SLOSUCCESS,
                        LanguageHelper.getErrorString("webpages.slo.success", request));

            } else {
                log.warn("Single LogOut process is not completed.");
                request.getSession().setAttribute(Constants.SESSION_SLOERROR,
                        LanguageHelper.getErrorString("webpages.slo.error", request));

            }

        } else {
            log.warn("Single LogOut response sends an unsupported statustype "
                    + sloResp.getStatus().getStatusCode().getValue());
            request.getSession().setAttribute(Constants.SESSION_SLOERROR,
                    LanguageHelper.getErrorString("webpages.slo.error", request));

        }
        String redirectURL = serviceURL + Constants.SERVLET_LOGOUT;
        redirectURL = response.encodeRedirectURL(redirectURL);
        response.setContentType("text/html");
        response.setStatus(302);
        response.addHeader("Location", redirectURL);

    }

    protected SingleLogoutService findIDPFrontChannelSLOService() throws ConfigurationException, SLOException {

        String entityname = config.getPVP2IDPMetadataEntityName();
        if (MiscUtil.isEmpty(entityname)) {
            log.info("No IDP EntityName configurated");
            throw new ConfigurationException("No IDP EntityName configurated");
        }

        //get IDP metadata from metadataprovider
        HTTPMetadataProvider idpmetadata = config.getMetaDataProvier();
        try {
            EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname);
            if (idpEntity == null) {
                log.info("IDP EntityName is not found in IDP Metadata");
                throw new ConfigurationException("IDP EntityName is not found in IDP Metadata");

            }

            //select authentication-service url from metadata
            SingleLogoutService redirectEndpoint = null;
            for (SingleLogoutService sss : idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS)
                    .getSingleLogoutServices()) {

                //Get the service address for the binding you wish to use
                if (sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI))
                    redirectEndpoint = sss;

                else if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI) && redirectEndpoint == null)
                    redirectEndpoint = sss;
            }

            if (redirectEndpoint == null) {
                log.warn("Single LogOut FAILED: IDP implements no frontchannel SLO service.");
                throw new SLOException("Single LogOut FAILED: IDP implements no frontchannel SLO service.");
            }

            return redirectEndpoint;
        } catch (MetadataProviderException e) {
            log.info("IDP EntityName is not found in IDP Metadata", e);
            throw new ConfigurationException("IDP EntityName is not found in IDP Metadata");

        }
    }

    protected ConfigurationProvider getConfig() {
        return config;
    }

}