Home » apache-tomcat-6.0.26-src » org.apache » tomcat » security » file » [javadoc | source]

    1   /*
    2    * The Apache Software License, Version 1.1
    3    *
    4    * Copyright (c) 1999 The Apache Software Foundation.  All rights 
    5    * reserved.
    6    *
    7    * Redistribution and use in source and binary forms, with or without
    8    * modification, are permitted provided that the following conditions
    9    * are met:
   10    *
   11    * 1. Redistributions of source code must retain the above copyright
   12    *    notice, this list of conditions and the following disclaimer. 
   13    *
   14    * 2. Redistributions in binary form must reproduce the above copyright
   15    *    notice, this list of conditions and the following disclaimer in
   16    *    the documentation and/or other materials provided with the
   17    *    distribution.
   18    *
   19    * 3. The end-user documentation included with the redistribution, if
   20    *    any, must include the following acknowlegement:  
   21    *       "This product includes software developed by the 
   22    *        Apache Software Foundation (http://www.apache.org/)."
   23    *    Alternately, this acknowlegement may appear in the software itself,
   24    *    if and wherever such third-party acknowlegements normally appear.
   25    *
   26    * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   27    *    Foundation" must not be used to endorse or promote products derived
   28    *    from this software without prior written permission. For written 
   29    *    permission, please contact apache@apache.org.
   30    *
   31    * 5. Products derived from this software may not be called "Apache"
   32    *    nor may "Apache" appear in their names without prior written
   33    *    permission of the Apache Group.
   34    *
   35    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   36    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   37    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   38    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   39    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   40    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   41    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   42    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   43    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   44    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   45    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   46    * SUCH DAMAGE.
   47    * ====================================================================
   48    *
   49    * This software consists of voluntary contributions made by many
   50    * individuals on behalf of the Apache Software Foundation.  For more
   51    * information on the Apache Software Foundation, please see
   52    * <http://www.apache.org/>.
   53    *
   54    * [Additional notices, if required by prior licensing conditions]
   55    *
   56    */ 
   57   
   58   
   59   package org.apache.tomcat.security.file;
   60   
   61   import java.io.ByteArrayOutputStream;
   62   import java.io.InputStream;
   63   import java.io.IOException;
   64   import java.io.OutputStream;
   65   import java.io.PrintWriter;
   66   import java.util.Enumeration;
   67   import java.util.Hashtable;
   68   import java.util.Vector;
   69   import org.apache.tomcat.util.HexUtils;
   70   import org.apache.tomcat.util.StringManager;
   71   import org.apache.tomcat.util.XMLParser;
   72   import org.apache.tomcat.util.XMLTree;
   73   import org.xml.sax.SAXException;
   74   import org.xml.sax.SAXParseException;
   75   
   76   /**
   77    * In-memory cache of the set of users, groups, and their associated roles,
   78    * stored in an XML-formatted file that conforms to DTD found in the
   79    * <code>tomcat-users.dtd</code> file in this directory.
   80    *
   81    * @author Craig R. McClanahan
   82    * @version $Revision: 1.2 $ $Date: 2000/02/26 02:32:14 $
   83    */
   84   
   85   public final class FileRealmDatabase {
   86   
   87   
   88       /**
   89        * The set of groups defined within this database, keyed by group name.
   90        */
   91       private Hashtable groups = new Hashtable();
   92   
   93   
   94       /**
   95        * The set of roles defined within this database, keyed by role name.
   96        * The value objects are arbitrary.
   97        */
   98       private Hashtable roles = new Hashtable();
   99   
  100   
  101       /**
  102        * The internationalized string constants for this package.
  103        */
  104       private StringManager sm =
  105   	StringManager.getManager(Constants.Package);
  106   
  107   
  108       /**
  109        * The set of users defined within this database, keyed by username.
  110        */
  111       private Hashtable users = new Hashtable();
  112   
  113   
  114       /**
  115        * Construct a new empty database.
  116        */
  117       public FileRealmDatabase() {
  118   
  119   	super();
  120   
  121       }
  122   
  123   
  124       /**
  125        * Construct a new database initialized from the specified input stream
  126        *
  127        * @param stream Stream from which to load the contents of this database
  128        *
  129        * @exception IOException if an input/output error occurs
  130        * @exception SAXParseException if a parsing exception occurs
  131        * @exception SAXException if a processing exception occurs
  132        */
  133       public FileRealmDatabase(InputStream stream)
  134   	throws IOException, SAXParseException, SAXException {
  135   
  136   	super();
  137   	read(stream);
  138   
  139       }
  140   
  141   
  142       /**
  143        * [Package Private] Add this group to the set of defined groups.
  144        */
  145       void addGroup(FileRealmGroup group) {
  146   
  147   	groups.put(group.getName(), group);
  148   
  149       }
  150   
  151   
  152       /**
  153        * [Package Private] Add this role to the set of defined roles.
  154        */
  155       void addRole(String role) {
  156   
  157   	roles.put(role, role);
  158   
  159       }
  160   
  161   
  162       /**
  163        * [Package Private] Add this user to the set of defined users.
  164        */
  165       void addUser(FileRealmUser user) {
  166   
  167   	users.put(user.getName(), user);
  168   
  169       }
  170   
  171   
  172       /**
  173        * Create and return a new group.
  174        *
  175        * @param name Group name of the newly created group
  176        *
  177        * @exception IllegalArgumentException if this group name is already in use
  178        */
  179       public FileRealmGroup createGroup(String name) {
  180   
  181   	if (getGroup(name) != null)
  182   	    throw new IllegalArgumentException(
  183                   sm.getString("file.createGroup.exists", name));
  184   
  185   	return (new FileRealmGroup(this, name));
  186   
  187       }
  188   
  189   
  190       /**
  191        * Create and return a new user.
  192        *
  193        * @param name Username of the newly created user
  194        * @param password Cleartext password of the newly created user
  195        *
  196        * @exception IllegalArgumentException if this username is already in use
  197        */
  198       public FileRealmUser createUser(String name, String password) {
  199   
  200   	if (getUser(name) != null)
  201   	    throw new IllegalArgumentException(
  202   	        sm.getString("file.createUser.exists", name));
  203   
  204   	return (new FileRealmUser(this, name, password));
  205   
  206       }
  207   
  208   
  209       /**
  210        * Create and return a new user.
  211        *
  212        * @param name Username of the newly created user
  213        * @param password Encrypted password of the newly created user
  214        *
  215        * @exception IllegalArgumentException if this username is already in use
  216        */
  217       public FileRealmUser createUser(String name, byte[] password) {
  218   
  219   	if (getUser(name) != null)
  220   	    throw new IllegalArgumentException(
  221   	        sm.getString("file.createUser.exists", name));
  222   
  223   	return (new FileRealmUser(this, name, password));
  224   
  225       }
  226   
  227   
  228       /**
  229        * Return the group with the specified name, if any.
  230        *
  231        * @param name Name of the desired group
  232        */
  233       public FileRealmGroup getGroup(String name) {
  234   
  235   	return ((FileRealmGroup) groups.get(name));
  236   
  237       }
  238   
  239   
  240       /**
  241        * Return an enumeration of the defined groups in this database.
  242        */
  243       public Enumeration getGroups() {
  244   
  245   	return (groups.elements());
  246   
  247       }
  248   
  249   
  250       /**
  251        * Return an enumeration of the defined roles in this database.
  252        */
  253       public Enumeration getRoles() {
  254   
  255   	return (roles.keys());
  256   
  257       }
  258   
  259   
  260       /**
  261        * Return the user with the specified name, if any.
  262        *
  263        * @param name Name of the desired user
  264        */
  265       public FileRealmUser getUser(String name) {
  266   
  267   	return ((FileRealmUser) users.get(name));
  268   
  269       }
  270   
  271   
  272       /**
  273        * Return an enumeration of the defined users in this database.
  274        */
  275       public Enumeration getUsers() {
  276   
  277   	return (users.elements());
  278   
  279       }
  280   
  281   
  282       /**
  283        * Is the specified role valid within this database?
  284        *
  285        * @param role Role to be tested
  286        */
  287       public boolean hasRole(String role) {
  288   
  289   	return (roles.get(role) != null);
  290   
  291       }
  292   
  293   
  294       /**
  295        * Load the contents of this database from the specified input stream.
  296        * IMPLEMENTATION NOTE:  The order of processing (users, groups, and
  297        * then roles) is important to correctly process XML files with forward
  298        * references in them.
  299        *
  300        * @param stream Input stream to read from
  301        *
  302        * @exception IOException if an input/output error occurs
  303        * @exception SAXParseException if a parsing exception occurs
  304        * @exception SAXException if a processing exception occurs
  305        */
  306       public void read(InputStream stream)
  307   	throws IOException, SAXParseException, SAXException {
  308   
  309   	reset();
  310   
  311   	// Parse the input stream into an XMLTree
  312   	XMLParser parser = new XMLParser();
  313   	XMLTree config = parser.process(stream);
  314   	if (!config.getName().equals(Constants.Element.TOMCAT_USERS))
  315   	    return;
  316   	Enumeration e;
  317   
  318   	// Process the defined users
  319   	e = config.getElements(Constants.Element.USER).elements();
  320   	while (e.hasMoreElements())
  321   	    readUser((XMLTree) e.nextElement());
  322   
  323   	// Process the defined groups
  324   	e = config.getElements(Constants.Element.GROUP).elements();
  325   	while (e.hasMoreElements())
  326   	    readGroup((XMLTree) e.nextElement());
  327   
  328   	// Process the defined roles
  329   	e = config.getElements(Constants.Element.ROLE).elements();
  330   	while (e.hasMoreElements())
  331   	    readRole((XMLTree) e.nextElement());
  332   
  333       }
  334   
  335   
  336       /**
  337        * Convert the specified XML element into a new group.
  338        *
  339        * @param element XML element for this group
  340        */
  341       private void readGroup(XMLTree element) {
  342   
  343   	// Construct the group itself
  344   	String name =
  345   	    (String) element.getAttribute(Constants.Attribute.NAME);
  346   	FileRealmGroup group = createGroup(name);
  347   
  348   	// Process the associated group memberships
  349   	Enumeration e =
  350   	    element.getElements(Constants.Element.USER_MEMBER).elements();
  351   	while (e.hasMoreElements()) {
  352   	    XMLTree um = (XMLTree) e.nextElement();
  353   	    String username =
  354   		(String) um.getAttribute(Constants.Attribute.NAME);
  355   	    FileRealmUser user = getUser(username);
  356   	    if (user != null)
  357   		user.addGroup(group);
  358   	}
  359   
  360   	// XXX: Does not support the "anyone" sub-element
  361   
  362       }
  363   
  364   
  365       /**
  366        * Convert the specified XML element into a new role.
  367        *
  368        * @param element XML element for this role
  369        */
  370       private void readRole(XMLTree element) {
  371   
  372   	// Construct the role itself
  373   	String role =
  374   	    (String) element.getAttribute(Constants.Attribute.NAME);
  375   	Enumeration e = null;
  376   
  377   	// Process the associated group memberships
  378   	e = element.getElements(Constants.Element.GROUP_MEMBER).elements();
  379   	while (e.hasMoreElements()) {
  380   	    XMLTree gm = (XMLTree) e.nextElement();
  381   	    String groupname =
  382   		(String) gm.getAttribute(Constants.Attribute.NAME);
  383   	    FileRealmGroup group = getGroup(groupname);
  384   	    if (group != null)
  385   		group.addRole(role);
  386   	}
  387   
  388   	// Process the associated user memberships
  389   	e = element.getElements(Constants.Element.USER_MEMBER).elements();
  390   	while (e.hasMoreElements()) {
  391   	    XMLTree um = (XMLTree) e.nextElement();
  392   	    String username =
  393   		(String) um.getAttribute(Constants.Attribute.NAME);
  394   	    FileRealmUser user = getUser(username);
  395   	    if (user != null)
  396   		user.addRole(role);
  397   	}
  398   
  399   	// XXX: Does not support the "anyone" sub-element
  400   
  401       }
  402   
  403   
  404       /**
  405        * Convert the specified XML element into a new user.
  406        *
  407        * @param element XML element for this user
  408        */
  409       private void readUser(XMLTree element) {
  410   
  411   	// Construct the user itself
  412   	String name =
  413   	    (String) element.getAttribute(Constants.Attribute.NAME);
  414   	byte[] password =
  415             HexUtils.convert
  416   	    ((String) element.getAttribute(Constants.Attribute.PASSWORD));
  417   	createUser(name, password);
  418   
  419       }
  420   
  421   
  422       /**
  423        * [Package Private] Remove this group from the set of defined groups.
  424        *
  425        * @param group Group to be removed
  426        */
  427       void remove(FileRealmGroup group) {
  428   
  429   	groups.remove(group.getName());
  430   
  431       }
  432   
  433   
  434       /**
  435        * [Package Private] Remove this role from the set of defined roles.
  436        *
  437        * @param role Role to be removed
  438        */
  439       void remove(String role) {
  440   
  441   	roles.remove(role);
  442   
  443       }
  444   
  445   
  446       /**
  447        * [Package Private] Remove this user from the set of defined users.
  448        *
  449        * @param user User to be removed
  450        */
  451       void remove(FileRealmUser user) {
  452   
  453   	users.remove(user.getName());
  454   
  455       }
  456   
  457   
  458       /**
  459        * Reset the contents of this database so that it can be reused
  460        */
  461       public void reset() {
  462   
  463   	groups.clear();
  464   	roles.clear();
  465   	users.clear();
  466   
  467       }
  468   
  469   
  470       /**
  471        * Write the contents of this database to the specified output stream,
  472        * in a format suitable for loading via the read() method.
  473        *
  474        * @exception IOException if an input/output error occurs
  475        */
  476       public void write(OutputStream stream) throws IOException {
  477   
  478   	// XXX - Yes, this should really create a DOM tree and ask it to
  479   	// output itself.  At this time, however, that approach would introduce
  480   	// another dependency on which XML parser is being used.  Once
  481   	// a standardized XML interface is selected, this will be modified.
  482   	// XXX - Does not support "<anyone/>" membership in groups or roles.
  483   	PrintWriter writer = new PrintWriter(stream);
  484   	writer.println("<tomcat-users>");
  485   
  486   	// Render user elements for all defined users
  487   	Enumeration users = getUsers();
  488   	while (users.hasMoreElements()) {
  489   	    FileRealmUser user = (FileRealmUser) users.nextElement();
  490   	    writer.println("  <user name=\"" + user.getName() +
  491   			   "\" password=\"" +
  492   			   HexUtils.convert(user.getPassword()) + "\" />");
  493   	}
  494   
  495   	// Render group elements for all defined groups
  496   	Enumeration groups = getGroups();
  497   	while (groups.hasMoreElements()) {
  498   	    FileRealmGroup group = (FileRealmGroup) groups.nextElement();
  499   	    writer.println("  <group name=\"" + group.getName() + "\">");
  500   	    users = group.getUsers();
  501   	    while (users.hasMoreElements()) {
  502   		FileRealmUser user = (FileRealmUser) users.nextElement();
  503   		writer.println("    <user-member name=\"" +
  504   			       user.getName() + "\" />");
  505   	    }
  506   	    writer.println("  </group>");
  507   	}
  508   
  509   	// Render role elements for all defined roles
  510   	Enumeration roles = getRoles();
  511   	while (roles.hasMoreElements()) {
  512   	    String role = (String) roles.nextElement();
  513   	    writer.println("  <role name=\"" + role + "\">");
  514   	    users = getUsers();
  515   	    while (users.hasMoreElements()) {
  516   		FileRealmUser user = (FileRealmUser) users.nextElement();
  517   		if (!user.hasRole(role))
  518   		    continue;
  519   		writer.println("    <user-member name=\"" +
  520   			       user.getName() + "\" />");
  521   	    }
  522   	    groups = getGroups();
  523   	    while (groups.hasMoreElements()) {
  524   		FileRealmGroup group = (FileRealmGroup) groups.nextElement();
  525   		if (!group.hasRole(role))
  526   		    continue;
  527   		writer.println("    <group-member name=\"" +
  528   			       group.getName() + "\" />");
  529   	    }
  530   	    writer.println("  </role>");
  531   	}
  532   
  533   	// Finish the output of this XML file
  534   	writer.println("</tomcat-users>");
  535   	writer.flush();
  536   
  537       }
  538   
  539   
  540   }

Home » apache-tomcat-6.0.26-src » org.apache » tomcat » security » file » [javadoc | source]