Package org.apache.geronimo.tomcat.realm

Source Code of org.apache.geronimo.tomcat.realm.TomcatGeronimoRealm

/**
*
* Copyright 2003-2004 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.apache.geronimo.tomcat.realm;

import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Wrapper;
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.catalina.realm.JAASRealm;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geronimo.security.ContextManager;
import org.apache.geronimo.security.jacc.PolicyContextHandlerContainerSubject;
import org.apache.geronimo.security.realm.providers.CertificateChainCallbackHandler;
import org.apache.geronimo.security.realm.providers.PasswordCallbackHandler;
import org.apache.geronimo.tomcat.JAASTomcatPrincipal;

import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.AccountExpiredException;
import javax.security.auth.login.CredentialExpiredException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.WebResourcePermission;
import javax.security.jacc.WebRoleRefPermission;
import javax.security.jacc.WebUserDataPermission;
import javax.servlet.ServletRequest;

import java.io.IOException;
import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.Principal;
import java.security.cert.X509Certificate;


public class TomcatGeronimoRealm extends JAASRealm {

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

    private static ThreadLocal currentRequestWrapperName = new ThreadLocal();

    /**
     * Descriptive information about this <code>Realm</code> implementation.
     */
    protected static final String info = "org.apache.geronimo.tomcat.TomcatGeronimoRealm/1.0";

    /**
     * Descriptive information about this <code>Realm</code> implementation.
     */
    protected static final String name = "TomcatGeronimoRealm";

    public TomcatGeronimoRealm() {

     }

    public static String setRequestWrapperName(String requestWrapperName) {
        String old = (String) currentRequestWrapperName.get();
        currentRequestWrapperName.set(requestWrapperName);
        return old;
    }

    /**
     * Enforce any user data constraint required by the security constraint
     * guarding this request URI.  Return <code>true</code> if this constraint
     * was not violated and processing should continue, or <code>false</code>
     * if we have created a response already.
     *
     * @param request     Request we are processing
     * @param response    Response we are creating
     * @param constraints Security constraint being checked
     * @throws IOException if an input/output error occurs
     */
    public boolean hasUserDataPermission(Request request,
                                         Response response,
                                         SecurityConstraint[] constraints)
            throws IOException {

        //Get an authenticated subject, if there is one
        Subject subject = null;
        try {

            //We will use the PolicyContextHandlerContainerSubject.HANDLER_KEY to see if a user
            //has authenticated, since a request.getUserPrincipal() will not pick up the user
            //unless its using a cached session.
            subject = (Subject) PolicyContext.getContext(PolicyContextHandlerContainerSubject.HANDLER_KEY);

        } catch (PolicyContextException e) {
            log.error(e);
        }

        //If nothing has authenticated yet, do the normal
        if (subject == null)
            return super.hasUserDataPermission(request, response, constraints);

        ContextManager.setCurrentCaller(subject);

        try {

            AccessControlContext acc = ContextManager.getCurrentContext();

            /**
             * JACC v1.0 secion 4.1.1
             */
            String transportType;
            if (request.isSecure()) {
                transportType = "CONFIDENTIAL";
                //What about INTEGRAL?? Does Tomcat support it??
            } else {
                transportType = "NONE";
            }
            WebUserDataPermission wudp = new WebUserDataPermission(request.getServletPath(), new String[]{request.getMethod()}, transportType);
            acc.checkPermission(wudp);

        } catch (AccessControlException ace) {
            response.sendError(Response.SC_FORBIDDEN);
            return false;
        }

        return true;
    }

    /**
     * Perform access control based on the specified authorization constraint.
     * Return <code>true</code> if this constraint is satisfied and processing
     * should continue, or <code>false</code> otherwise.
     *
     * @param request    Request we are processing
     * @param response   Response we are creating
     * @param constraints Security constraints we are enforcing
     * @param context    The Context to which client of this class is attached.
     * @throws java.io.IOException if an input/output error occurs
     */
    public boolean hasResourcePermission(Request request,
                                         Response response,
                                         SecurityConstraint[] constraints,
                                         Context context)
            throws IOException {

        // Specifically allow access to the form login and form error pages
        // and the "j_security_check" action
        LoginConfig config = context.getLoginConfig();
        if ((config != null) &&
            (org.apache.catalina.realm.Constants.FORM_METHOD.equals(config.getAuthMethod()))) {
            String requestURI = request.getDecodedRequestURI();
            String loginPage = context.getPath() + config.getLoginPage();
            if (loginPage.equals(requestURI)) {
                if (log.isDebugEnabled())
                    log.debug(" Allow access to login page " + loginPage);
                return (true);
            }
            String errorPage = context.getPath() + config.getErrorPage();
            if (errorPage.equals(requestURI)) {
                if (log.isDebugEnabled())
                    log.debug(" Allow access to error page " + errorPage);
                return (true);
            }
            if (requestURI.endsWith(org.apache.catalina.realm.Constants.FORM_ACTION)) {
                if (log.isDebugEnabled())
                    log.debug(" Allow access to username/password submission");
                return (true);
            }
        }
       
        //Set the current wrapper name (Servlet mapping)
        currentRequestWrapperName.set(request.getWrapper().getName());

        // Which user principal have we already authenticated?
        Principal principal = request.getUserPrincipal();

        //If we have no principal, then we should use the default.
        if (principal == null) {
            return request.isSecure();

        } else {
            ContextManager.setCurrentCaller(((JAASTomcatPrincipal) principal).getSubject());
        }

        try {

            AccessControlContext acc = ContextManager.getCurrentContext();


            /**
             * JACC v1.0 section 4.1.2
             */
            acc.checkPermission(new WebResourcePermission(request));

        } catch (AccessControlException ace) {
            response.sendError(Response.SC_FORBIDDEN);
            return false;
        }

        return true;

    }

    /**
     * Return <code>true</code> if the specified Principal has the specified
     * security role, within the context of this Realm; otherwise return
     * <code>false</code>.
     *
     * @param principal Principal for whom the role is to be checked
     * @param role      Security role to be checked
     */
    public boolean hasRole(Principal principal, String role) {

        if ((principal == null) || (role == null) || !(principal instanceof JAASTomcatPrincipal)) {
            return false;
        }

        String name = (String)currentRequestWrapperName.get();

        /**
         * JACC v1.0 secion B.19
         */
        if (name == null || name.equals("jsp")) {
            name = "";
        }

        //Set the caller
        ContextManager.setCurrentCaller(((JAASTomcatPrincipal) principal).getSubject());

        AccessControlContext acc = ContextManager.getCurrentContext();

        try {
            /**
             * JACC v1.0 section 4.1.3
             */
            acc.checkPermission(new WebRoleRefPermission(name, role));
        } catch (AccessControlException e) {
            return false;
        }

        return true;
    }

    /**
     * Return the <code>Principal</code> associated with the specified
     * username and credentials, if there is one; otherwise return
     * <code>null</code>.
     * <p/>
     * If there are any errors with the JDBC connection, executing the query or
     * anything we return null (don't authenticate). This event is also logged,
     * and the connection will be closed so that a subsequent request will
     * automatically re-open it.
     *
     * @param username    Username of the <code>Principal</code> to look up
     * @param credentials Password or other credentials to use in authenticating this
     *                    username
     */
    public Principal authenticate(String username, String credentials) {

        char[] cred = credentials == null? null: credentials.toCharArray();
        CallbackHandler callbackHandler = new PasswordCallbackHandler(username, cred);
        return authenticate(callbackHandler, username);
    }

    public Principal authenticate(X509Certificate[] certs) {
        if (certs == null || certs.length == 0) {
            return null;
        }
        CallbackHandler callbackHandler = new CertificateChainCallbackHandler(certs);
        String principalName = certs[0].getSubjectX500Principal().getName();
        return authenticate(callbackHandler, principalName);
    }

    public Principal authenticate(CallbackHandler callbackHandler, String principalName) {

        // Establish a LoginContext to use for authentication
        try {

            if ( (principalName!=null) && (!principalName.equals("")) ) {
              LoginContext loginContext = null;
              if (appName == null)
                  appName = "Tomcat";

              if (log.isDebugEnabled())
                  log.debug(sm.getString("jaasRealm.beginLogin", principalName, appName));

              // What if the LoginModule is in the container class loader ?
              ClassLoader ocl = null;

              if (isUseContextClassLoader()) {
                  ocl = Thread.currentThread().getContextClassLoader();
                  Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
              }

              try {
                  loginContext = new LoginContext(appName, callbackHandler);
              } catch (Throwable e) {
                  log.error(sm.getString("jaasRealm.unexpectedError"), e);
                  return (null);
              } finally {
                  if (isUseContextClassLoader()) {
                      Thread.currentThread().setContextClassLoader(ocl);
                  }
              }

              if (log.isDebugEnabled())
                  log.debug("Login context created " + principalName);

              // Negotiate a login via this LoginContext
              Subject subject;
              try {
                  loginContext.login();
                  Subject tempSubject = loginContext.getSubject();
                  if (tempSubject == null) {
                      if (log.isDebugEnabled())
                          log.debug(sm.getString("jaasRealm.failedLogin", principalName));
                      return (null);
                  }

                  subject = ContextManager.getServerSideSubject(tempSubject);
                  if (subject == null) {
                      if (log.isDebugEnabled())
                          log.debug(sm.getString("jaasRealm.failedLogin", principalName));
                      return (null);
                  }

                  ContextManager.setCurrentCaller(subject);

              } catch (AccountExpiredException e) {
                  if (log.isDebugEnabled())
                      log.debug(sm.getString("jaasRealm.accountExpired", principalName));
                  return (null);
              } catch (CredentialExpiredException e) {
                  if (log.isDebugEnabled())
                      log.debug(sm.getString("jaasRealm.credentialExpired", principalName));
                  return (null);
              } catch (FailedLoginException e) {
                  if (log.isDebugEnabled())
                      log.debug(sm.getString("jaasRealm.failedLogin", principalName));
                  return (null);
              } catch (LoginException e) {
                  log.warn(sm.getString("jaasRealm.loginException", principalName), e);
                  return (null);
              } catch (Throwable e) {
                  log.error(sm.getString("jaasRealm.unexpectedError"), e);
                  return (null);
              }

              if (log.isDebugEnabled())
                  log.debug(sm.getString("jaasRealm.loginContextCreated", principalName));

              // Return the appropriate Principal for this authenticated Subject
  /*            Principal principal = createPrincipal(username, subject);
              if (principal == null) {
                  log.debug(sm.getString("jaasRealm.authenticateFailure", username));
                  return (null);
              }
              if (log.isDebugEnabled()) {
                  log.debug(sm.getString("jaasRealm.authenticateSuccess", username));
              }
  */
              JAASTomcatPrincipal jaasPrincipal = new JAASTomcatPrincipal(principalName);
              jaasPrincipal.setSubject(subject);

              return (jaasPrincipal);
            }
            else {
                if (log.isDebugEnabled())
                    log.debug("Login Failed - null userID");
                return null;
            }

        } catch (Throwable t) {
            log.error("error ", t);
            return null;
        }
    }
    /**
     * Prepare for active use of the public methods of this <code>Component</code>.
     *
     * @throws org.apache.catalina.LifecycleException
     *          if this component detects a fatal error
     *          that prevents it from being started
     */
    public void start() throws LifecycleException {

        // Perform normal superclass initialization
        super.start();

    }

    /**
     * Gracefully shut down active use of the public methods of this <code>Component</code>.
     *
     * @throws LifecycleException if this component detects a fatal error
     *                            that needs to be reported
     */
    public void stop() throws LifecycleException {

        // Perform normal superclass finalization
        super.stop();

    }
}
TOP

Related Classes of org.apache.geronimo.tomcat.realm.TomcatGeronimoRealm

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.