Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » users » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   
   19   package org.apache.catalina.users;
   20   
   21   
   22   import java.io.File;
   23   import java.io.FileInputStream;
   24   import java.io.FileOutputStream;
   25   import java.io.IOException;
   26   import java.io.OutputStreamWriter;
   27   import java.io.PrintWriter;
   28   import java.util.HashMap;
   29   import java.util.Iterator;
   30   import org.apache.catalina.Group;
   31   import org.apache.catalina.Role;
   32   import org.apache.catalina.User;
   33   import org.apache.catalina.UserDatabase;
   34   import org.apache.catalina.util.StringManager;
   35   import org.apache.juli.logging.Log;
   36   import org.apache.juli.logging.LogFactory;
   37   import org.apache.tomcat.util.digester.Digester;
   38   import org.apache.tomcat.util.digester.ObjectCreationFactory;
   39   import org.xml.sax.Attributes;
   40   
   41   
   42   /**
   43    * <p>Concrete implementation of {@link UserDatabase} that loads all
   44    * defined users, groups, and roles into an in-memory data structure,
   45    * and uses a specified XML file for its persistent storage.</p>
   46    *
   47    * @author Craig R. McClanahan
   48    * @version $Revision: 777556 $ $Date: 2009-05-22 16:59:34 +0200 (Fri, 22 May 2009) $
   49    * @since 4.1
   50    */
   51   
   52   public class MemoryUserDatabase implements UserDatabase {
   53   
   54   
   55       private static Log log = LogFactory.getLog(MemoryUserDatabase.class);
   56   
   57       // ----------------------------------------------------------- Constructors
   58   
   59   
   60       /**
   61        * Create a new instance with default values.
   62        */
   63       public MemoryUserDatabase() {
   64   
   65           super();
   66   
   67       }
   68   
   69   
   70       /**
   71        * Create a new instance with the specified values.
   72        *
   73        * @param id Unique global identifier of this user database
   74        */
   75       public MemoryUserDatabase(String id) {
   76   
   77           super();
   78           this.id = id;
   79   
   80       }
   81   
   82   
   83       // ----------------------------------------------------- Instance Variables
   84   
   85   
   86       /**
   87        * The set of {@link Group}s defined in this database, keyed by
   88        * group name.
   89        */
   90       protected HashMap groups = new HashMap();
   91   
   92   
   93       /**
   94        * The unique global identifier of this user database.
   95        */
   96       protected String id = null;
   97   
   98   
   99       /**
  100        * The relative (to <code>catalina.base</code>) or absolute pathname to
  101        * the XML file in which we will save our persistent information.
  102        */
  103       protected String pathname = "conf/tomcat-users.xml";
  104   
  105   
  106       /**
  107        * The relative or absolute pathname to the file in which our old
  108        * information is stored while renaming is in progress.
  109        */
  110       protected String pathnameOld = pathname + ".old";
  111   
  112   
  113       /**
  114        * The relative or absolute pathname ot the file in which we write
  115        * our new information prior to renaming.
  116        */
  117       protected String pathnameNew = pathname + ".new";
  118   
  119   
  120       /**
  121        * A flag, indicating if the user database is read only.
  122        */
  123       protected boolean readonly = true;
  124   
  125       /**
  126        * The set of {@link Role}s defined in this database, keyed by
  127        * role name.
  128        */
  129       protected HashMap roles = new HashMap();
  130   
  131   
  132       /**
  133        * The string manager for this package.
  134        */
  135       private static StringManager sm =
  136           StringManager.getManager(Constants.Package);
  137   
  138   
  139       /**
  140        * The set of {@link User}s defined in this database, keyed by
  141        * user name.
  142        */
  143       protected HashMap users = new HashMap();
  144   
  145   
  146       // ------------------------------------------------------------- Properties
  147   
  148   
  149       /**
  150        * Return the set of {@link Group}s defined in this user database.
  151        */
  152       public Iterator getGroups() {
  153   
  154           synchronized (groups) {
  155               return (groups.values().iterator());
  156           }
  157   
  158       }
  159   
  160   
  161       /**
  162        * Return the unique global identifier of this user database.
  163        */
  164       public String getId() {
  165   
  166           return (this.id);
  167   
  168       }
  169   
  170   
  171       /**
  172        * Return the relative or absolute pathname to the persistent storage file.
  173        */
  174       public String getPathname() {
  175   
  176           return (this.pathname);
  177   
  178       }
  179   
  180   
  181       /**
  182        * Set the relative or absolute pathname to the persistent storage file.
  183        *
  184        * @param pathname The new pathname
  185        */
  186       public void setPathname(String pathname) {
  187   
  188           this.pathname = pathname;
  189           this.pathnameOld = pathname + ".old";
  190           this.pathnameNew = pathname + ".new";
  191   
  192       }
  193   
  194   
  195       /**
  196        * Returning the readonly status of the user database
  197        */
  198       public boolean getReadonly() {
  199   
  200           return (this.readonly);
  201   
  202       }
  203   
  204   
  205       /**
  206        * Setting the readonly status of the user database
  207        *
  208        * @param pathname The new pathname
  209        */
  210       public void setReadonly(boolean readonly) {
  211   
  212           this.readonly = readonly;
  213   
  214       }
  215   
  216   
  217       /**
  218        * Return the set of {@link Role}s defined in this user database.
  219        */
  220       public Iterator getRoles() {
  221   
  222           synchronized (roles) {
  223               return (roles.values().iterator());
  224           }
  225   
  226       }
  227   
  228   
  229       /**
  230        * Return the set of {@link User}s defined in this user database.
  231        */
  232       public Iterator getUsers() {
  233   
  234           synchronized (users) {
  235               return (users.values().iterator());
  236           }
  237   
  238       }
  239   
  240   
  241   
  242       // --------------------------------------------------------- Public Methods
  243   
  244   
  245       /**
  246        * Finalize access to this user database.
  247        *
  248        * @exception Exception if any exception is thrown during closing
  249        */
  250       public void close() throws Exception {
  251   
  252           save();
  253   
  254           synchronized (groups) {
  255               synchronized (users) {
  256                   users.clear();
  257                   groups.clear();
  258               }
  259           }
  260   
  261       }
  262   
  263   
  264       /**
  265        * Create and return a new {@link Group} defined in this user database.
  266        *
  267        * @param groupname The group name of the new group (must be unique)
  268        * @param description The description of this group
  269        */
  270       public Group createGroup(String groupname, String description) {
  271   
  272           MemoryGroup group = new MemoryGroup(this, groupname, description);
  273           synchronized (groups) {
  274               groups.put(group.getGroupname(), group);
  275           }
  276           return (group);
  277   
  278       }
  279   
  280   
  281       /**
  282        * Create and return a new {@link Role} defined in this user database.
  283        *
  284        * @param rolename The role name of the new group (must be unique)
  285        * @param description The description of this group
  286        */
  287       public Role createRole(String rolename, String description) {
  288   
  289           MemoryRole role = new MemoryRole(this, rolename, description);
  290           synchronized (roles) {
  291               roles.put(role.getRolename(), role);
  292           }
  293           return (role);
  294   
  295       }
  296   
  297   
  298       /**
  299        * Create and return a new {@link User} defined in this user database.
  300        *
  301        * @param username The logon username of the new user (must be unique)
  302        * @param password The logon password of the new user
  303        * @param fullName The full name of the new user
  304        */
  305       public User createUser(String username, String password,
  306                              String fullName) {
  307   
  308           MemoryUser user = new MemoryUser(this, username, password, fullName);
  309           synchronized (users) {
  310               users.put(user.getUsername(), user);
  311           }
  312           return (user);
  313   
  314       }
  315   
  316   
  317       /**
  318        * Return the {@link Group} with the specified group name, if any;
  319        * otherwise return <code>null</code>.
  320        *
  321        * @param groupname Name of the group to return
  322        */
  323       public Group findGroup(String groupname) {
  324   
  325           synchronized (groups) {
  326               return ((Group) groups.get(groupname));
  327           }
  328   
  329       }
  330   
  331   
  332       /**
  333        * Return the {@link Role} with the specified role name, if any;
  334        * otherwise return <code>null</code>.
  335        *
  336        * @param rolename Name of the role to return
  337        */
  338       public Role findRole(String rolename) {
  339   
  340           synchronized (roles) {
  341               return ((Role) roles.get(rolename));
  342           }
  343   
  344       }
  345   
  346   
  347       /**
  348        * Return the {@link User} with the specified user name, if any;
  349        * otherwise return <code>null</code>.
  350        *
  351        * @param username Name of the user to return
  352        */
  353       public User findUser(String username) {
  354   
  355           synchronized (users) {
  356               return ((User) users.get(username));
  357           }
  358   
  359       }
  360   
  361   
  362       /**
  363        * Initialize access to this user database.
  364        *
  365        * @exception Exception if any exception is thrown during opening
  366        */
  367       public void open() throws Exception {
  368   
  369           synchronized (groups) {
  370               synchronized (users) {
  371   
  372                   // Erase any previous groups and users
  373                   users.clear();
  374                   groups.clear();
  375                   roles.clear();
  376   
  377                   // Construct a reader for the XML input file (if it exists)
  378                   File file = new File(pathname);
  379                   if (!file.isAbsolute()) {
  380                       file = new File(System.getProperty("catalina.base"),
  381                                       pathname);
  382                   }
  383                   if (!file.exists()) {
  384                       return;
  385                   }
  386                   FileInputStream fis = new FileInputStream(file);
  387   
  388                   // Construct a digester to read the XML input file
  389                   Digester digester = new Digester();
  390                   try {
  391                       digester.setFeature(
  392                               "http://apache.org/xml/features/allow-java-encodings",
  393                               true);
  394                   } catch (Exception e) {
  395                       log.warn(sm.getString("memoryUserDatabase.xmlFeatureEncoding"), e);
  396                   }
  397                   digester.addFactoryCreate
  398                       ("tomcat-users/group",
  399                        new MemoryGroupCreationFactory(this));
  400                   digester.addFactoryCreate
  401                       ("tomcat-users/role",
  402                        new MemoryRoleCreationFactory(this));
  403                   digester.addFactoryCreate
  404                       ("tomcat-users/user",
  405                        new MemoryUserCreationFactory(this));
  406   
  407                   // Parse the XML input file to load this database
  408                   try {
  409                       digester.parse(fis);
  410                       fis.close();
  411                   } catch (Exception e) {
  412                       try {
  413                           fis.close();
  414                       } catch (Throwable t) {
  415                           ;
  416                       }
  417                       throw e;
  418                   }
  419   
  420               }
  421           }
  422   
  423       }
  424   
  425   
  426       /**
  427        * Remove the specified {@link Group} from this user database.
  428        *
  429        * @param group The group to be removed
  430        */
  431       public void removeGroup(Group group) {
  432   
  433           synchronized (groups) {
  434               Iterator users = getUsers();
  435               while (users.hasNext()) {
  436                   User user = (User) users.next();
  437                   user.removeGroup(group);
  438               }
  439               groups.remove(group.getGroupname());
  440           }
  441   
  442       }
  443   
  444   
  445       /**
  446        * Remove the specified {@link Role} from this user database.
  447        *
  448        * @param role The role to be removed
  449        */
  450       public void removeRole(Role role) {
  451   
  452           synchronized (roles) {
  453               Iterator groups = getGroups();
  454               while (groups.hasNext()) {
  455                   Group group = (Group) groups.next();
  456                   group.removeRole(role);
  457               }
  458               Iterator users = getUsers();
  459               while (users.hasNext()) {
  460                   User user = (User) users.next();
  461                   user.removeRole(role);
  462               }
  463               roles.remove(role.getRolename());
  464           }
  465   
  466       }
  467   
  468   
  469       /**
  470        * Remove the specified {@link User} from this user database.
  471        *
  472        * @param user The user to be removed
  473        */
  474       public void removeUser(User user) {
  475   
  476           synchronized (users) {
  477               users.remove(user.getUsername());
  478           }
  479   
  480       }
  481   
  482   
  483       /**
  484        * Check for permissions to save this user database
  485        * to persistent storage location
  486        *
  487        */
  488       public boolean isWriteable() {
  489   
  490           File file = new File(pathname);
  491           if (!file.isAbsolute()) {
  492               file = new File(System.getProperty("catalina.base"),
  493                               pathname);
  494           }
  495           File dir = file.getParentFile();
  496           return dir.exists() && dir.isDirectory() && dir.canWrite();
  497   
  498       }
  499   
  500   
  501       /**
  502        * Save any updated information to the persistent storage location for
  503        * this user database.
  504        *
  505        * @exception Exception if any exception is thrown during saving
  506        */
  507       public void save() throws Exception {
  508   
  509           if (getReadonly()) {
  510               log.error(sm.getString("memoryUserDatabase.readOnly"));
  511               return;
  512           }
  513   
  514           if (!isWriteable()) {
  515               log.warn(sm.getString("memoryUserDatabase.notPersistable"));
  516               return;
  517           }
  518   
  519           // Write out contents to a temporary file
  520           File fileNew = new File(pathnameNew);
  521           if (!fileNew.isAbsolute()) {
  522               fileNew =
  523                   new File(System.getProperty("catalina.base"), pathnameNew);
  524           }
  525           PrintWriter writer = null;
  526           try {
  527   
  528               // Configure our PrintWriter
  529               FileOutputStream fos = new FileOutputStream(fileNew);
  530               OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
  531               writer = new PrintWriter(osw);
  532   
  533               // Print the file prolog
  534               writer.println("<?xml version='1.0' encoding='utf-8'?>");
  535               writer.println("<tomcat-users>");
  536   
  537               // Print entries for each defined role, group, and user
  538               Iterator values = null;
  539               values = getRoles();
  540               while (values.hasNext()) {
  541                   writer.print("  ");
  542                   writer.println(values.next());
  543               }
  544               values = getGroups();
  545               while (values.hasNext()) {
  546                   writer.print("  ");
  547                   writer.println(values.next());
  548               }
  549               values = getUsers();
  550               while (values.hasNext()) {
  551                   writer.print("  ");
  552                   writer.println(values.next());
  553               }
  554   
  555               // Print the file epilog
  556               writer.println("</tomcat-users>");
  557   
  558               // Check for errors that occurred while printing
  559               if (writer.checkError()) {
  560                   writer.close();
  561                   fileNew.delete();
  562                   throw new IOException
  563                       (sm.getString("memoryUserDatabase.writeException",
  564                                     fileNew.getAbsolutePath()));
  565               }
  566               writer.close();
  567           } catch (IOException e) {
  568               if (writer != null) {
  569                   writer.close();
  570               }
  571               fileNew.delete();
  572               throw e;
  573           }
  574   
  575           // Perform the required renames to permanently save this file
  576           File fileOld = new File(pathnameOld);
  577           if (!fileOld.isAbsolute()) {
  578               fileOld =
  579                   new File(System.getProperty("catalina.base"), pathnameOld);
  580           }
  581           fileOld.delete();
  582           File fileOrig = new File(pathname);
  583           if (!fileOrig.isAbsolute()) {
  584               fileOrig =
  585                   new File(System.getProperty("catalina.base"), pathname);
  586           }
  587           if (fileOrig.exists()) {
  588               fileOld.delete();
  589               if (!fileOrig.renameTo(fileOld)) {
  590                   throw new IOException
  591                       (sm.getString("memoryUserDatabase.renameOld",
  592                                     fileOld.getAbsolutePath()));
  593               }
  594           }
  595           if (!fileNew.renameTo(fileOrig)) {
  596               if (fileOld.exists()) {
  597                   fileOld.renameTo(fileOrig);
  598               }
  599               throw new IOException
  600                   (sm.getString("memoryUserDatabase.renameNew",
  601                                 fileOrig.getAbsolutePath()));
  602           }
  603           fileOld.delete();
  604   
  605       }
  606   
  607   
  608       /**
  609        * Return a String representation of this UserDatabase.
  610        */
  611       public String toString() {
  612   
  613           StringBuffer sb = new StringBuffer("MemoryUserDatabase[id=");
  614           sb.append(this.id);
  615           sb.append(",pathname=");
  616           sb.append(pathname);
  617           sb.append(",groupCount=");
  618           sb.append(this.groups.size());
  619           sb.append(",roleCount=");
  620           sb.append(this.roles.size());
  621           sb.append(",userCount=");
  622           sb.append(this.users.size());
  623           sb.append("]");
  624           return (sb.toString());
  625   
  626       }
  627   
  628   
  629       // -------------------------------------------------------- Package Methods
  630   
  631   
  632       /**
  633        * Return the <code>StringManager</code> for use in looking up messages.
  634        */
  635       StringManager getStringManager() {
  636   
  637           return (sm);
  638   
  639       }
  640   
  641   
  642   }
  643   
  644   
  645   
  646   /**
  647    * Digester object creation factory for group instances.
  648    */
  649   class MemoryGroupCreationFactory implements ObjectCreationFactory {
  650   
  651       public MemoryGroupCreationFactory(MemoryUserDatabase database) {
  652           this.database = database;
  653       }
  654   
  655       public Object createObject(Attributes attributes) {
  656           String groupname = attributes.getValue("groupname");
  657           if (groupname == null) {
  658               groupname = attributes.getValue("name");
  659           }
  660           String description = attributes.getValue("description");
  661           String roles = attributes.getValue("roles");
  662           Group group = database.createGroup(groupname, description);
  663           if (roles != null) {
  664               while (roles.length() > 0) {
  665                   String rolename = null;
  666                   int comma = roles.indexOf(',');
  667                   if (comma >= 0) {
  668                       rolename = roles.substring(0, comma).trim();
  669                       roles = roles.substring(comma + 1);
  670                   } else {
  671                       rolename = roles.trim();
  672                       roles = "";
  673                   }
  674                   if (rolename.length() > 0) {
  675                       Role role = database.findRole(rolename);
  676                       if (role == null) {
  677                           role = database.createRole(rolename, null);
  678                       }
  679                       group.addRole(role);
  680                   }
  681               }
  682           }
  683           return (group);
  684       }
  685   
  686       private MemoryUserDatabase database = null;
  687   
  688       private Digester digester = null;
  689   
  690       public Digester getDigester() {
  691           return (this.digester);
  692       }
  693   
  694       public void setDigester(Digester digester) {
  695           this.digester = digester;
  696       }
  697   
  698   }
  699   
  700   
  701   /**
  702    * Digester object creation factory for role instances.
  703    */
  704   class MemoryRoleCreationFactory implements ObjectCreationFactory {
  705   
  706       public MemoryRoleCreationFactory(MemoryUserDatabase database) {
  707           this.database = database;
  708       }
  709   
  710       public Object createObject(Attributes attributes) {
  711           String rolename = attributes.getValue("rolename");
  712           if (rolename == null) {
  713               rolename = attributes.getValue("name");
  714           }
  715           String description = attributes.getValue("description");
  716           Role role = database.createRole(rolename, description);
  717           return (role);
  718       }
  719   
  720       private MemoryUserDatabase database = null;
  721   
  722       private Digester digester = null;
  723   
  724       public Digester getDigester() {
  725           return (this.digester);
  726       }
  727   
  728       public void setDigester(Digester digester) {
  729           this.digester = digester;
  730       }
  731   
  732   }
  733   
  734   
  735   /**
  736    * Digester object creation factory for user instances.
  737    */
  738   class MemoryUserCreationFactory implements ObjectCreationFactory {
  739   
  740       public MemoryUserCreationFactory(MemoryUserDatabase database) {
  741           this.database = database;
  742       }
  743   
  744       public Object createObject(Attributes attributes) {
  745           String username = attributes.getValue("username");
  746           if (username == null) {
  747               username = attributes.getValue("name");
  748           }
  749           String password = attributes.getValue("password");
  750           String fullName = attributes.getValue("fullName");
  751           if (fullName == null) {
  752               fullName = attributes.getValue("fullname");
  753           }
  754           String groups = attributes.getValue("groups");
  755           String roles = attributes.getValue("roles");
  756           User user = database.createUser(username, password, fullName);
  757           if (groups != null) {
  758               while (groups.length() > 0) {
  759                   String groupname = null;
  760                   int comma = groups.indexOf(',');
  761                   if (comma >= 0) {
  762                       groupname = groups.substring(0, comma).trim();
  763                       groups = groups.substring(comma + 1);
  764                   } else {
  765                       groupname = groups.trim();
  766                       groups = "";
  767                   }
  768                   if (groupname.length() > 0) {
  769                       Group group = database.findGroup(groupname);
  770                       if (group == null) {
  771                           group = database.createGroup(groupname, null);
  772                       }
  773                       user.addGroup(group);
  774                   }
  775               }
  776           }
  777           if (roles != null) {
  778               while (roles.length() > 0) {
  779                   String rolename = null;
  780                   int comma = roles.indexOf(',');
  781                   if (comma >= 0) {
  782                       rolename = roles.substring(0, comma).trim();
  783                       roles = roles.substring(comma + 1);
  784                   } else {
  785                       rolename = roles.trim();
  786                       roles = "";
  787                   }
  788                   if (rolename.length() > 0) {
  789                       Role role = database.findRole(rolename);
  790                       if (role == null) {
  791                           role = database.createRole(rolename, null);
  792                       }
  793                       user.addRole(role);
  794                   }
  795               }
  796           }
  797           return (user);
  798       }
  799   
  800       private MemoryUserDatabase database = null;
  801   
  802       private Digester digester = null;
  803   
  804       public Digester getDigester() {
  805           return (this.digester);
  806       }
  807   
  808       public void setDigester(Digester digester) {
  809           this.digester = digester;
  810       }
  811   
  812   }

Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » users » [javadoc | source]