You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@apache.org on 2002/01/24 23:04:55 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm JAASRealm.java LocalStrings.properties

craigmcc    02/01/24 14:04:55

  Modified:    catalina/src/share/org/apache/catalina/realm JAASRealm.java
                        LocalStrings.properties
  Log:
  Flesh out the implementation of JAASRealm so that we can still be reasonably
  independent of the way that the JAAS LoginModule is actually implemented.
  
  Revision  Changes    Path
  1.2       +153 -29   jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASRealm.java
  
  Index: JAASRealm.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASRealm.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JAASRealm.java	13 Nov 2001 22:42:31 -0000	1.1
  +++ JAASRealm.java	24 Jan 2002 22:04:55 -0000	1.2
  @@ -1,12 +1,12 @@
   /*
  - * $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 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JAASRealm.java,v 1.2 2002/01/24 22:04:55 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2002/01/24 22:04:55 $
    *
    * ====================================================================
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 1999 The Apache Software Foundation.  All rights
  + * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -65,6 +65,7 @@
   
   
   import java.security.Principal;
  +import java.util.ArrayList;
   import java.util.Iterator;
   import java.util.Set;
   import javax.security.auth.Subject;
  @@ -89,22 +90,48 @@
    * 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>
  + * <p>The JAAS Specification describes the result of a successful login as a
  + * <code>javax.security.auth.Subject</code> instance, which can contain zero
  + * or more <code>java.security.Principal</code> objects in the return value
  + * of the <code>Subject.getPrincipals()</code> method.  However, it provides
  + * no guidance on how to distinguish Principals that describe the individual
  + * user (and are thus appropriate to return as the value of
  + * request.getUserPrincipal() in a web application) from the Principal(s)
  + * that describe the authorized roles for this user.  To maintain as much
  + * independence as possible from the underlying <code>LoginMethod</code>
  + * implementation executed by JAAS, the following policy is implemented by
  + * this Realm:</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>
  + * <li>The JAAS <code>LoginModule</code> is assumed to return a
  + *     <code>Subject with at least one <code>Principal</code> instance
  + *     representing the user himself or herself, and zero or more separate
  + *     <code>Principals</code> representing the security roles authorized
  + *     for this user.</li>
  + * <li>On the <code>Principal</code> representing the user, the Principal
  + *     name is an appropriate value to return via the Servlet API method
  + *     <code>HttpServletRequest.getRemoteUser()</code>.</li>
  + * <li>On the <code>Principals</code> representing the security roles, the
  + *     name is the name of the authorized security role.</li>
  + * <li>This Realm will be configured with two lists of fully qualified Java
  + *     class names of classes that implement
  + *     <code>java.security.Principal</code> - one that identifies class(es)
  + *     representing a user, and one that identifies class(es) representing
  + *     a security role.</li>
  + * <li>As this Realm iterates over the <code>Principals</code> returned by
  + *     <code>Subject.getPrincipals()</code>, it will identify the first
  + *     <code>Principal</code> that matches the "user classes" list as the
  + *     <code>Principal</code> for this user.</li>
  + * <li>As this Realm iterates over the <code>Princpals</code> returned by
  + *     <code>Subject.getPrincipals()</code>, it will accumulate the set of
  + *     all <code>Principals</code> matching the "role classes" list as
  + *     identifying the security roles for this user.</li>
  + * <li>It is a configuration error for the JAAS login method to return a
  + *     validated <code>Subject</code> without a <code>Principal</code> that
  + *     matches the "user classes" list.</li>
    * </ul>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2001/11/13 22:42:31 $
  + * @version $Revision: 1.2 $ $Date: 2002/01/24 22:04:55 $
    */
   
   public class JAASRealm
  @@ -135,15 +162,91 @@
   
   
       /**
  +     * The list of role class names, split out for easy processing.
  +     */
  +    protected ArrayList roleClasses = new ArrayList();
  +
  +
  +    /**
        * The string manager for this package.
        */
       protected static final StringManager sm =
           StringManager.getManager(Constants.Package);
   
   
  +    /**
  +     * The set of user class names, split out for easy processing.
  +     */
  +    protected ArrayList userClasses = new ArrayList();
  +
  +
       // ------------------------------------------------------------- Properties
   
   
  +    /**
  +     * Comma-delimited list of <code>javax.security.Principal</code> classes
  +     * that represent security roles.
  +     */
  +    protected String roleClassNames = null;
  +
  +    public String getRoleClassNames() {
  +        return (this.roleClassNames);
  +    }
  +
  +    public void setRoleClassNames(String roleClassNames) {
  +        this.roleClassNames = roleClassNames;
  +        roleClasses.clear();
  +        String temp = this.roleClassNames;
  +        if (temp == null) {
  +            return;
  +        }
  +        while (true) {
  +            int comma = temp.indexOf(',');
  +            if (comma < 0) {
  +                break;
  +            }
  +            roleClasses.add(temp.substring(0, comma).trim());
  +            temp = temp.substring(comma + 1);
  +        }
  +        temp = temp.trim();
  +        if (temp.length() > 0) {
  +            roleClasses.add(temp);
  +        }
  +    }
  +
  +
  +    /**
  +     * Comma-delimited list of <code>javax.security.Principal</code> classes
  +     * that represent individual users.
  +     */
  +    protected String userClassNames = null;
  +
  +    public String getUserClassNames() {
  +        return (this.userClassNames);
  +    }
  +
  +    public void setUserClassNames(String userClassNames) {
  +        this.userClassNames = userClassNames;
  +        userClasses.clear();
  +        String temp = this.roleClassNames;
  +        if (temp == null) {
  +            return;
  +        }
  +        while (true) {
  +            int comma = temp.indexOf(',');
  +            if (comma < 0) {
  +                break;
  +            }
  +            userClasses.add(temp.substring(0, comma).trim());
  +            temp = temp.substring(comma + 1);
  +        }
  +        temp = temp.trim();
  +        if (temp.length() > 0) {
  +            userClasses.add(temp);
  +        }
  +    }
  +
  +
       // --------------------------------------------------------- Public Methods
   
   
  @@ -201,9 +304,15 @@
           }
   
           // Return the appropriate Principal for this authenticated Subject
  -        if (debug >= 2)
  +        Principal principal = createPrincipal(subject);
  +        if (principal == null) {
  +            log(sm.getString("jaasRealm.authenticateError", username));
  +            return (null);
  +        }
  +        if (debug >= 2) {
               log(sm.getString("jaasRealm.authenticateSuccess", username));
  -        return (selectPrincipal(subject));
  +        }
  +        return (principal);
   
       }
   
  @@ -245,23 +354,38 @@
   
   
       /**
  -     * 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.
  +     * Construct and return a <code>java.security.Principal</code> instance
  +     * representing the authenticated user for the specified Subject.  If no
  +     * such Principal can be constructed, return <code>null</code>.
        *
  -     * @param subject The <code>Subject</code> representing the
  -     *  authenticated user
  +     * @param subject The Subject representing the logged in user
        */
  -    protected Principal selectPrincipal(Subject subject) {
  +    protected Principal createPrincipal(Subject subject) {
  +
  +        // Prepare to scan the Principals for this Subject
  +        String username = null;
  +        String password = null; // Will not be carried forward
  +        ArrayList roles = new ArrayList();
   
  +        // Scan the Principals for this Subject
           Iterator principals = subject.getPrincipals().iterator();
           while (principals.hasNext()) {
  -            return ((Principal) principals.next());
  +            Principal principal = (Principal) principals.next();
  +            String principalClass = principal.getClass().getName();
  +            if ((username == null) && userClasses.contains(principalClass)) {
  +                username = principal.getName();
  +            }
  +            if (roleClasses.contains(principalClass)) {
  +                roles.add(principal.getName());
  +            }
  +        }
  +
  +        // Create the resulting Principal for our authenticated user
  +        if (username != null) {
  +            return (new GenericPrincipal(this, username, password, roles));
  +        } else {
  +            return (null);
           }
  -        return (null); // Should never happen
   
       }
   
  
  
  
  1.7       +2 -1      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- LocalStrings.properties	20 Jan 2002 03:00:57 -0000	1.6
  +++ LocalStrings.properties	24 Jan 2002 22:04:55 -0000	1.7
  @@ -1,4 +1,4 @@
  -# $Id: LocalStrings.properties,v 1.6 2002/01/20 03:00:57 craigmcc Exp $
  +# $Id: LocalStrings.properties,v 1.7 2002/01/24 22:04:55 craigmcc Exp $
   
   # language 
   
  @@ -30,6 +30,7 @@
   realmBase.hasRoleFailure=Username {0} does NOT have role {1}
   realmBase.hasRoleSuccess=Username {0} has role {1}
   realmBase.notStarted=This Realm has not yet been started
  +userDatabaseRealm.authenticateError=Login configuration error authenticating username {0}
   userDatabaseRealm.authenticateFailure=Username {0} NOT successfully authenticated
   userDatabaseRealm.authenticateSuccess=Username {0} successfully authenticated
   userDatabaseRealm.lookup=Exception looking up UserDatabase under key {0}
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>