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...@locus.apache.org on 2000/07/11 00:55:22 UTC

cvs commit: jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy package.html SecurityCollection.java SecurityConstraint.java

craigmcc    00/07/10 15:55:22

  Modified:    proposals/catalina/src/share/org/apache/tomcat/deploy
                        SecurityCollection.java SecurityConstraint.java
  Added:       proposals/catalina/src/share/org/apache/tomcat/deploy
                        package.html
  Log:
  Tune the behavior of these classes so that checks against a specific
  constraint do not require any object creations.  Also, add a package
  documentation file (for Javadoc) that documents the assumptions of how
  these objects will be used -- i.e. read-only access once they are
  initialized -- because no synchronization declarations are used.
  
  NOTE:  Testing these changes has uncovered a bug in the Catalina
  implementation of form-based login that will be fixed separately.
  
  Revision  Changes    Path
  1.3       +101 -89   jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy/SecurityCollection.java
  
  Index: SecurityCollection.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy/SecurityCollection.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- SecurityCollection.java	2000/05/03 22:58:26	1.2
  +++ SecurityCollection.java	2000/07/10 22:55:22	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy/SecurityCollection.java,v 1.2 2000/05/03 22:58:26 craigmcc Exp $
  - * $Revision: 1.2 $
  - * $Date: 2000/05/03 22:58:26 $
  + * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy/SecurityCollection.java,v 1.3 2000/07/10 22:55:22 craigmcc Exp $
  + * $Revision: 1.3 $
  + * $Date: 2000/07/10 22:55:22 $
    *
    * ====================================================================
    *
  @@ -65,23 +65,19 @@
   package org.apache.tomcat.deploy;
   
   
  -import java.util.Enumeration;
  -import java.util.Hashtable;
  -
  -
   /**
    * Representation of a web resource collection for a web application's security
    * constraint, as represented in a <code>&lt;web-resource-collection&gt;</code>
    * element in the deployment descriptor.
    * <p>
  - * <b>WARNING</b>:  The property setting methods in this class are for use by
  - * the application logic that parses a web application deployment descriptor.
  - * They should not be called by a Context implementation (or an associated
  - * Valve or Interceptor that implements the authentication and authorization
  - * constraints expressed here).
  + * <b>WARNING</b>:  It is assumed that instances of this class will be created
  + * and modified only within the context of a single thread, before the instance
  + * is made visible to the remainder of the application.  After that, only read
  + * access is expected.  Therefore, none of the read and write access within
  + * this class is synchronized.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.2 $ $Date: 2000/05/03 22:58:26 $
  + * @version $Revision: 1.3 $ $Date: 2000/07/10 22:55:22 $
    */
   
   public final class SecurityCollection {
  @@ -94,8 +90,20 @@
        * Construct a new security collection instance with default values.
        */
       public SecurityCollection() {
  +
  +	this(null, null);
  +
  +    }
  +
  +
  +    /**
  +     * Construct a new security collection instance with specified values.
  +     *
  +     * @param name Name of this security collection
  +     */
  +    public SecurityCollection(String name) {
   
  -        super();
  +	this(name, null);
   
       }
   
  @@ -103,14 +111,14 @@
       /**
        * Construct a new security collection instance with specified values.
        *
  -     * @param constraint Security constraint we are attached to
        * @param name Name of this security collection
  +     * @param description Description of this security collection
        */
  -    public SecurityCollection(SecurityConstraint constraint, String name) {
  +    public SecurityCollection(String name, String description) {
   
   	super();
  -	setConstraint(constraint);
   	setName(name);
  +	setDescription(description);
   
       }
   
  @@ -119,15 +127,15 @@
   
   
       /**
  -     * The security constraint we are attached to.
  +     * Description of this web resource collection.
        */
  -    private SecurityConstraint constraint = null;
  +    private String description = null;
   
   
       /**
        * The HTTP methods covered by this web resource collection.
        */
  -    private String[] methods = new String[0];
  +    private String methods[] = new String[0];
   
   
       /**
  @@ -137,51 +145,32 @@
   
   
       /**
  -     * The URL patterns protected by this security collection, keyed by
  -     * pattern.
  +     * The URL patterns protected by this security collection.
        */
  -    private Hashtable patterns = new Hashtable();
  +    private String patterns[] = new String[0];
   
   
       // ------------------------------------------------------------- Properties
   
   
       /**
  -     * Return the security constraint we are attached to.
  +     * Return the description of this web resource collection.
        */
  -    public SecurityConstraint getConstraint() {
  +    public String getDescription() {
   
  -	return (this.constraint);
  +	return (this.description);
   
       }
   
   
       /**
  -     * Set the security constraint we are attached to.
  +     * Set the description of this web resource collection.
        *
  -     * @param constraint The associated constraint
  +     * @param description The new description
        */
  -    public void setConstraint(SecurityConstraint constraint) {
  +    public void setDescription(String description) {
   
  -        // Remove our patterns from the old constraint (if any)
  -        if (this.constraint != null) {
  -	    Enumeration currentPatterns = this.patterns.keys();
  -	    while (currentPatterns.hasMoreElements()) {
  -	        String currentPattern = (String) currentPatterns.nextElement();
  -		this.constraint.removePattern(currentPattern);
  -	    }
  -	}
  -
  -        this.constraint = constraint;
  -
  -	// Set our patterns in the new constraint (if any)
  -        if (this.constraint != null) {
  -	    Enumeration currentPatterns = this.patterns.keys();
  -	    while (currentPatterns.hasMoreElements()) {
  -	        String currentPattern = (String) currentPatterns.nextElement();
  -		this.constraint.addPattern(currentPattern, this);
  -	    }
  -	}
  +	this.description = description;
   
       }
   
  @@ -218,16 +207,11 @@
   
   	if (method == null)
   	    return;
  -	synchronized (methods) {
  -	    String results[] = new String[methods.length + 1];
  -	    for (int i = 0; i < methods.length; i++) {
  -		if (method.equals(methods[i]))
  -		    return;
  -		results[i] = methods[i];
  -	    }
  -	    results[results.length - 1] = method;
  -	    methods = results;
  -	}
  +	String results[] = new String[methods.length + 1];
  +	for (int i = 0; i < methods.length; i++)
  +	    results[i] = methods[i];
  +	results[methods.length] = method;
  +	methods = results;
   
       }
   
  @@ -237,9 +221,13 @@
        */
       public void addPattern(String pattern) {
   
  -	patterns.put(pattern, pattern);
  -	if (constraint != null)
  -	    constraint.addPattern(pattern, this);
  +	if (pattern == null)
  +	    return;
  +	String results[] = new String[patterns.length + 1];
  +	for (int i = 0; i < patterns.length; i++)
  +	    results[i] = patterns[i];
  +	results[patterns.length] = pattern;
  +	patterns = results;
   
       }
   
  @@ -252,12 +240,10 @@
        */
       public boolean findMethod(String method) {
   
  -	if (method == null)
  -	    return (false);
   	if (methods.length == 0)
   	    return (true);
   	for (int i = 0; i < methods.length; i++) {
  -	    if (method.equals(methods[i]))
  +	    if (methods[i].equals(method))
   		return (true);
   	}
   	return (false);
  @@ -266,13 +252,29 @@
   
   
       /**
  +     * Return the set of HTTP request methods that are part of this web
  +     * resource collection, or a zero-length array if all request methods
  +     * are included.
  +     */
  +    public String[] findMethods() {
  +
  +	return (methods);
  +
  +    }
  +
  +
  +    /**
        * Is the specified pattern part of this web resource collection?
        *
        * @param pattern Pattern to be compared
        */
       public boolean findPattern(String pattern) {
   
  -	return (patterns.get(pattern) != null);
  +	for (int i = 0; i < patterns.length; i++) {
  +	    if (patterns[i].equals(pattern))
  +		return (true);
  +	}
  +	return (false);
   
       }
   
  @@ -284,13 +286,7 @@
        */
       public String[] findPatterns() {
   
  -	synchronized (patterns) {
  -	    String results[] = new String[patterns.size()];
  -	    Enumeration urls = patterns.keys();
  -	    for (int i = 0; i < results.length; i++)
  -		results[i] = (String) urls.nextElement();
  -	    return (results);
  -	}
  +	return (patterns);
   
       }
   
  @@ -305,26 +301,23 @@
   
   	if (method == null)
   	    return;
  -	synchronized (methods) {
  -	    int n = -1;
  -	    for (int i = 0; i < methods.length; i++) {
  -		if (method.equals(methods[i])) {
  -		    n = i;
  -		    break;
  -		}
  +	int n = -1;
  +	for (int i = 0; i < methods.length; i++) {
  +	    if (methods[i].equals(method)) {
  +		n = i;
  +		break;
   	    }
  -	    if (n < 0)
  -		return;
  -	    String results[] = new String[methods.length - 1];
  +	}
  +	if (n >= 0) {
   	    int j = 0;
  +	    String results[] = new String[methods.length - 1];
   	    for (int i = 0; i < methods.length; i++) {
  -		if (i == n)
  -		    continue;
  -		results[j++] = methods[i];
  +		if (i != n)
  +		    results[j++] = methods[i];
   	    }
   	    methods = results;
   	}
  -
  +	
       }
   
   
  @@ -336,9 +329,24 @@
        */
       public void removePattern(String pattern) {
   
  -	patterns.remove(pattern);
  -	if (constraint != null)
  -	  constraint.removePattern(pattern);
  +	if (pattern == null)
  +	    return;
  +	int n = -1;
  +	for (int i = 0; i < patterns.length; i++) {
  +	    if (patterns[i].equals(pattern)) {
  +		n = i;
  +		break;
  +	    }
  +	}
  +	if (n >= 0) {
  +	    int j = 0;
  +	    String results[] = new String[patterns.length - 1];
  +	    for (int i = 0; i < patterns.length; i++) {
  +		if (i != n)
  +		    results[j++] = patterns[i];
  +	    }
  +	    patterns = results;
  +	}
   
       }
   
  @@ -350,6 +358,10 @@
   
           StringBuffer sb = new StringBuffer("SecurityCollection[");
   	sb.append(name);
  +	if (description != null) {
  +	    sb.append(", ");
  +	    sb.append(description);
  +	}
   	sb.append("]");
   	return (sb.toString());
   
  
  
  
  1.3       +101 -136  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy/SecurityConstraint.java
  
  Index: SecurityConstraint.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy/SecurityConstraint.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- SecurityConstraint.java	2000/05/03 22:58:27	1.2
  +++ SecurityConstraint.java	2000/07/10 22:55:22	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy/SecurityConstraint.java,v 1.2 2000/05/03 22:58:27 craigmcc Exp $
  - * $Revision: 1.2 $
  - * $Date: 2000/05/03 22:58:27 $
  + * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy/SecurityConstraint.java,v 1.3 2000/07/10 22:55:22 craigmcc Exp $
  + * $Revision: 1.3 $
  + * $Date: 2000/07/10 22:55:22 $
    *
    * ====================================================================
    *
  @@ -65,23 +65,19 @@
   package org.apache.tomcat.deploy;
   
   
  -import java.util.Enumeration;
  -import java.util.Hashtable;
  -
  -
   /**
    * Representation of a security constraint element for a web application,
    * as represented in a <code>&lt;security-constraint&gt;</code> element in the
    * deployment descriptor.
    * <p>
  - * <b>WARNING</b>:  The property setting methods in this class are for use by
  - * the application logic that parses a web application deployment descriptor.
  - * They should not be called by a Context implementation (or an associated
  - * Valve or Interceptor that implements the authentication and authorization
  - * constraints expressed here).
  + * <b>WARNING</b>:  It is assumed that instances of this class will be created
  + * and modified only within the context of a single thread, before the instance
  + * is made visible to the remainder of the application.  After that, only read
  + * access is expected.  Therefore, none of the read and write access within
  + * this class is synchronized.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.2 $ $Date: 2000/05/03 22:58:27 $
  + * @version $Revision: 1.3 $ $Date: 2000/07/10 22:55:22 $
    */
   
   public final class SecurityConstraint {
  @@ -112,20 +108,12 @@
   
       /**
        * The set of web resource collections protected by this security
  -     * constraint, keyed by resource collection name.
  +     * constraint.
        */
  -    private Hashtable collections = new Hashtable();
  +    private SecurityCollection collections[] = new SecurityCollection[0];
   
   
       /**
  -     * The URL patterns that are parts of the web resource collections
  -     * managed by this security constraint.  The key is the pattern itself,
  -     * while the value is the corresponding collection.
  -     */
  -    private Hashtable patterns = new Hashtable();
  -
  -
  -    /**
        * The user data constraint for this security constraint.  Must be NONE,
        * INTEGRAL, or CONFIDENTIAL.
        */
  @@ -165,21 +153,17 @@
        * Add an authorization role, which is a role name that will be
        * permitted access to the resources protected by this security constraint.
        *
  -     * @param role Role name to be added
  +     * @param authRole Role name to be added
        */
  -    public void addAuthRole(String role) {
  +    public void addAuthRole(String authRole) {
   
  -	if (role == null)
  +	if (authRole == null)
   	    return;
  -	synchronized (authRoles) {
  -	    if (findAuthRole(role))
  -		return;
  -	    String newRoles[] = new String[authRoles.length + 1];
  -	    for (int i = 0; i < authRoles.length; i++)
  -		newRoles[i] = authRoles[i];
  -	    newRoles[newRoles.length - 1] = role;
  -	    authRoles = newRoles;
  -	}
  +	String results[] = new String[authRoles.length + 1];
  +	for (int i = 0; i < authRoles.length; i++)
  +	    results[i] = authRoles[i];
  +	results[authRoles.length] = authRole;
  +	authRoles = results;
   
       }
   
  @@ -191,20 +175,15 @@
        * @param collection The new web resource collection
        */
       public void addCollection(SecurityCollection collection) {
  -
  -	collections.put(collection.getName(), collection);
   
  -    }
  -
  -
  -    /**
  -     * Create and return a web resource collection with default values.
  -     *
  -     * @param name Name of the new web resource collection
  -     */
  -    public SecurityCollection createCollection(String name) {
  -
  -	return (new SecurityCollection(this, name));
  +	if (collection == null)
  +	    return;
  +	SecurityCollection results[] =
  +	    new SecurityCollection[collections.length + 1];
  +	for (int i = 0; i < collections.length; i++)
  +	    results[i] = collections[i];
  +	results[collections.length] = collection;
  +	collections = results;
   
       }
   
  @@ -219,11 +198,9 @@
   
   	if (role == null)
   	    return (false);
  -	synchronized (authRoles) {
  -	    for (int i = 0; i < authRoles.length; i++) {
  -		if (role.equals(authRoles[i]))
  -		    return (true);
  -	    }
  +	for (int i = 0; i < authRoles.length; i++) {
  +	    if (role.equals(authRoles[i]))
  +		return (true);
   	}
   	return (false);
   
  @@ -238,7 +215,7 @@
        */
       public String[] findAuthRoles() {
   
  -	return (authRoles);	// Assumption - caller will not modify
  +	return (authRoles);
   
       }
   
  @@ -251,25 +228,25 @@
        */
       public SecurityCollection findCollection(String name) {
   
  -	return ((SecurityCollection) collections.get(name));
  +	if (name == null)
  +	    return (null);
  +	for (int i = 0; i < collections.length; i++) {
  +	    if (name.equals(collections[i].getName()))
  +		return (collections[i]);
  +	}
  +	return (null);
   
       }
   
   
       /**
  -     * Return the names of all web resource collections protected by this
  +     * Return all of the web resource collections protected by this
        * security constraint.  If there are none, a zero-length array is
        * returned.
        */
  -    public String[] findCollections() {
  +    public SecurityCollection[] findCollections() {
   
  -	synchronized (collections) {
  -	    String results[] = new String[collections.size()];
  -	    Enumeration names = collections.keys();
  -	    for (int i = 0; i < results.length; i++)
  -		results[i] = (String) names.nextElement();
  -	    return (results);
  -	}
  +	return (collections);
   
       }
   
  @@ -283,22 +260,23 @@
        */
       public boolean included(String uri, String method) {
   
  -	// Check all defined patterns
  -	SecurityCollection collection = null;
  -	Enumeration patterns = this.patterns.keys();
  -	while (patterns.hasMoreElements()) {
  -	    String pattern = (String) patterns.nextElement();
  -	    if (matchPattern(uri, pattern)) {
  -		collection = (SecurityCollection) this.patterns.get(pattern);
  -		break;
  +	// We cannot match without a valid request method
  +	if (method == null)
  +	    return (false);
  +
  +	// Check all of the collections included in this constraint
  +	for (int i = 0; i < collections.length; i++) {
  +	    if (!collections[i].findMethod(method))
  +		continue;
  +	    String patterns[] = collections[i].findPatterns();
  +	    for (int j = 0; j < patterns.length; j++) {
  +		if (matchPattern(uri, patterns[j]))
  +		    return (true);
   	    }
   	}
   
  -	// Match on HTTP request method as well
  -	if (collection == null)
  -	    return (false);
  -	else
  -	    return (collection.findMethod(method));
  +	// No collection included in this constraint matches this request
  +	return (false);
   
       }
   
  @@ -307,23 +285,27 @@
        * Remove the specified role from the set of roles permitted to access
        * the resources protected by this security constraint.
        *
  -     * @param role Role name to be removed
  +     * @param authRole Role name to be removed
        */
  -    public void removeAuthRole(String role) {
  +    public void removeAuthRole(String authRole) {
   
  -	if (role == null)
  +	if (authRole == null)
   	    return;
  -	synchronized (authRoles) {
  -	    if (!findAuthRole(role))
  -		return;
  -	    String newRoles[] = new String[authRoles.length - 1];
  +	int n = -1;
  +	for (int i = 0; i < authRoles.length; i++) {
  +	    if (authRoles[i].equals(authRole)) {
  +		n = i;
  +		break;
  +	    }
  +	}
  +	if (n >= 0) {
   	    int j = 0;
  +	    String results[] = new String[authRoles.length - 1];
   	    for (int i = 0; i < authRoles.length; i++) {
  -		if (role.equals(authRoles[i]))
  -		    continue;
  -		newRoles[j++] = authRoles[i];
  +		if (i != n)
  +		    results[j++] = authRoles[i];
   	    }
  -	    authRoles = newRoles;
  +	    authRoles = results;
   	}
   
       }
  @@ -337,7 +319,25 @@
        */
       public void removeCollection(SecurityCollection collection) {
   
  -	collections.remove(collection.getName());
  +	if (collection == null)
  +	    return;
  +	int n = -1;
  +	for (int i = 0; i < collections.length; i++) {
  +	    if (collections[i].equals(collection)) {
  +		n = i;
  +		break;
  +	    }
  +	}
  +	if (n >= 0) {
  +	    int j = 0;
  +	    SecurityCollection results[] =
  +		new SecurityCollection[collections.length - 1];
  +	    for (int i = 0; i < collections.length; i++) {
  +		if (i != n)
  +		    results[j++] = collections[i];
  +	    }
  +	    collections = results;
  +	}
   
       }
   
  @@ -348,16 +348,10 @@
       public String toString() {
   
           StringBuffer sb = new StringBuffer("SecurityConstraint[");
  -	int n = 0;
  -	Enumeration names = collections.keys();
  -	while (names.hasMoreElements()) {
  -	    String name = (String) names.nextElement();
  -	    if (n > 0)
  -	        sb.append(",");
  -	    sb.append("(");
  -	    sb.append(name);
  -	    sb.append(")");
  -	    n++;
  +	for (int i = 0; i < collections.length; i++) {
  +	    if (i > 0)
  +		sb.append(", ");
  +	    sb.append(collections[i].getName());
   	}
   	sb.append("]");
   	return (sb.toString());
  @@ -365,44 +359,14 @@
       }
   
   
  -    // ------------------------------------------------ Package Private Methods
  -
  -
  -    /**
  -     * Add a URL pattern that is part of one of our constituent web resource
  -     * collections.
  -     *
  -     * @param pattern URL pattern to be added
  -     * @param collection The corresponding collection
  -     */
  -    void addPattern(String pattern, SecurityCollection collection) {
  -
  -	patterns.put(pattern, collection);
  -
  -    }
  -
  -
  -    /**
  -     * Remove a URL pattern that was part of one of our constituent web
  -     * resource collections.
  -     *
  -     * @param pattern URL pattern to be removed
  -     */
  -    void removePattern(String pattern) {
  -
  -	patterns.remove(pattern);
  -
  -    }
  -
  -
       // -------------------------------------------------------- Private Methods
   
   
       /**
        * Does the specified request path match the specified URL pattern?
  +     * This method follows the same rules (in the same order) as those used
  +     * for mapping requests to servlets.
        *
  -     * XXX - Shouldn't this be a shared utility method someplace?
  -     *
        * @param path Context-relative request path to be checked
        *  (must start with '/')
        * @param pattern URL pattern to be compared against
  @@ -419,10 +383,6 @@
   	if (path.equals(pattern))
   	    return (true);
   
  -	// Check for universal mapping
  -	if (pattern.equals("/"))
  -	    return (true);
  -
   	// Check for path prefix matching
   	if (pattern.startsWith("/") && pattern.endsWith("/*")) {
   	    pattern = pattern.substring(0, pattern.length() - 2);
  @@ -442,14 +402,19 @@
   	}
   
   	// Check for suffix matching
  -	else if (pattern.startsWith("*.")) {
  +	if (pattern.startsWith("*.")) {
   	    int slash = path.lastIndexOf('/');
   	    int period = path.lastIndexOf('.');
   	    if ((slash >= 0) && (period > slash) &&
   		path.endsWith(pattern.substring(1))) {
   		return (true);
   	    }
  +	    return (false);
   	}
  +
  +	// Check for universal mapping
  +	if (pattern.equals("/"))
  +	    return (true);
   
   	return (false);
   
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/deploy/package.html
  
  Index: package.html
  ===================================================================
  This package contains Java objects that represent complex data structures
  from the web application deployment descriptor file (<code>web.xml</code>).
  It is assumed that these objects will be initialized within the context of
  a single thread, and then referenced in a read-only manner subsequent to that
  time.  Therefore, no multi-thread synchronization is utilized within the
  implementation classes.