Author: sbrewin
Date: Wed Aug  5 13:53:41 2015
New Revision: 1694216

URL: http://svn.apache.org/r1694216
Log:
Maintenance release of 2.3.2. Fixes JAMES-1600, JAMES-1602 and JAMES-1603

Added:
    james/server/tags/2_3_2_1/
      - copied from r1690897, james/server/tags/2_3_2/
Modified:
    james/server/tags/2_3_2_1/build.xml
    james/server/tags/2_3_2_1/default.properties
    james/server/tags/2_3_2_1/pom.xml
    james/server/tags/2_3_2_1/src/conf/james-config.xml
    
james/server/tags/2_3_2_1/src/java/org/apache/james/userrepository/UsersFileRepository.java

Modified: james/server/tags/2_3_2_1/build.xml
URL: 
http://svn.apache.org/viewvc/james/server/tags/2_3_2_1/build.xml?rev=1694216&r1=1690897&r2=1694216&view=diff
==============================================================================
--- james/server/tags/2_3_2_1/build.xml (original)
+++ james/server/tags/2_3_2_1/build.xml Wed Aug  5 13:53:41 2015
@@ -343,7 +343,8 @@ Legal:
           <param name="-version"/>
           <param name="-use"/>
           <param name="-breakiterator"/>
-          <param name="-link" value="http://java.sun.com/j2se/1.4/docs/api"/>
+          <!-- <param name="-link" 
value="http://java.sun.com/j2se/1.4/docs/api"/> -->
+          <param name="-link" 
value="http://docs.oracle.com/javase/1.5.0/docs/api/"/>  
           <param name="-link" 
value="http://java.sun.com/j2ee/sdk_1.3/techdocs/api"/>
           <param name="-link" value="http://avalon.apache.org/api"/>
           <param name="-link" value="http://avalon.apache.org/phoenix/api"/>
@@ -362,7 +363,8 @@ Legal:
           <param name="-version"/>
           <param name="-breakiterator"/>
           <param name="-use"/>
-          <param name="-link" value="http://java.sun.com/j2se/1.4/docs/api"/>
+          <!-- <param name="-link" 
value="http://java.sun.com/j2se/1.4/docs/api"/> -->
+          <param name="-link" 
value="http://docs.oracle.com/javase/1.5.0/docs/api/"/>
           <param name="-link" 
value="http://java.sun.com/j2ee/sdk_1.3/techdocs/api"/>
           <param name="-link" value="http://avalon.apache.org/api"/>
           <param name="-link" value="http://avalon.apache.org/phoenix/api"/>

Modified: james/server/tags/2_3_2_1/default.properties
URL: 
http://svn.apache.org/viewvc/james/server/tags/2_3_2_1/default.properties?rev=1694216&r1=1690897&r2=1694216&view=diff
==============================================================================
--- james/server/tags/2_3_2_1/default.properties (original)
+++ james/server/tags/2_3_2_1/default.properties Wed Aug  5 13:53:41 2015
@@ -27,11 +27,11 @@
 
 name=james
 Name=James Mail Server
-version=2.3.2
+version=2.3.2.1
 mailet-version=2.3
 mailet-api-version=2.3
 #package-version=3.0a1
-year=1999-2009
+year=1999-2015
 extension.name=org.apache.james
 vendor=Apache Software Foundation
 

Modified: james/server/tags/2_3_2_1/pom.xml
URL: 
http://svn.apache.org/viewvc/james/server/tags/2_3_2_1/pom.xml?rev=1694216&r1=1690897&r2=1694216&view=diff
==============================================================================
--- james/server/tags/2_3_2_1/pom.xml (original)
+++ james/server/tags/2_3_2_1/pom.xml Wed Aug  5 13:53:41 2015
@@ -31,7 +31,7 @@
   <groupId>org.apache.james</groupId>
   <artifactId>james-server</artifactId>
   <name>Apache JAMES Server</name>
-  <version>2.3.2</version>
+  <version>2.3.2.1</version>
   <packaging>jar</packaging>
   <description>
     The Apache Java Enterprise Mail Server (a.k.a. JAMES Server)
@@ -191,6 +191,12 @@
       <version>1.4.1</version>
       <scope>test</scope>
     </dependency>
+    
+       <dependency>
+               <groupId>commons-codec</groupId>
+               <artifactId>commons-codec</artifactId>
+               <version>1.10</version>
+       </dependency>
 
     <dependency>
       <groupId>cornerstone-connection</groupId>

Modified: james/server/tags/2_3_2_1/src/conf/james-config.xml
URL: 
http://svn.apache.org/viewvc/james/server/tags/2_3_2_1/src/conf/james-config.xml?rev=1694216&r1=1690897&r2=1694216&view=diff
==============================================================================
--- james/server/tags/2_3_2_1/src/conf/james-config.xml (original)
+++ james/server/tags/2_3_2_1/src/conf/james-config.xml Wed Aug  5 13:53:41 2015
@@ -812,7 +812,7 @@ Regards, Postmaster XXX.YYY
          <administrator_accounts>
 <!-- CHECKME! -->
             <!-- Change the default login/password. -->
-            <account login="root" password="root"/>
+            <account login="root" password="!changeme!"/>
          </administrator_accounts>
          <connectiontimeout> 60000 </connectiontimeout>
          <!-- The prompt directive adds a prompt to every output from 
RemoteManager -->

Modified: 
james/server/tags/2_3_2_1/src/java/org/apache/james/userrepository/UsersFileRepository.java
URL: 
http://svn.apache.org/viewvc/james/server/tags/2_3_2_1/src/java/org/apache/james/userrepository/UsersFileRepository.java?rev=1694216&r1=1690897&r2=1694216&view=diff
==============================================================================
--- 
james/server/tags/2_3_2_1/src/java/org/apache/james/userrepository/UsersFileRepository.java
 (original)
+++ 
james/server/tags/2_3_2_1/src/java/org/apache/james/userrepository/UsersFileRepository.java
 Wed Aug  5 13:53:41 2015
@@ -34,230 +34,366 @@ import org.apache.james.services.User;
 import org.apache.james.services.UsersRepository;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.Iterator;
 
 /**
  * Implementation of a Repository to store users on the File System.
  *
  * Requires a configuration element in the .conf.xml file of the form:
- *  &lt;repository destinationURL="file://path-to-root-dir-for-repository"
- *              type="USERS"
- *              model="SYNCHRONOUS"/&gt;
- * Requires a logger called UsersRepository.
+ * &lt;repository destinationURL="file://path-to-root-dir-for-repository"
+ * type="USERS" model="SYNCHRONOUS"/&gt; Requires a logger called
+ * UsersRepository.
  *
  *
  * @version CVS $Revision$
  *
  */
-public class UsersFileRepository
-    extends AbstractLogEnabled
-    implements UsersRepository, Configurable, Serviceable, Initializable {
- 
-    /**
-     * Whether 'deep debugging' is turned on.
-     */
-    protected static boolean DEEP_DEBUG = false;
-
-    private Store store;
-    private ObjectRepository or;
-
-    /**
-     * The destination URL used to define the repository.
-     */
-    private String destination;
-
-    /**
-     * @see 
org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
-     */
-    public void service( final ServiceManager componentManager )
-        throws ServiceException {
-
-        try {
-            store = (Store)componentManager.lookup( Store.ROLE );
-        } catch (Exception e) {
-            final String message = "Failed to retrieve Store component:" + 
e.getMessage();
-            getLogger().error( message, e );
-            throw new ServiceException ("", message, e );
-        }
-    }
-
-    /**
-     * @see 
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
-     */
-    public void configure( final Configuration configuration )
-        throws ConfigurationException {
-
-        destination = configuration.getChild( "destination" ).getAttribute( 
"URL" );
-
-        if (!destination.endsWith(File.separator)) {
-            destination += File.separator;
-        }
-    }
-
-    /**
-     * @see org.apache.avalon.framework.activity.Initializable#initialize()
-     */
-    public void initialize()
-        throws Exception {
-
-        try {
-            //prepare Configurations for object and stream repositories
-            final DefaultConfiguration objectConfiguration
-                = new DefaultConfiguration( "repository",
-                                            
"generated:UsersFileRepository.compose()" );
-
-            objectConfiguration.setAttribute( "destinationURL", destination );
-            objectConfiguration.setAttribute( "type", "OBJECT" );
-            objectConfiguration.setAttribute( "model", "SYNCHRONOUS" );
-
-            or = (ObjectRepository)store.select( objectConfiguration );
-            if (getLogger().isDebugEnabled()) {
-                StringBuffer logBuffer =
-                    new StringBuffer(192)
-                            .append(this.getClass().getName())
-                            .append(" created in ")
-                            .append(destination);
-                getLogger().debug(logBuffer.toString());
-            }
-        } catch (Exception e) {
-            if (getLogger().isErrorEnabled()) {
-                getLogger().error("Failed to initialize repository:" + 
e.getMessage(), e );
-            }
-            throw e;
-        }
-    }
-
-    /**
-     * List users in repository.
-     *
-     * @return Iterator over a collection of Strings, each being one user in 
the repository.
-     */
-    public Iterator list() {
-        return or.list();
-    }
-
-    /**
-     * Update the repository with the specified user object. A user object
-     * with this username must already exist.
-     *
-     * @param user the user to be added.
-     *
-     * @return true if successful.
-     */
-    public synchronized boolean addUser(User user) {
-        String username = user.getUserName();
-        if (contains(username)) {
-            return false;
-        }
-        try {
-            or.put(username, user);
-        } catch (Exception e) {
-            throw new RuntimeException("Exception caught while storing user: " 
+ e );
-        }
-        return true;
-    }
-
-    public void addUser(String name, Object attributes) {
-        if (attributes instanceof String) {
-            User newbie = new DefaultUser(name, "SHA");
-            newbie.setPassword( (String) attributes);
-            addUser(newbie);
-        }
-        else {
-            throw new RuntimeException("Improper use of deprecated method"
-                                       + " - use addUser(User user)");
-        }
-    }
-
-    public boolean addUser(String username, String password) {
-        User newbie = new DefaultJamesUser(username, "SHA");
-        newbie.setPassword(password);
-        return addUser(newbie);
-    }
-
-    public synchronized User getUserByName(String name) {
-        if (contains(name)) {
-            try {
-                return (User)or.get(name);
-            } catch (Exception e) {
-                throw new RuntimeException("Exception while retrieving user: "
-                                           + e.getMessage());
-            }
-        } else {
-            return null;
-        }
-    }
-
-    public User getUserByNameCaseInsensitive(String name) {
-        String realName = getRealName(name);
-        if (realName == null ) {
-            return null;
-        }
-        return getUserByName(realName);
-    }
-
-    public String getRealName(String name) {
-        Iterator it = list();
-        while (it.hasNext()) {
-            String temp = (String) it.next();
-            if (name.equalsIgnoreCase(temp)) {
-                return temp;
-            }
-        }
-        return null;
-    }
-
-    public boolean updateUser(User user) {
-        String username = user.getUserName();
-        if (!contains(username)) {
-            return false;
-        }
-        try {
-            or.put(username, user);
-        } catch (Exception e) {
-            throw new RuntimeException("Exception caught while storing user: " 
+ e );
-        }
-        return true;
-    }
-
-    public synchronized void removeUser(String name) {
-        or.remove(name);
-    }
-
-    public boolean contains(String name) {
-        return or.containsKey(name);
-    }
-
-    public boolean containsCaseInsensitive(String name) {
-        Iterator it = list();
-        while (it.hasNext()) {
-            if (name.equalsIgnoreCase((String)it.next())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean test(String name, String password) {
-        User user;
-        try {
-            if (contains(name)) {
-                user = (User) or.get(name);
-            } else {
-               return false;
-            }
-        } catch (Exception e) {
-            throw new RuntimeException("Exception retrieving User" + e);
-        }
-        return user.verifyPassword(password);
-    }
-
-    public int countUsers() {
-        int count = 0;
-        for (Iterator it = list(); it.hasNext(); it.next()) {
-            count++;
-        }
-        return count;
-    }
+public class UsersFileRepository extends AbstractLogEnabled implements
+               UsersRepository, Configurable, Serviceable, Initializable {
+
+       public class UsersFileRepositoryException extends Exception {
+
+               /**
+         * 
+         */
+               private static final long serialVersionUID = 
-3156859346280071870L;
+
+               public UsersFileRepositoryException() {
+                       super();
+               }
+
+               /**
+                * @param message
+                * @param cause
+                */
+               public UsersFileRepositoryException(String message, Throwable 
cause) {
+                       super(message, cause);
+               }
+
+               /**
+                * @param message
+                */
+               public UsersFileRepositoryException(String message) {
+                       super(message);
+               }
+
+               /**
+                * @param cause
+                */
+               public UsersFileRepositoryException(Throwable cause) {
+                       super(cause);
+               }
+
+       }
+
+       /**
+        * Whether 'deep debugging' is turned on.
+        */
+       protected static boolean DEEP_DEBUG = false;
+
+       private Store store;
+       private ObjectRepository or;
+
+       /**
+        * The destination URL used to define the repository.
+        */
+       private String destination;
+       private File destinationCanonicalFile;
+
+       /**
+        * @see 
org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
+        */
+       public void service(final ServiceManager componentManager)
+                       throws ServiceException {
+
+               try {
+                       store = (Store) componentManager.lookup(Store.ROLE);
+               } catch (Exception e) {
+                       final String message = "Failed to retrieve Store 
component:"
+                                       + e.getMessage();
+                       getLogger().error(message, e);
+                       throw new ServiceException("", message, e);
+               }
+       }
+
+       /**
+        * @see 
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+        */
+       public void configure(final Configuration configuration)
+                       throws ConfigurationException {
+
+               destination = 
configuration.getChild("destination").getAttribute("URL");
+
+               if (!destination.endsWith(File.separator)) {
+                       destination += File.separator;
+               }
+               try {
+                       destinationCanonicalFile = new 
File(destination).getCanonicalFile();
+               } catch (IOException e) {
+                       throw new ConfigurationException("destination>>URL", e);
+               }
+               getLogger().debug("Canonical destination: " + 
destinationCanonicalFile);
+       }
+
+       /**
+        * @see org.apache.avalon.framework.activity.Initializable#initialize()
+        */
+       public void initialize() throws Exception {
+
+               try {
+                       // prepare Configurations for object and stream 
repositories
+                       final DefaultConfiguration objectConfiguration = new 
DefaultConfiguration(
+                                       "repository", 
"generated:UsersFileRepository.compose()");
+
+                       objectConfiguration.setAttribute("destinationURL", 
destination);
+                       objectConfiguration.setAttribute("type", "OBJECT");
+                       objectConfiguration.setAttribute("model", 
"SYNCHRONOUS");
+
+                       or = (ObjectRepository) 
store.select(objectConfiguration);
+                       if (getLogger().isDebugEnabled()) {
+                               StringBuffer logBuffer = new StringBuffer(192)
+                                               
.append(this.getClass().getName())
+                                               .append(" created in 
").append(destination);
+                               getLogger().debug(logBuffer.toString());
+                       }
+               } catch (Exception e) {
+                       if (getLogger().isErrorEnabled()) {
+                               getLogger().error(
+                                               "Failed to initialize 
repository:" + e.getMessage(), e);
+                       }
+                       throw e;
+               }
+       }
+
+       /**
+        * List users in repository.
+        *
+        * @return Iterator over a collection of Strings, each being one user 
in the
+        *         repository.
+        */
+       public Iterator list() {
+               return or.list();
+       }
+
+       /**
+        * Update the repository with the specified user object. A user object 
with
+        * this username must already exist.
+        *
+        * @param user
+        *            the user to be added.
+        *
+        * @return true if successful.
+        */
+       public synchronized boolean addUser(User user) {
+               String username = user.getUserName();
+               if (contains(username)) {
+                       return false;
+               }
+               try {
+                       validateUser(user);
+                       or.put(username, user);
+               } catch (Exception e) {
+                       throw new RuntimeException("Exception caught while 
storing user: "
+                                       + e);
+               }
+               return true;
+       }
+
+       public void addUser(String name, Object attributes) {
+               if (attributes instanceof String) {
+                       User newbie = new DefaultUser(name, "SHA");
+                       newbie.setPassword((String) attributes);
+                       addUser(newbie);
+               } else {
+                       throw new RuntimeException("Improper use of deprecated 
method"
+                                       + " - use addUser(User user)");
+               }
+       }
+
+       public boolean addUser(String username, String password) {
+               User newbie = new DefaultJamesUser(username, "SHA");
+               newbie.setPassword(password);
+               return addUser(newbie);
+       }
+
+       public synchronized User getUserByName(String name) {
+               if (contains(name)) {
+                       try {
+                               return (User) or.get(name);
+                       } catch (Exception e) {
+                               throw new RuntimeException("Exception while 
retrieving user: "
+                                               + e.getMessage());
+                       }
+               } else {
+                       return null;
+               }
+       }
+
+       public User getUserByNameCaseInsensitive(String name) {
+               String realName = getRealName(name);
+               if (realName == null) {
+                       return null;
+               }
+               return getUserByName(realName);
+       }
+
+       public String getRealName(String name) {
+               Iterator it = list();
+               while (it.hasNext()) {
+                       String temp = (String) it.next();
+                       if (name.equalsIgnoreCase(temp)) {
+                               return temp;
+                       }
+               }
+               return null;
+       }
+
+       public boolean updateUser(User user) {
+               String username = user.getUserName();
+               if (!contains(username)) {
+                       return false;
+               }
+               try {
+                       or.put(username, user);
+               } catch (Exception e) {
+                       throw new RuntimeException("Exception caught while 
storing user: "
+                                       + e);
+               }
+               return true;
+       }
+
+       public synchronized void removeUser(String name) {
+               or.remove(name);
+       }
+
+       public boolean contains(String name) {
+               return or.containsKey(name);
+       }
+
+       public boolean containsCaseInsensitive(String name) {
+               Iterator it = list();
+               while (it.hasNext()) {
+                       if (name.equalsIgnoreCase((String) it.next())) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       public boolean test(String name, String password) {
+               User user;
+               try {
+                       if (contains(name)) {
+                               user = (User) or.get(name);
+                       } else {
+                               return false;
+                       }
+               } catch (Exception e) {
+                       throw new RuntimeException("Exception retrieving User" 
+ e);
+               }
+               return user.verifyPassword(password);
+       }
+
+       public int countUsers() {
+               int count = 0;
+               for (Iterator it = list(); it.hasNext(); it.next()) {
+                       count++;
+               }
+               return count;
+       }
+
+       /**
+        * Validate the passed <code>User</code>.
+        * 
+        * <p>
+        * Enforces partial RFC 3696 compliance and a file system 'jail' such 
that
+        * only user names that will result in a file that is a child of the
+        * configured directory for the repository pass validation.
+        * 
+        * @see org.apache.james.userrepository.UsersFileRepositoryTest
+        * 
+        * @param user
+        * @throws UsersFileRepositoryException
+        */
+       protected void validateUser(final User user)
+                       throws UsersFileRepositoryException {
+
+               // "." is never allowed as a starting character. It is neither 
RFC 3696
+               // compliant or safe
+               if (user.getUserName().startsWith(".")) {
+                       UsersFileRepositoryException ex = new 
UsersFileRepositoryException(
+                                       "User name \"" + user.getUserName()
+                                                       + "\" starts with 
\".\"");
+                       getLogger().error("User name validation failure", ex);
+                       throw ex;
+               }
+
+               // "." is never allowed as an ending character. It is neither 
RFC 3696
+               // compliant or safe
+               if (user.getUserName().endsWith(".")) {
+                       UsersFileRepositoryException ex = new 
UsersFileRepositoryException(
+                                       "User name \"" + user.getUserName() + 
"\" ends with \".\"");
+                       getLogger().error("User name validation failure", ex);
+                       throw ex;
+               }
+
+               // A sequence of two or more "." is never allowed. It is 
neither RFC
+               // 3696 compliant or safe
+               if (user.getUserName().contains("..")) {
+                       UsersFileRepositoryException ex = new 
UsersFileRepositoryException(
+                                       "User name \"" + user.getUserName() + 
"\" contains \"..\"");
+                       getLogger().error("User name validation failure", ex);
+                       throw ex;
+               }
+
+               // Absolute path conversion discards the trailing file separator
+               // so "X" and "X/" resolve to the same path potentially 
resulting in
+               // conflicts
+               if (user.getUserName().endsWith(File.separator)) {
+                       UsersFileRepositoryException ex = new 
UsersFileRepositoryException(
+                                       "User name \"" + user.getUserName()
+                                                       + "\" ends with a file 
name separator");
+                       getLogger().error("User name validation failure", ex);
+                       throw ex;
+               }
+
+               // Canonical paths derived from the user name must be children
+               // of the configured destination
+               try {
+                       File targetCanonicalFile = new 
File(destinationCanonicalFile,
+                                       user.getUserName()).getCanonicalFile();
+                       boolean isChild = false;
+                       File targetParentCanonicalFile = targetCanonicalFile
+                                       .getParentFile().getCanonicalFile();
+                       while (!isChild && null != targetParentCanonicalFile) {
+                               isChild = destinationCanonicalFile
+                                               
.equals(targetParentCanonicalFile);
+                               targetParentCanonicalFile = 
targetParentCanonicalFile
+                                               
.getParentFile().getCanonicalFile();
+                       }
+                       if (!isChild) {
+                               UsersFileRepositoryException ex = new 
UsersFileRepositoryException(
+                                               "The canonical path \""
+                                                               + 
targetCanonicalFile
+                                                               + "\" for user 
name \""
+                                                               + 
user.getUserName()
+                                                               + "\" is 
invalid. The resultant path is not a child of \""
+                                                               + 
destinationCanonicalFile + "\"");
+                               getLogger().error("User name validation 
failure", ex);
+                               throw ex;
+                       } else if (getLogger().isDebugEnabled()) {
+                               getLogger()
+                                               .debug("The canonical path \""
+                                                               + 
targetCanonicalFile
+                                                               + "\" for user 
name \""
+                                                               + 
user.getUserName()
+                                                               + "\" is valid. 
The resultant path is a child of \""
+                                                               + 
destinationCanonicalFile + "\"");
+                       }
+               } catch (IOException e) {
+                       throw new UsersFileRepositoryException(e);
+               }
+       }
 
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to