craigmcc    01/11/13 14:42:31

  Added:       catalina/src/share/org/apache/catalina/realm
                        JAASCallbackHandler.java JAASMemoryLoginModule.java
                        JAASRealm.java
  Log:
  Basic implementation of a Realm that uses JAAS APIs underneath to perform
  authentication.  See the class-level Javadocs on JAASRealm for some
  important outstanding issues that should be addressed before trying to use
  this module in production.
  
  Revision  Changes    Path
  1.1                  
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASCallbackHandler.java
  
  Index: JAASCallbackHandler.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASCallbackHandler.java,v
 1.1 2001/11/13 22:42:31 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2001/11/13 22:42:31 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  
  package org.apache.catalina.realm;
  
  
  import java.io.IOException;
  import javax.security.auth.callback.Callback;
  import javax.security.auth.callback.CallbackHandler;
  import javax.security.auth.callback.NameCallback;
  import javax.security.auth.callback.PasswordCallback;
  import javax.security.auth.callback.UnsupportedCallbackException;
  
  
  /**
   * <p>Implementation of the JAAS <strong>CallbackHandler</code> interface,
   * used to negotiate delivery of the username and credentials that were
   * specified to our constructor.  No interaction with the user is required
   * (or possible).</p>
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2001/11/13 22:42:31 $
   */
  
  public class JAASCallbackHandler implements CallbackHandler {
  
  
      // ------------------------------------------------------------ Constructor
  
  
      /**
       * Construct a callback handler configured with the specified values.
       *
       * @param realm Our associated JAASRealm instance
       * @param username Username to be authenticated with
       * @param password Password to be authenticated with
       */
      public JAASCallbackHandler(JAASRealm realm, String username,
                                 String password) {
  
          super();
          this.realm = realm;
          this.username = username;
          this.password = password;
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The password to be authenticated with.
       */
      protected String password = null;
  
  
      /**
       * The associated <code>JAASRealm</code> instance.
       */
      protected JAASRealm realm = null;
  
  
      /**
       * The username to be authenticated with.
       */
      protected String username = null;
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Retrieve the information requested in the provided Callbacks.  This
       * implementation only recognizes <code>NameCallback</code> and
       * <code>PasswordCallback</code> instances.
       *
       * @param callbacks The set of callbacks to be processed
       *
       * @exception IOException if an input/output error occurs
       * @exception UnsupportedCallbackException if the login method requests
       *  an unsupported callback type
       */
      public void handle(Callback callbacks[])
          throws IOException, UnsupportedCallbackException {
  
          for (int i = 0; i < callbacks.length; i++) {
  
              if (callbacks[i] instanceof NameCallback) {
                  if (realm.getDebug() >= 3)
                      realm.log("Returning username " + username);
                  ((NameCallback) callbacks[i]).setName(username);
              } else if (callbacks[i] instanceof PasswordCallback) {
                  if (realm.getDebug() >= 3)
                      realm.log("Returning password " + password);
                  ((PasswordCallback) callbacks[i]).setPassword
                      (password.toCharArray());
              } else {
                  throw new UnsupportedCallbackException(callbacks[i]);
              }
  
  
          }
  
      }
  
  
  }
  
  
  
  1.1                  
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASMemoryLoginModule.java
  
  Index: JAASMemoryLoginModule.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASMemoryLoginModule.java,v
 1.1 2001/11/13 22:42:31 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2001/11/13 22:42:31 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  
  package org.apache.catalina.realm;
  
  
  import java.beans.PropertyChangeListener;
  import java.io.File;
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Map;
  import java.security.Principal;
  import java.security.cert.X509Certificate;
  import javax.security.auth.Subject;
  import javax.security.auth.callback.Callback;
  import javax.security.auth.callback.CallbackHandler;
  import javax.security.auth.callback.NameCallback;
  import javax.security.auth.callback.PasswordCallback;
  import javax.security.auth.callback.UnsupportedCallbackException;
  import javax.security.auth.login.FailedLoginException;
  import javax.security.auth.login.LoginException;
  import javax.security.auth.spi.LoginModule;
  import org.apache.catalina.Container;
  import org.apache.catalina.Realm;
  import org.apache.commons.digester.Digester;
  
  
  /**
   * <p>Implementation of the JAAS <strong>LoginModule</strong> interface,
   * primarily for use in testing <code>JAASRealm</code>.  It utilizes an
   * XML-format data file of username/password/role information identical to
   * that supported by <code>org.apache.catalina.realm.MemoryRealm</code>
   * (except that digested passwords are not supported).</p>
   *
   * <p>This class recognizes the following string-valued options, which are
   * specified in the configuration file (and passed to our constructor in
   * the <code>options</code> argument:</p>
   * <ul>
   * <li><strong>debug</strong> - Set to "true" to get debugging messages
   *     generated to System.out.  The default value is <code>false</code>.</li>
   * <li><strong>pathname</strong> - Relative (to the pathname specified by the
   *     "catalina.base" system property) or absolute pahtname to the
   *     XML file containing our user information, in the format supported by
   *     {@link MemoryRealm}.  The default value matches the MemoryRealm
   *     default.</li>
   * </ul>
   *
   * <p><strong>IMPLEMENTATION NOTE</strong> - This class implements
   * <code>Realm</code> only to satisfy the calling requirements of the
   * <code>GenericPrincipal</code> constructor.  It does not actually perform
   * the functionality required of a <code>Realm</code> implementation.</p>
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2001/11/13 22:42:31 $
   */
  
  public class JAASMemoryLoginModule implements LoginModule, Realm {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The callback handler responsible for answering our requests.
       */
      protected CallbackHandler callbackHandler = null;
  
  
      /**
       * Has our own <code>commit()</code> returned successfully?
       */
      protected boolean committed = false;
  
  
      /**
       * Should we log debugging messages?
       */
      protected boolean debug = false;
  
  
      /**
       * The configuration information for this <code>LoginModule</code>.
       */
      protected Map options = null;
  
  
      /**
       * The absolute or relative pathname to the XML configuration file.
       */
      protected String pathname = "conf/tomcat-users.xml";
  
  
      /**
       * The <code>Principal</code> identified by our validation, or
       * <code>null</code> if validation falied.
       */
      protected Principal principal = null;
  
  
      /**
       * The set of <code>Principals</code> loaded from our configuration file.
       */
      protected HashMap principals = new HashMap();
  
  
      /**
       * The state information that is shared with other configured
       * <code>LoginModule</code> instances.
       */
      protected Map sharedState = null;
  
  
      /**
       * The subject for which we are performing authentication.
       */
      protected Subject subject = null;
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Add a new user to the in-memory database.
       *
       * @param username User's username
       * @param password User's password (clear text)
       * @param roles Comma-delimited set of roles associated with this user
       */
      void addUser(String username, String password, String roles) {
  
          // Accumulate the list of roles for this user
          ArrayList list = new ArrayList();
          roles += ",";
          while (true) {
              int comma = roles.indexOf(',');
              if (comma < 0)
                  break;
              String role = roles.substring(0, comma).trim();
              list.add(role);
              roles = roles.substring(comma + 1);
          }
  
          // Construct and cache the Principal for this user
          GenericPrincipal principal =
              new GenericPrincipal(this, username, password, list);
          principals.put(username, principal);
  
      }
  
  
      /**
       * Phase 2 of authenticating a <code>Subject</code> when Phase 1
       * fails.  This method is called if the <code>LoginContext</code>
       * failed somewhere in the overall authentication chain.
       *
       * @return <code>true</code> if this method succeeded, or
       *  <code>false</code> if this <code>LoginModule</code> should be
       *  ignored
       *
       * @exception LoginException if the abort fails
       */
      public boolean abort() throws LoginException {
  
          // If our authentication was not successful, just return false
          if (principal == null)
              return (false);
  
          // Clean up if overall authentication failed
          if (committed)
              logout();
          else {
              committed = false;
              principal = null;
          }
          return (true);
  
      }
  
  
      /**
       * Phase 2 of authenticating a <code>Subject</code> when Phase 1
       * was successful.  This method is called if the <code>LoginContext</code>
       * succeeded in the overall authentication chain.
       *
       * @return <code>true</code> if the authentication succeeded, or
       *  <code>false</code> if this <code>LoginModule</code> should be
       *  ignored
       *
       * @exception LoginException if the commit fails
       */
      public boolean commit() throws LoginException {
  
          // If authentication was not successful, just return false
          if (principal == null)
              return (false);
  
          // Add our Principal to the Subject if needed
          if (!subject.getPrincipals().contains(principal))
              subject.getPrincipals().add(principal);
          committed = true;
          return (true);
  
      }
  
  
      /**
       * Initialize this <code>LoginModule</code> with the specified
       * configuration information.
       *
       * @param subject The <code>Subject</code> to be authenticated
       * @param callbackHandler A <code>CallbackHandler</code> for communicating
       *  with the end user as necessary
       * @param sharedState State information shared with other
       *  <code>LoginModule</code> instances
       * @param options Configuration information for this specific
       *  <code>LoginModule</code> instance
       */
      public void initialize(Subject subject, CallbackHandler callbackHandler,
                             Map sharedState, Map options) {
  
          // Save configuration values
          this.subject = subject;
          this.callbackHandler = callbackHandler;
          this.sharedState = sharedState;
          this.options = options;
  
          // Perform instance-specific initialization
          this.debug = "true".equalsIgnoreCase((String) options.get("debug"));
          if (options.get("pathname") != null)
              this.pathname = (String) options.get("pathname");
  
          // Load our defined Principals
          load();
  
      }
  
  
      /**
       * Phase 1 of authenticating a <code>Subject</code>.
       *
       * @return <code>true</code> if the authentication succeeded, or
       *  <code>false</code> if this <code>LoginModule</code> should be
       *  ignored
       *
       * @exception LoginException if the authentication fails
       */
      public boolean login() throws LoginException {
  
          // Set up our CallbackHandler requests
          if (callbackHandler == null)
              throw new LoginException("No CallbackHandler specified");
          Callback callbacks[] = new Callback[2];
          callbacks[0] = new NameCallback("Username: ");
          callbacks[1] = new PasswordCallback("Password: ", false);
  
          // Interact with the user to retrieve the username and password
          String username = null;
          String password = null;
          try {
              callbackHandler.handle(callbacks);
              username = ((NameCallback) callbacks[0]).getName();
              password =
                  new String(((PasswordCallback) callbacks[1]).getPassword());
          } catch (IOException e) {
              throw new LoginException(e.toString());
          } catch (UnsupportedCallbackException e) {
              throw new LoginException(e.toString());
          }
  
          // Validate the username and password we have received
          principal = null; // FIXME - look up and check password
  
          // Report results based on success or failure
          if (principal != null) {
              return (true);
          } else {
              throw new
                  FailedLoginException("Username or password is incorrect");
          }
  
      }
  
  
      /**
       * Log out this user.
       *
       * @return <code>true</code> in all cases because thie
       *  <code>LoginModule</code> should not be ignored
       *
       * @exception LoginException if logging out failed
       */
      public boolean logout() throws LoginException {
  
          subject.getPrincipals().remove(principal);
          committed = false;
          principal = null;
          return (true);
  
      }
  
  
      // ---------------------------------------------------------- Realm Methods
  
  
      /**
       * Return the Container with which this Realm has been associated.
       */
      public Container getContainer() {
  
          return (null);
  
      }
  
  
      /**
       * Set the Container with which this Realm has been associated.
       *
       * @param container The associated Container
       */
      public void setContainer(Container container) {
  
          ;
  
      }
  
  
      /**
       * Return descriptive information about this Realm implementation and
       * the corresponding version number, in the format
       * <code>&lt;description&gt;/&lt;version&gt;</code>.
       */
      public String getInfo() {
  
          return (null);
  
      }
  
  
      /**
       * Add a property change listener to this component.
       *
       * @param listener The listener to add
       */
      public void addPropertyChangeListener(PropertyChangeListener listener) {
  
          ;
  
      }
  
  
      /**
       * Return the Principal associated with the specified username and
       * credentials, if there is one; otherwise return <code>null</code>.
       *
       * @param username Username of the Principal to look up
       * @param credentials Password or other credentials to use in
       *  authenticating this username
       */
      public Principal authenticate(String username, String credentials) {
  
          return (null);
  
      }
  
  
      /**
       * Return the Principal associated with the specified username and
       * credentials, if there is one; otherwise return <code>null</code>.
       *
       * @param username Username of the Principal to look up
       * @param credentials Password or other credentials to use in
       *  authenticating this username
       */
      public Principal authenticate(String username, byte[] credentials) {
  
          return (null);
  
      }
  
  
      /**
       * Return the Principal associated with the specified username, which
       * matches the digest calculated using the given parameters using the
       * method described in RFC 2069; otherwise return <code>null</code>.
       *
       * @param username Username of the Principal to look up
       * @param digest Digest which has been submitted by the client
       * @param nonce Unique (or supposedly unique) token which has been used
       * for this request
       * @param realm Realm name
       * @param md5a2 Second MD5 digest used to calculate the digest :
       * MD5(Method + ":" + uri)
       */
      public Principal authenticate(String username, String digest,
                                    String nonce, String nc, String cnonce,
                                    String qop, String realm,
                                    String md5a2) {
  
          return (null);
  
      }
  
  
      /**
       * Return the Principal associated with the specified chain of X509
       * client certificates.  If there is none, return <code>null</code>.
       *
       * @param certs Array of client certificates, with the first one in
       *  the array being the certificate of the client itself.
       */
      public Principal authenticate(X509Certificate certs[]) {
  
          return (null);
  
      }
  
  
      /**
       * 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) {
  
          return (false);
  
      }
  
  
      /**
       * Remove a property change listener from this component.
       *
       * @param listener The listener to remove
       */
      public void removePropertyChangeListener(PropertyChangeListener listener) {
  
          ;
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Load the contents of our configuration file.
       */
      protected void load() {
  
          // Validate the existence of our configuration file
          File file = new File(pathname);
          if (!file.isAbsolute())
              file = new File(System.getProperty("catalina.base"), pathname);
          if (!file.exists() || !file.canRead()) {
              log("Cannot load configuration file " + file.getAbsolutePath());
              return;
          }
  
          // Load the contents of our configuration file
          Digester digester = new Digester();
          digester.setValidating(false);
          digester.addRuleSet(new MemoryRuleSet());
          try {
              digester.push(this);
              digester.parse(file);
          } catch (Exception e) {
              log("Error processing configuration file " +
                  file.getAbsolutePath(), e);
              return;
          }
  
      }
  
  
      /**
       * Log a message.
       *
       * @param message The message to be logged
       */
      protected void log(String message) {
  
          System.out.print("JAASMemoryLoginModule: ");
          System.out.println(message);
  
      }
  
  
      /**
       * Log a message and associated exception.
       *
       * @param message The message to be logged
       * @param exception The associated exception
       */
      protected void log(String message, Throwable exception) {
  
          log(message);
          exception.printStackTrace(System.out);
  
      }
  
  
  }
  
  
  
  1.1                  
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASRealm.java
  
  Index: JAASRealm.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASRealm.java,v
 1.1 2001/11/13 22:42:31 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2001/11/13 22:42:31 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  
  package org.apache.catalina.realm;
  
  
  import java.security.Principal;
  import java.util.Iterator;
  import java.util.Set;
  import javax.security.auth.Subject;
  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 org.apache.catalina.Lifecycle;
  import org.apache.catalina.LifecycleException;
  import org.apache.catalina.util.StringManager;
  
  
  /**
   * <p>Implmentation of <b>Realm</b> that authenticates users via the <em>Java
   * Authentication and Authorization Service</em> (JAAS).  JAAS support requires
   * either JDK 1.4 (which includes it as part of the standard platform) or
   * JDK 1.3 (with the plug-in <code>jaas.jar</code> file).</p>
   *
   * <p>The value configured for the <code>appName</code> property is passed to
   * the <code>javax.security.auth.login.LoginContext</code> constructor, to
   * specify the <em>application name</em> used to select the set of relevant
   * <code>LoginModules</code> required.</p>
   *
   * <p><strong>FIXME</strong> - The following issues need to be addressed before
   * the use of this module is practical:</p>
   * <ul>
   * <li>If the <code>Subject</code> returned by the
   *     underyling JAAS <code>LoginMethod</code> implementation returns more
   *     than one <code>Principal</code>, the selected one exposed to web
   *     applications is arbitrary (it will be the first one returned by an
   *     Iterator over the returned Set).</li>
   * <li>It is not clear how roles should be mapped to Principals in a JAAS
   *     environment.  Therefore, authenticated Principals will appear to have
   *     no associated roles, and <code>hasRole()</code> will always
   *     return false.</li>
   * </ul>
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2001/11/13 22:42:31 $
   */
  
  public class JAASRealm
      extends RealmBase {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The application name passed to the JAAS <code>LoginContext</code>,
       * which uses it to select the set of relevant <code>LoginModules</code>.
       */
      protected String appName = "Tomcat";
  
  
      /**
       * Descriptive information about this Realm implementation.
       */
      protected static final String info =
          "org.apache.catalina.realm.JAASRealm/1.0";
  
  
      /**
       * Descriptive information about this Realm implementation.
       */
      protected static final String name = "JAASRealm";
  
  
      /**
       * The string manager for this package.
       */
      protected static final StringManager sm =
          StringManager.getManager(Constants.Package);
  
  
      // ------------------------------------------------------------- Properties
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Return the Principal associated with the specified username and
       * credentials, if there is one; otherwise return <code>null</code>.
       *
       * 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 Principal to look up
       * @param credentials Password or other credentials to use in
       *  authenticating this username
       */
      public Principal authenticate(String username, String credentials) {
  
          // Establish a LoginContext to use for authentication
          LoginContext loginContext = null;
          try {
              loginContext = new LoginContext
                  (appName, new JAASCallbackHandler(this, username,
                                                    credentials));
          } catch (LoginException e) {
              log(sm.getString("jaasRealm.loginException", username), e);
              return (null);
          }
  
          // Negotiate a login via this LoginContext
          Subject subject = null;
          try {
              loginContext.login();
              subject = loginContext.getSubject();
              if (subject == null) {
                  if (debug >= 2)
                      log(sm.getString("jaasRealm.failedLogin", username));
                  return (null);
              }
          } catch (AccountExpiredException e) {
              if (debug >= 2)
                  log(sm.getString("jaasRealm.accountExpired", username));
              return (null);
          } catch (CredentialExpiredException e) {
              if (debug >= 2)
                  log(sm.getString("jaasRealm.credentialExpired", username));
              return (null);
          } catch (FailedLoginException e) {
              if (debug >= 2)
                  log(sm.getString("jaasRealm.failedLogin", username));
              return (null);
          } catch (LoginException e) {
              log(sm.getString("jaasRealm.loginException", username), e);
              return (null);
          }
  
          // Return the appropriate Principal for this authenticated Subject
          if (debug >= 2)
              log(sm.getString("jaasRealm.authenticateSuccess", username));
          return (selectPrincipal(subject));
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Return a short name for this Realm implementation.
       */
      protected String getName() {
  
          return (this.name);
  
      }
  
  
      /**
       * Return the password associated with the given principal's user name.
       */
      protected String getPassword(String username) {
  
          return (null);
  
      }
  
  
      /**
       * Return the Principal associated with the given user name.
       */
      protected Principal getPrincipal(String username) {
  
          return (null);
  
      }
  
  
      /**
       * Select and return the appropriate <code>Principal</code> to represent
       * the authenticated <code>Subject</code>.  The default implementation
       * simply returns the first <code>Principal</code> returned by an
       * iteration of the <code>Set</code> returned by calling
       * <code>subject.getPrincipals().iterator()</code>.  Subclasses can be
       * more intelligent, based on knowledge of the login methods in use.
       *
       * @param subject The <code>Subject</code> representing the
       *  authenticated user
       */
      protected Principal selectPrincipal(Subject subject) {
  
          Iterator principals = subject.getPrincipals().iterator();
          while (principals.hasNext()) {
              return ((Principal) principals.next());
          }
          return (null); // Should never happen
  
      }
  
  
      // ------------------------------------------------------ Lifecycle Methods
  
  
      /**
       *
       * Prepare for active use of the public methods of this Component.
       *
       * @exception IllegalStateException if this component has already been
       *  started
       * @exception 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 Component.
       *
       * @exception IllegalStateException if this component has not been started
       * @exception LifecycleException if this component detects a fatal error
       *  that needs to be reported
       */
      public void stop() throws LifecycleException {
  
          // Perform normal superclass finalization
          super.stop();
  
      }
  
  
  }
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to