org.josso.jb5.agent.JOSSOJASPIAuthenticator.java Source code

Java tutorial

Introduction

Here is the source code for org.josso.jb5.agent.JOSSOJASPIAuthenticator.java

Source

/*
 * JOSSO: Java Open Single Sign-On
 *
 * Copyright 2004-2009, Atricore, Inc.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 *
 */

package org.josso.jb5.agent;

import java.io.IOException;
import java.security.Principal;

import javax.security.auth.Subject;
import javax.security.auth.message.callback.CallerPrincipalCallback;
import javax.security.auth.message.callback.PasswordValidationCallback;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;

import org.apache.catalina.Realm;
import org.apache.catalina.Session;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.deploy.SecurityConstraint;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.security.ServerAuthenticationManager;
import org.jboss.security.auth.message.GenericMessageInfo;
import org.jboss.web.tomcat.security.jaspi.TomcatJASPIAuthenticator;
import org.josso.agent.Lookup;
import org.josso.agent.http.HttpSSOAgent;
import org.josso.agent.http.WebAccessControlUtil;
import org.josso.gateway.Constants;
import org.josso.jaspi.agent.JASPICallbackHandler;

/**
 * JOSSO authenticator that does JSR-196 (JASPI) authentication.
 */
public class JOSSOJASPIAuthenticator extends TomcatJASPIAuthenticator {

    private static final Log log = LogFactory.getLog(JOSSOJASPIAuthenticator.class);

    private String messageLayer = "HttpServlet";

    @Override
    public void invoke(Request request, Response response) throws IOException, ServletException {

        if (log.isDebugEnabled())
            log.debug("Security checking request " + request.getMethod() + " " + request.getRequestURI());
        LoginConfig config = this.context.getLoginConfig();

        // Have we got a cached authenticated Principal to record?
        Principal principal = request.getUserPrincipal();
        if (principal == null) {
            Session session = request.getSessionInternal(false);
            if (session != null) {
                if (!jossoCookieExists(request)) {
                    session.setPrincipal(null);
                }
                principal = session.getPrincipal();
                if (principal != null) {
                    if (log.isDebugEnabled())
                        log.debug("We have cached auth type " + session.getAuthType() + " for principal "
                                + session.getPrincipal());
                    request.setAuthType(session.getAuthType());
                    request.setUserPrincipal(principal);
                }
            }
        }

        Realm realm = this.context.getRealm();
        // Is this request URI subject to a security constraint?
        SecurityConstraint[] constraints = realm.findSecurityConstraints(request, this.context);

        // Enforce any user data constraint for this security constraint
        if (log.isDebugEnabled()) {
            log.debug(" Calling hasUserDataPermission()");
        }
        if (!realm.hasUserDataPermission(request, response, constraints)) {
            if (log.isDebugEnabled()) {
                log.debug(" Failed hasUserDataPermission()");
            }
            /*
             * ASSERT: Authenticator already set the appropriate HTTP status
             * code, so we do not have to do anything special
             */
            return;
        }

        if (!authenticate(request, response, config)) {
            if (log.isDebugEnabled()) {
                log.debug(" Failed authenticate()");
            }
            /*
             * ASSERT: Authenticator already set the appropriate HTTP status
             * code, so we do not have to do anything special
             */
            return;
        }

        if (log.isDebugEnabled()) {
            log.debug(" Calling accessControl()");
        }

        if (!realm.hasResourcePermission(request, response, constraints, this.context)) {
            if (log.isDebugEnabled()) {
                log.debug(" Failed accessControl()");
            }
            /*
             * ASSERT: AccessControl method has already set the appropriate HTTP
             * status code, so we do not have to do anything special
             */
            return;
        }

        // Any and all specified constraints have been satisfied
        if (log.isDebugEnabled()) {
            log.debug(" Successfully passed all security constraints");
        }
        getNext().invoke(request, response);
    }

    @Override
    protected boolean authenticate(Request request, Response response, LoginConfig config) throws IOException {
        boolean result = false;

        String authMethod = config.getAuthMethod();

        // Have we already authenticated someone?
        Principal principal = request.getUserPrincipal();
        if (principal != null) {
            log.trace("Already authenticated '" + principal.getName() + "'");
            //return true;
        }

        Realm realm = this.context.getRealm();
        // Is this request URI subject to a security constraint?
        SecurityConstraint[] constraints = realm.findSecurityConstraints(request, this.context);

        if (!jossoCookieExists(request) && principal == null && constraints != null && constraints.length > 0) {
            boolean authRequired = true;
            for (int i = 0; i < constraints.length && authRequired; i++) {
                if (!constraints[i].getAuthConstraint()) {
                    authRequired = false;
                } else if (!constraints[i].getAllRoles()) {
                    String[] roles = constraints[i].findAuthRoles();
                    if (roles == null || roles.length == 0) {
                        authRequired = false;
                    }
                }
            }

            if (authRequired) {
                forwardToLoginPage(request, response, config);
                return false;
            }
        }

        GenericMessageInfo messageInfo = new GenericMessageInfo();
        messageInfo.setRequestMessage(request);
        messageInfo.setResponseMessage(response);

        // Put bits of information needed by tomcat server auth modules
        messageInfo.getMap().put("CACHE", cache);

        JASPICallbackHandler cbh = new JASPICallbackHandler();

        Subject subject = new Subject();
        ServerAuthenticationManager sam = getServerAuthenticationManager();
        if (sam != null) {
            result = sam.isValid(messageInfo, subject, messageLayer, cbh);
        }

        // The Authentication process has been a success. We need to register
        // the principal, username, password with the container
        if (result) {
            PasswordValidationCallback pvc = cbh.getPasswordValidationCallback();
            CallerPrincipalCallback cpcb = cbh.getCallerPrincipalCallback();
            if (pvc != null && cpcb != null) {
                this.register(request, response, cpcb.getPrincipal(), authMethod, pvc.getUsername(),
                        new String(pvc.getPassword()));
                JBossSecurityAssociationActions.setPrincipalInfo(cpcb.getPrincipal(), new String(pvc.getPassword()),
                        subject);
            }
        }

        return result;
    }

    /**
     * Register an authenticated Principal and authentication type in our
     * request and session.
     * 
     * @param request
     *            The servlet request we are processing
     * @param response
     *            The servlet response we are generating
     * @param principal
     *            The authenticated Principal to be registered
     * @param authType
     *            The authentication type to be registered
     * @param username
     *            Username used to authenticate (if any)
     * @param password
     *            Password used to authenticate (if any)
     */
    protected void register(Request request, Response response, Principal principal, String authType,
            String username, String password) {

        if (log.isTraceEnabled()) {
            String name = (principal == null) ? "none" : principal.getName();
            log.trace("Authenticated '" + name + "' with type '" + authType + "'");
        }

        // Cache the authentication information in our request
        request.setAuthType(authType);
        request.setUserPrincipal(principal);

        // Cache the authentication information in our session, if any
        Session session = request.getSessionInternal(false);
        if (session != null && cache) {
            session.setAuthType(authType);
            session.setPrincipal(principal);
        }
    }

    /**
     * Called to forward to the login page.
     * 
     * @param request Request we are processing
     * @param response Response we are creating
     * @param config Login configuration describing 
     *       how authentication should be performed
     */
    protected void forwardToLoginPage(Request request, Response response, LoginConfig config) {
        RequestDispatcher disp = context.getServletContext().getRequestDispatcher(config.getLoginPage());
        try {
            Lookup lookup = Lookup.getInstance();
            lookup.init("josso-agent-config.xml");
            HttpSSOAgent agent = (HttpSSOAgent) lookup.lookupSSOAgent();
            agent.setAttribute(request.getRequest(), response.getResponse(),
                    WebAccessControlUtil.KEY_JOSSO_SAVED_REQUEST_URI, getRequestURI(request));
            disp.forward(request.getRequest(), response.getResponse());
            response.finishResponse();
        } catch (Throwable t) {
            log.warn("Unexpected error forwarding to login page", t);
        }
    }

    /**
     * Returns request URI.
     * 
     * @param request request
     * @return request URI.
     */
    protected String getRequestURI(Request request) {
        StringBuffer requestURI = new StringBuffer(request.getRequestURI());
        if (request.getQueryString() != null) {
            requestURI.append('?');
            requestURI.append(request.getQueryString());
        }
        return requestURI.toString();
    }

    /**
     * Checks if josso cookie exists.
     * 
     * @param request request
     * @return true if josso cookie exists, false otherwise
     */
    protected boolean jossoCookieExists(Request request) {
        boolean jossoCookieExists = false;
        Cookie cookies[] = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (Constants.JOSSO_SINGLE_SIGN_ON_COOKIE.equals(cookie.getName())) {
                    if (cookie.getValue() != null && !cookie.getValue().equals("-")) {
                        jossoCookieExists = true;
                    }
                    break;
                }
            }
        }
        return jossoCookieExists;
    }
}