org.guanxi.sp.engine.security.GuardVerifier.java Source code

Java tutorial

Introduction

Here is the source code for org.guanxi.sp.engine.security.GuardVerifier.java

Source

//: "The contents of this file are subject to the Mozilla Public License
//: Version 1.1 (the "License"); you may not use this file except in
//: compliance with the License. You may obtain a copy of the License at
//: http://www.mozilla.org/MPL/
//:
//: Software distributed under the License is distributed on an "AS IS"
//: basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//: License for the specific language governing rights and limitations
//: under the License.
//:
//: The Original Code is Guanxi (http://www.guanxi.uhi.ac.uk).
//:
//: The Initial Developer of the Original Code is Alistair Young alistair@codebrane.com
//: All Rights Reserved.
//:

package org.guanxi.sp.engine.security;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.context.ServletContextAware;
import org.springframework.context.MessageSource;
import org.apache.log4j.Logger;
import org.guanxi.xal.saml_2_0.metadata.EntityDescriptorType;
import org.guanxi.xal.saml2.metadata.GuardRoleDescriptorExtensions;
import org.guanxi.common.definitions.Guanxi;
import org.guanxi.common.EntityConnection;
import org.guanxi.common.GuanxiException;
import org.guanxi.sp.Util;
import org.guanxi.sp.engine.Config;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.cert.X509Certificate;
import java.security.KeyStore;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * Verification process for a Guard
 */
public class GuardVerifier extends HandlerInterceptorAdapter implements ServletContextAware {
    private static final Logger logger = Logger.getLogger(GuardVerifier.class.getName());

    /** The ServletContext, passed to us by Spring as we are ServletContextAware */
    private ServletContext servletContext = null;
    /** The localised messages to use */
    private MessageSource messages = null;
    /** The error page to use */
    private String errorPage = null;

    // Called by Spring as we are ServletContextAware
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    /**
     * Initialise the interceptor
     */
    public void init() {
    }

    /**
     * Blocks Guard access to a service until the Guard can be verified.
     *
     * @param request Standard HttpServletRequest
     * @param response Standard HttpServletResponse
     * @param object handler
     * @return true if the caller is authorised to use the service
     * @throws Exception if an error occurs
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object)
            throws Exception {
        String guardID = request.getParameter(Guanxi.WAYF_PARAM_GUARD_ID);
        String sessionID = request.getParameter(Guanxi.WAYF_PARAM_SESSION_ID);

        if ((guardID == null) || (sessionID == null)) {
            logger.error("Cant' verify Guard due to missing parameter");
            request.setAttribute("error", messages.getMessage("engine.error.missing.guard.verification.parameter",
                    null, request.getLocale()));
            request.setAttribute("message", messages.getMessage("engine.error.missing.guard.verification.parameter",
                    null, request.getLocale()));
            request.getRequestDispatcher(errorPage).forward(request, response);
            return false;
        }

        EntityDescriptorType guardEntityDescriptor = (EntityDescriptorType) servletContext.getAttribute(guardID);
        if (guardEntityDescriptor == null) {
            logger.error("Guard '" + guardID + "' not found in metadata repository");
            request.setAttribute("error",
                    messages.getMessage("engine.error.no.guard.metadata", null, request.getLocale()));
            request.setAttribute("message",
                    messages.getMessage("engine.error.no.guard.metadata", null, request.getLocale()));
            request.getRequestDispatcher(errorPage).forward(request, response);
            return false;
        }

        Config config = (Config) servletContext.getAttribute(Guanxi.CONTEXT_ATTR_ENGINE_CONFIG);
        if (config == null) {
            logger.error("Guard '" + guardID + "' wants to talk but Engine hasn't finished initialisation");
            request.setAttribute("error",
                    messages.getMessage("engine.error.not.initialised", null, request.getLocale()));
            request.setAttribute("message",
                    messages.getMessage("engine.error.not.initialised", null, request.getLocale()));
            request.getRequestDispatcher(errorPage).forward(request, response);
            return false;
        }

        // Load the GuanxiGuardService node from the metadata
        GuardRoleDescriptorExtensions guardNativeMetadata = Util.getGuardNativeMetadata(guardEntityDescriptor);

        // Build the REST URL to verify the Guard's session
        String queryString = guardNativeMetadata.getVerifierURL() + "?" + Guanxi.SESSION_VERIFIER_PARAM_SESSION_ID
                + "=" + sessionID;

        // If we haven't already checked the Guard for secure comms, do it now
        if (servletContext.getAttribute(guardID + "SECURE_CHECK_DONE_SP") == null) {
            // Load up the Guard's native metadata...
            GuardRoleDescriptorExtensions guardExt = Util.getGuardNativeMetadata(guardEntityDescriptor);

            // ...and see if it's using HTTPS
            try {
                if (Util.isGuardSecure(guardExt)) {
                    logger.info("Probing for Guard certificate for : " + guardID);

                    /* If the Guard is using HTTPS then we'll need to connect to it, extract it's
                     * certificate and add it to our truststore. To do that, we'll need to use our
                     * own keystore to let the Guard authenticate us.
                     */
                    EntityConnection guardConnection = new EntityConnection(queryString,
                            config.getCertificateAlias(), // alias of cert
                            config.getKeystore(), config.getKeystorePassword(), config.getTrustStore(),
                            config.getTrustStorePassword(), EntityConnection.PROBING_ON);
                    X509Certificate guardX509 = guardConnection.getServerCertificate();

                    // We've got the Guard's X509 so add it to our truststore...
                    KeyStore engineTrustStore = KeyStore.getInstance("jks");
                    engineTrustStore.load(new FileInputStream(config.getTrustStore()),
                            config.getTrustStorePassword().toCharArray());
                    // ...under it's Subject DN as an alias...
                    engineTrustStore.setCertificateEntry(guardID, guardX509);
                    // ...and rewrite the trust store
                    engineTrustStore.store(new FileOutputStream(config.getTrustStore()),
                            config.getTrustStorePassword().toCharArray());

                    // Mark Guard as having been checked for secure comms
                    servletContext.setAttribute(guardID + "SECURE_CHECK_DONE_SP", "SECURE");

                    logger.info("Added : " + guardID + " to truststore");
                } else {
                    // Mark Guard as having been checked for secure comms
                    servletContext.setAttribute(guardID + "SECURE_CHECK_DONE_SP", "NOT_SECURE");
                }
            } catch (Exception e) {
                logger.error("Failed to probe Guard : " + guardID + " for cert : ", e);
                request.setAttribute("error",
                        messages.getMessage("engine.error.guard.comms.failed", null, request.getLocale()));
                request.setAttribute("message",
                        messages.getMessage("engine.error.guard.comms.failed", null, request.getLocale()));
                request.getRequestDispatcher(errorPage).forward(request, response);
                return false;
            }
        }

        // Verify that the Guard actually sent the request
        String verificationResult = null;
        try {
            EntityConnection verifierService = new EntityConnection(queryString, config.getCertificateAlias(), // alias of cert
                    config.getKeystore(), config.getKeystorePassword(), config.getTrustStore(),
                    config.getTrustStorePassword(), EntityConnection.PROBING_OFF);
            verifierService.setDoOutput(true);
            verifierService.connect();
            verificationResult = verifierService.getContentAsString();
        } catch (GuanxiException ge) {
            logger.error("Guard '" + guardID + "' error during verification : ", ge);
            request.setAttribute("error",
                    messages.getMessage("engine.error.guard.comms.failed", null, request.getLocale()));
            request.setAttribute("message",
                    messages.getMessage("engine.error.guard.comms.failed", null, request.getLocale()));
            request.getRequestDispatcher(errorPage).forward(request, response);
            return false;
        }

        // Did the Guard verify the session?
        if (!verificationResult.equals(Guanxi.SESSION_VERIFIER_RETURN_VERIFIED)) {
            logger.error("Guard '" + guardID + "' error during verification : " + verificationResult);
            request.setAttribute("error",
                    messages.getMessage("engine.error.guard.failed.verification", null, request.getLocale()));
            request.setAttribute("message",
                    messages.getMessage("engine.error.guard.failed.verification", null, request.getLocale()));
            request.getRequestDispatcher(errorPage).forward(request, response);
            return false;
        }

        /* Convert the Guard's session ID to an Engine session ID and store the Guard's GuanxiGuardService
         * node under it.
         */
        servletContext.setAttribute(sessionID.replaceAll("GUARD", "ENGINE"), guardEntityDescriptor);

        return true;
    }

    // Setters
    public void setMessages(MessageSource messages) {
        this.messages = messages;
    }

    public void setErrorPage(String errorPage) {
        this.errorPage = errorPage;
    }
}