james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From charl...@apache.org
Subject cvs commit: jakarta-james/src/java/org/apache/james/userrepository AbstractUsersRepository.java DefaultJamesUser.java DefaultUser.java UsersJDBCRepository.java UsersFileRepository.java UsersLDAPRepository.java UsersTownRepository.java
Date Mon, 11 Jun 2001 09:29:40 GMT
charlesb    01/06/11 02:29:39

  Modified:    .        build.xml
               src/conf james-config.xml
               src/java/org/apache/james James.java
               src/java/org/apache/james/remotemanager
                        RemoteManagerHandler.java
               src/java/org/apache/james/services UsersRepository.java
               src/java/org/apache/james/userrepository
                        UsersFileRepository.java UsersLDAPRepository.java
                        UsersTownRepository.java
  Added:       src/java/org/apache/james/security DigestUtil.java
               src/java/org/apache/james/services JamesUser.java User.java
               src/java/org/apache/james/userrepository
                        AbstractUsersRepository.java DefaultJamesUser.java
                        DefaultUser.java UsersJDBCRepository.java
  Removed:     proposals/v1.3/conf james-config.xml
               proposals/v1.3/java/org/apache/james James.java
               proposals/v1.3/java/org/apache/james/remotemanager
                        RemoteManagerHandler.java
               proposals/v1.3/java/org/apache/james/security
                        DigestUtil.java
               proposals/v1.3/java/org/apache/james/services JamesUser.java
                        User.java UsersRepository.java UsersStore.java
               proposals/v1.3/java/org/apache/james/userrepository
                        AbstractUsersRepository.java DefaultJamesUser.java
                        DefaultUser.java UsersFileRepository.java
                        UsersJDBCRepository.java UsersLDAPRepository.java
                        UsersTownRepository.java
  Log:
  Move UsersRepository proposal from proposals/v1.3 to main tree. Includes UsersJDBCRepository contributed by Darrell DeBoer
  
  Revision  Changes    Path
  1.72      +1 -1      jakarta-james/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-james/build.xml,v
  retrieving revision 1.71
  retrieving revision 1.72
  diff -u -r1.71 -r1.72
  --- build.xml	2001/06/10 13:19:56	1.71
  +++ build.xml	2001/06/11 09:29:01	1.72
  @@ -27,7 +27,7 @@
   
     <property name="name" value="james"/>
     <property name="Name" value="James"/>
  -  <property name="version" value="1.2.2-dev"/>
  +  <property name="version" value="1.3-dev"/>
     <property name="year" value="1999-2001"/>
   
     <!-- There should be no need to override default compiler but need to change
  
  
  
  1.2       +60 -0     jakarta-james/src/conf/james-config.xml
  
  Index: james-config.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/conf/james-config.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- james-config.xml	2001/05/15 17:02:57	1.1
  +++ james-config.xml	2001/06/11 09:29:23	1.2
  @@ -35,6 +35,12 @@
           <servername>localhost</servername>
         </servernames>
   
  +      <!-- Set whether user names are case sensitive or insensitive -->
  +      <!-- Set whether to enable local aliases -->
  +      <usernames ignoreCase="TRUE" enableAliases="TRUE"
  +                                   enableForwarding="TRUE"/>
  +
  +
         <!-- Set the type of permanent mailfolders to be used.
         If IMAP service is to be provided, storage must be 'IMAP'; if only POP3
         service is being provided then use must be 'basic' (default) . At some
  @@ -482,6 +488,7 @@
          
     <!-- The User Storage block -->
     <users-store>
  +      <!-- File-based user repository  -->
         <repository name="LocalUsers"
                     class="org.apache.james.userrepository.UsersFileRepository">
           <destination URL="file://var/users/"/>
  @@ -495,7 +502,60 @@
           <table>Users</table>
         </repository>
         -->
  +      <!-- The following are examples of database connections which have been tested.
  +           Theses should provided a guide to setting up other databases as well.
  +           The driver.class and destination.URL properties are require,
  +           but destination.user and destination.password are optional. -->
  +      <!-- Mssql server with Inet Sprinta
  +            <destination>
  +                <driver class="com.inet.tds.TdsDriver"/>
  +                <datasource>
  +                    <dburl>jdbc:inetdae7:127.0.0.1?database=mail</dburl>
  +                    <user>user</user>
  +                    <password>password</password>
  +                </datasource>
  +            </destination>
  +      </repository>
  +      -->
         
  +      <!-- MySQL server via ODBC
  +      <repository name="LocalUsers"
  +                  class="org.apache.james.userrepository.UsersJDBCRepository">
  +            <destination>
  +                <driver class="sun.jdbc.odbc.JdbcOdbcDriver"/>
  +                <datasource>
  +                    <dburl>jdbc:odbc:mail-mysql</dburl>
  +                </datasource>
  +            </destination>
  +      </repository>
  +      -->
  +      <!-- MySQL server via mm mysql driver
  +      <repository name="LocalUsers"
  +                  class="org.apache.james.userrepository.UsersJDBCRepository">
  +            <destination>
  +                <driver class="org.gjt.mm.mysql.Driver"/>
  +                <datasource>
  +                    <dburl>jdbc:mysql://127.0.0.1/mail</dburl>
  +                    <user>user</user>
  +                    <password>password</password>
  +                </datasource>
  +            </destination>
  +      </repository>
  +      -->
  +      <!-- Oracle8i server via thin driver
  +      <repository name="LocalUsers"
  +                  class="org.apache.james.userrepository.UsersJDBCRepository">
  +            <destination>
  +                <driver class="oracle.jdbc.driver.OracleDriver"/>
  +                <datasource>
  +                    <dburl>jdbc:oracle:thin:@127.0.0.1:1521:mail</dburl>
  +                    <user>user</user>
  +                    <password>password</password>
  +                </datasource>
  +            </destination>
  +      </repository>
  +      -->
  +
         <repository name="list-james"
                     class="org.apache.james.userrepository.UsersFileRepository">
           <destination URL="file://var/lists/list-james/"/>
  
  
  
  1.3       +65 -8     jakarta-james/src/java/org/apache/james/James.java
  
  Index: James.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/James.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- James.java	2001/06/06 13:17:54	1.2
  +++ James.java	2001/06/11 09:29:25	1.3
  @@ -34,6 +34,7 @@
   import org.apache.james.imapserver.*;
   import org.apache.james.services.*;
   import org.apache.james.transport.*;
  +import org.apache.james.userrepository.DefaultJamesUser;
   import org.apache.log.Logger;
   import org.apache.log.Priority;
   import org.apache.mailet.*;
  @@ -72,6 +73,9 @@
       private String inboxRootURL;
       private UsersRepository localusers;
       private Collection serverNames;
  +    private boolean ignoreCase;
  +    private boolean enableAliases;
  +    private boolean enableForwarding;
   
       // this used to be long, but increment operations on long are not
       // thread safe. Changed to int. 'int' should be ok, because id generation
  @@ -163,6 +167,23 @@
           this.postmaster = new MailAddress( postMasterAddress );
           context.put( Constants.POSTMASTER, postmaster );
   
  +        Configuration userNamesConf = conf.getChild("usernames");
  +        if (userNamesConf.getAttribute("ignoreCase").equals("TRUE")) {
  +            ignoreCase = true;
  +        } else {
  +	    ignoreCase = false;
  +	}
  +        if (userNamesConf.getAttribute("enableAliases").equals("TRUE")) {
  +            enableAliases = true;
  +        } else {
  +	    enableAliases = false;
  +	}
  +        if (userNamesConf.getAttribute("enableForwarding").equals("TRUE")) {
  +            enableForwarding = true;
  +        } else {
  +	    enableForwarding = false;
  +	}
  +
           //Get localusers
           try {
               localusers = (UsersRepository) usersStore.getRepository("LocalUsers");
  @@ -206,7 +227,6 @@
                   getLogger().info("Using SimpleSystem.");
                   imapHost = (Host) Class.forName(imapHostClass).newInstance();
                   //imapHost = new JamesHost();
  -		setupLogger(imapHost, "imaphost");
                   imapHost.configure(conf.getChild("imapHost"));
                   imapHost.contextualize(context);
                   imapHost.compose(compMgr);
  @@ -448,8 +468,12 @@
           sendMail(bouncer, recipients, reply);
       }
   
  -    public boolean isLocalUser(String userAccout) {
  -        return localusers.contains(userAccout);
  +    public boolean isLocalUser(String name) {
  +	if (ignoreCase) {
  +	    return localusers.containsCaseInsensitive(name);
  +	} else {
  +            return localusers.contains(name);
  +	}
       }
   
       public MailAddress getPostmaster() {
  @@ -458,10 +482,39 @@
   
       public void storeMail(MailAddress sender, MailAddress recipient, MimeMessage message) {
   
  +        String username;
  +        if (ignoreCase) {
  +            username = localusers.getRealName(recipient.getUser());
  +        } else {
  +            username = recipient.getUser();
  +        }
  +	JamesUser user;
  +	if (enableAliases || enableForwarding) {
  +	    user = (JamesUser) localusers.getUserByName(username);
  +	    if (enableAliases && user.getAliasing()) {
  +	        username = user.getAlias();
  +	    }
  +	    if (enableForwarding && user.getForwarding()) {
  +		MailAddress forwardTo = user.getForwardingDestination();
  +		Collection recipients = new HashSet();
  +		recipients.add(forwardTo);
  +		try {
  +		    sendMail(sender, recipients, message);
  +		    getLogger().info("Mail for " + username + " forwarded to "
  +                                 +  forwardTo.toString());
  +		    return;
  +		} catch (MessagingException me) {
  +		    getLogger().error("Error forwarding mail to "
  +				      + forwardTo.toString()
  +				      + "attempting local delivery");
  +		}
  +	    }
  +	}
  +
           if (useIMAPstorage) {
               ACLMailbox mbox = null;
               try {
  -                String folderName = "#users." + recipient.getUser() + ".INBOX";
  +                String folderName = "#users." + username + ".INBOX";
                   getLogger().debug("Want to store to: " + folderName);
                   mbox = imapHost.getMailbox(MailServer.MDA, folderName);
                   if(mbox.store(message,MailServer.MDA)) {
  @@ -484,7 +537,7 @@
               Collection recipients = new HashSet();
               recipients.add(recipient);
               MailImpl mailImpl = new MailImpl(getId(), sender, recipients, message);
  -            getUserInbox(recipient.getUser()).store(mailImpl);
  +            getUserInbox(username).store(mailImpl);
           }
       }
   
  @@ -531,14 +584,18 @@
        * @returns boolean true if user added succesfully, else false.
        */
       public boolean addUser(String userName, String password) {
  -        localusers.addUser(userName, password);
  -        if (useIMAPstorage) {
  +	boolean success;
  +	DefaultJamesUser user = new DefaultJamesUser(userName, "SHA");
  +	user.setPassword(password);
  +	user.initialize();
  +        success = localusers.addUser(user);
  +        if (useIMAPstorage && success) {
               JamesHost jh = (JamesHost) imapHost;
               if (jh.createPrivateMailAccount(userName)) {
                   getLogger().info("New MailAccount created for" + userName);
               }
           }
  -        return true;
  +        return success;
       }
   
   }
  
  
  
  1.2       +151 -9    jakarta-james/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java
  
  Index: RemoteManagerHandler.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RemoteManagerHandler.java	2001/05/11 09:39:33	1.1
  +++ RemoteManagerHandler.java	2001/06/11 09:29:27	1.2
  @@ -10,6 +10,7 @@
   import java.io.*;
   import java.net.*;
   import java.util.*;
  +import javax.mail.internet.ParseException;
   import org.apache.avalon.framework.component.Component;
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.component.ComponentManager;
  @@ -25,8 +26,11 @@
   import org.apache.james.Constants;
   import org.apache.james.BaseConnectionHandler;
   import org.apache.james.services.MailServer;
  +import org.apache.james.services.User;
  +import org.apache.james.services.JamesUser;
   import org.apache.james.services.UsersRepository;
   import org.apache.james.services.UsersStore;
  +import org.apache.mailet.MailAddress;
   
   /**
    * Provides a really rude network interface to administer James.
  @@ -37,7 +41,11 @@
    * @version 1.0.0, 24/04/1999
    * @author  Federico Barbieri <scoobie@pop.systemy.it>
    * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
  + * @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
    *
  + * Last changed by: $Author: charlesb $ on $Date: 2001/06/11 09:29:27 $
  + * $Revision: 1.2 $
  + *
    */
   public class RemoteManagerHandler
       extends BaseConnectionHandler
  @@ -172,10 +180,10 @@
               argument1 = commandLine.nextToken();
           }
           if (command.equalsIgnoreCase("ADDUSER")) {
  -            String user = argument;
  +            String username = argument;
               String passwd = argument1;
               try {
  -                if (user.equals("") || passwd.equals("")) {
  +                if (username.equals("") || passwd.equals("")) {
                       out.println("usage: adduser [username] [password]");
                       return true;
                   }
  @@ -183,18 +191,46 @@
                   out.println("usage: adduser [username] [password]");
                   return true;
               }
  -            if (users.contains(user)) {
  -                out.println("user " + user + " already exist");
  +            if (users.contains(username)) {
  +                out.println("user " + username + " already exist");
               } else {
  -                if(mailServer.addUser(user, passwd)) {
  -                    out.println("User " + user + " added");
  -                    getLogger().info("User " + user + " added");
  +                if(mailServer.addUser(username, passwd)) {
  +                    out.println("User " + username + " added");
  +                    getLogger().info("User " + username + " added");
                   } else {
  -                    out.println("Error adding user " + user);
  -                    getLogger().info("Error adding user " + user);
  +                    out.println("Error adding user " + username);
  +                    getLogger().info("Error adding user " + username);
                   }
               }
               out.flush();
  +        } else if (command.equalsIgnoreCase("SETPASSWORD")) {
  +	    if (argument == null || argument1 == null) {
  +                out.println("usage: setpassword [username] [password]");
  +                return true;
  +	    }
  +            String username = argument;
  +            String passwd = argument1;
  +            if (username.equals("") || passwd.equals("")) {
  +                out.println("usage: adduser [username] [password]");
  +                return true;
  +	    }
  +	    JamesUser user = (JamesUser) users.getUserByName(username);
  +	    if (user == null) {
  +		out.println("No such user");
  +		return true;
  +	    }
  +	    boolean success;
  +	    success = user.setPassword(passwd);
  +	    if (success){
  +		users.updateUser(user);
  +                out.println("Password for " + username + " reset");
  +                getLogger().info("Password for " + username + " reset");
  +	    } else {
  +                out.println("Error resetting password");
  +                getLogger().info("Error resetting password");
  +	    }
  +            out.flush();
  +	    return true;
           } else if (command.equalsIgnoreCase("DELUSER")) {
               String user = argument;
               if (user.equals("")) {
  @@ -237,6 +273,112 @@
               out.println("verify [username]               verify if specified user exist");
               out.println("quit                            close connection");
               out.flush();
  +        } else if (command.equalsIgnoreCase("SETALIAS")) {
  +	    if (argument == null || argument1 == null) {
  +                out.println("usage: setalias [username] [alias]");
  +                return true;
  +	    }
  +            String username = argument;
  +            String alias = argument1;
  +            if (username.equals("") || alias.equals("")) {
  +                out.println("usage: adduser [username] [alias]");
  +                return true;
  +	    }
  +	    JamesUser user = (JamesUser) users.getUserByName(username);
  +	    if (user == null) {
  +		out.println("No such user");
  +		return true;
  +	    }
  +	    JamesUser aliasUser = (JamesUser) users.getUserByName(alias);
  +	    if (aliasUser == null) {
  +		out.println("Alias unknown to server" 
  +                            + " - create that user first.");
  +		return true;
  +	    }
  +
  +  	    boolean success;
  +	    success = user.setAlias(alias);
  +	    if (success){
  +	        user.setAliasing(true);
  +		users.updateUser(user);
  +                out.println("Alias for " + username + " set to:" + alias);
  +                getLogger().info("Alias for " + username + " set to:" + alias);
  +	    } else {
  +                out.println("Error setting alias");
  +                getLogger().info("Error setting alias");
  +	    }
  +            out.flush();
  +	    return true;
  +        } else if (command.equalsIgnoreCase("SETFORWARDING")) {
  +	    if (argument == null || argument1 == null) {
  +                out.println("usage: setforwarding [username] [emailaddress]");
  +                return true;
  +	    }
  +            String username = argument;
  +            String forward = argument1;
  +            if (username.equals("") || forward.equals("")) {
  +                out.println("usage: adduser [username] [emailaddress]");
  +                return true;
  +	    }
  +	    // Verify user exists
  +	    JamesUser user = (JamesUser) users.getUserByName(username);
  +	    if (user == null) {
  +		out.println("No such user");
  +		return true;
  +	    }
  +	    // Veriy acceptable email address
  +	    MailAddress forwardAddr;
  +            try {
  +                 forwardAddr = new MailAddress(forward);
  +            } catch(ParseException pe) {
  +		out.println("Parse exception with that email address: "
  +                            + pe.getMessage());
  +		out.println("Forwarding address not added for " + username);
  +	        return true;
  +	    }
  +
  +  	    boolean success;
  +	    success = user.setForwardingDestination(forwardAddr);
  +	    if (success){
  +	        user.setForwarding(true);
  +		users.updateUser(user);
  +                out.println("Forwarding destination for " + username
  +                             + " set to:" + forwardAddr.toString());
  +                getLogger().info("Forwarding destination for " + username
  +                                 + " set to:" + forwardAddr.toString());
  +	    } else {
  +                out.println("Error setting forwarding");
  +                getLogger().info("Error setting forwarding");
  +	    }
  +            out.flush();
  +	    return true;
  +        } else if (command.equalsIgnoreCase("UNSETALIAS")) {
  +	    if (argument == null) {
  +                out.println("usage: unsetalias [username]");
  +                return true;
  +	    }
  +            String username = argument;
  +            if (username.equals("")) {
  +                out.println("usage: adduser [username]");
  +                return true;
  +	    }
  +	    JamesUser user = (JamesUser) users.getUserByName(username);
  +	    if (user == null) {
  +		out.println("No such user");
  +		return true;
  +	    }
  +
  +	    if (user.getAliasing()){
  +	        user.setAliasing(false);
  +		users.updateUser(user);
  +                out.println("Alias for " + username + " unset");
  +                getLogger().info("Alias for " + username + " unset");
  +	    } else {
  +                out.println("Aliasing not active for" + username);
  +                getLogger().info("Aliasing not active for" + username);
  +	    }
  +            out.flush();
  +	    return true;
           } else if (command.equalsIgnoreCase("QUIT")) {
               out.println("bye");
               return false;
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/security/DigestUtil.java
  
  Index: DigestUtil.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.security;
  
  import java.io.IOException;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.OutputStream;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import javax.mail.MessagingException;
  import javax.mail.internet.MimeUtility;
  
  
  /**
   * Class to compute and verify digests of files and strings
   *
   * @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/06/11 09:29:30 $
   * $Revision: 1.1 $
   */
  public class DigestUtil {
  
      /**
       * Command line interface. Use -help for arguments
       */
      public static void main(String[] args) {
  
  	String alg = "SHA";
  	boolean file = false;
  
  	if (args.length == 0 || args.length > 4)
          {
  	    printUsage();
  	    return;
  	}
  
  	for (int i = 0; i < args.length; i++)
          {
              if (args[i].equalsIgnoreCase("-help")
                   || args[i].equalsIgnoreCase("-usage"))
              {
  	    printUsage();
  	    return;
  	    }
              if (args[i].equalsIgnoreCase("-alg"))
              {
  		alg = args[i+1];
  	    }
              if (args[i].equalsIgnoreCase("-file"))
              {
  		file = true;
  	    }
  	}
  
          if (file)
  	{
  	    digestFile(args[args.length - 1], alg);
  	    return ;
  	}
          else 
          {
              try 
  	    {
  	        String hash = digestString(args[args.length - 1], alg);
  	        System.out.println("Hash is: " + hash);
  		return;
  	    }
              catch (NoSuchAlgorithmException nsae)
  	    {
                  System.out.println("No such algorithm available");
  	    }
  	}
      }
  
      /**
       * For CLI only
       */
      public static void printUsage() {
  	System.out.println("Usage: " 
                             + "java org.apache.james.security.DigestUtil"
                             + " [-alg algorithm]"
                             + " [-file] filename|string");
      }
  
      /**
       * Calculate digest of given file with given algorithm.
       * Writes digest to file named filename.algorithm
       *
       * @param filename the String name of the file to be hashed
       * @param algorithm the algorithm to be used
       */
      public static void digestFile(String filename, String algorithm) {
  	byte[] b = new byte[65536];
  	int count = 0;
  	int read = 0;
  	FileInputStream fis = null;
  	FileOutputStream fos = null;
  	try
          {
  	    MessageDigest md = MessageDigest.getInstance(algorithm);
  	    fis = new FileInputStream(filename);
  	    while (fis.available() > 0)
              {
  		read =  fis.read(b);
  		md.update(b, 0, read);
  		count += read;
  	    }
  	    byte[] digest = md.digest();
  	    fos = new FileOutputStream(filename + "." + algorithm);
  	    OutputStream encodedStream = MimeUtility.encode(fos, "base64");
  	    encodedStream.write(digest);
  	    fos.flush();
  	}
          catch (Exception e)
          {
  	    System.out.println("Error computing Digest: " + e);
  	}
          finally
          {
  	    try
              {
  		fis.close();
  		fos.close();
  	    }
              catch (Exception ignored)
              {
  	    }
  	}
      }
  
      /**
       * Calculate digest of given String using given algorithm.
       * Encode digest in MIME-like base64
       *
       * @param pass the String to be hashed
       * @param algorithm the algorithm to be used
       * @returns String Base-64 encoding of digest
       */
      public static String digestString(String pass, String algorithm )
              throws NoSuchAlgorithmException  {
  
  	MessageDigest md;
  	ByteArrayOutputStream bos;
  
          try
          {
              md = MessageDigest.getInstance(algorithm);
              byte[] digest = md.digest(pass.getBytes("iso-8859-1"));
  	    bos = new ByteArrayOutputStream();
  	    OutputStream encodedStream = MimeUtility.encode(bos, "base64");
  	    encodedStream.write(digest);
  	    return bos.toString("iso-8859-1");
  
  	}
          catch (IOException ioe) 
  	{
  	    throw new RuntimeException("Fatal error: " + ioe);
  	}
          catch (MessagingException me) 
  	{
  	    throw new RuntimeException("Fatal error: " + me);
  	}
      }
  
  
  }
  
  
  
  1.2       +61 -0     jakarta-james/src/java/org/apache/james/services/UsersRepository.java
  
  Index: UsersRepository.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/services/UsersRepository.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- UsersRepository.java	2001/05/11 09:39:34	1.1
  +++ UsersRepository.java	2001/06/11 09:29:32	1.2
  @@ -16,12 +16,24 @@
    *
    * @version 1.0.0, 24/04/1999
    * @author  Federico Barbieri <scoobie@pop.systemy.it>
  + * @author Charles Benett <charles@benett1.demon.co.uk>
  + *
  + * Last changed by: $Author: charlesb $ on $Date: 2001/06/11 09:29:32 $
  + * $Revision: 1.2 $
    */
   public interface UsersRepository {
   
       String USER = "USER";
   
       /**
  +     * Adds a user to the repository with the specified User object.
  +     *
  +     * @returns true if succesful, false otherwise
  +     * @since James 1.2.2
  +     */
  +    boolean addUser(User user);
  +
  +    /**
        * Adds a user to the repository with the specified attributes.  In current
        * implementations, the Object attributes is generally a String password.
        */
  @@ -29,10 +41,43 @@
   
       /**
        * Gets the attribute for a user.  Not clear on behavior.
  +     *
  +     * @deprecated As of James 1.2.2 . Use the {@link #getUserByName(String) getUserByName} method.
        */
       Object getAttributes(String name);
   
  +
  +    /**
  +     * Get the user object with the specified user name.  Return null if no
  +     * such user.
  +     *
  +     * @since James 1.2.2
  +     */
  +    User getUserByName(String name);
  +
  +    /**
  +     * Get the user object with the specified user name. Match user naems on
  +     * a case insensitive basis.  Return null if no such user.
  +     *
  +     * @since James 1.2.2
  +     */
  +    User getUserByNameCaseInsensitive(String name);
  +
       /**
  +     * Returns the user name of the user matching name on an equalsIgnoreCase
  +     * basis. Returns null if no match.
  +     */
  +    String getRealName(String name);
  +
  +    /**
  +     * Update the repository with the specified user object. A user object
  +     * with this username must already exist.
  +     *
  +     * @returns true if successful.
  +     */
  +    boolean updateUser(User user);
  +
  +    /**
        * Removes a user from the repository
        */
       void removeUser(String name);
  @@ -43,11 +88,27 @@
       boolean contains(String name);
   
       /**
  +     * Returns whether or not this user is in the repository. Names are
  +     * matched on a case insensitive basis.
  +     */
  +    boolean containsCaseInsensitive(String name);
  +
  +
  +    /**
        * Tests a user with the appropriate attributes.  In current implementations,
        * this typically means "check the password" where a String password is passed
        * as the Object attributes.
  +     *
  +     * @deprecated As of James 1.2.2, use {@link #test(String, String) test(String name, String password)}
        */
       boolean test(String name, Object attributes);
  +
  +    /**
  +     * Test if user with name 'name' has password 'password'.
  +     *
  +     * @since James 1.2.2
  +     */
  +    boolean test(String name, String password);
   
       /**
        * Returns a count of the users in the repository.
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/services/JamesUser.java
  
  Index: JamesUser.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.services;
  
  import org.apache.mailet.MailAddress;
  
  /**
   * Interface for objects representing users of an email/ messaging system.
   *
   * @author Charles Benett <charles@benett1.demon.co.uk>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/06/11 09:29:32 $
   * $Revision: 1.1 $
   */
  
  public interface JamesUser extends User {
  
      /**
       * Change password to pass. Return true if uccessful.
       */
      boolean setPassword(String pass);
  
      /**
       * Indicate if mail for this user should be forwarded to some other mail
       * server.
       */
      void setForwarding(boolean forward);
  
      /** 
       * Return true if mail for this user should be forwarded
       */
      boolean getForwarding();
  
      /**
       * Set destination for forwading mail
       * Should we use a MailAddress?
       */
      boolean setForwardingDestination(MailAddress address);
  
      /**
       * Return the destination to which email should be forwarded
       */
      MailAddress getForwardingDestination();
  
      /**
       * Indicate if mail received for this user should be delivered locally to
       * a different address.
       */
      void setAliasing(boolean alias);
  
      /**
       * Return true if emails should be dlivered locally to an alias.
       */
      boolean getAliasing();
  
      /**
       * Set local address to which email should be delivered.
       *
       * @returns true if successful
       */
      boolean setAlias(String address);
  
      /**
       * Get local address to which mail should be delivered.
       */
      String getAlias();
  
  
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/services/User.java
  
  Index: User.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.services;
  
  /**
   * Interface for objects representing users.
   *
   * @author Charles Benett <charles@benett1.demon.co.uk>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/06/11 09:29:32 $
   * $Revision: 1.1 $
   */
  
  public interface User {
  
      /**
       * Return the user name of this user
       */
      String getUserName();
  
      /**
       * Return true if pass matches password of this user.
       */
      boolean verifyPassword(String pass);
  
      /**
       * Sets new password from String. No checks made on guessability of
       * password.
       *
       * @param newPass the String that is the new password.
       * @returns true if newPass successfully added
       */
      public boolean setPassword(String newPass);
  
  }
  
  
  
  1.3       +111 -11   jakarta-james/src/java/org/apache/james/userrepository/UsersFileRepository.java
  
  Index: UsersFileRepository.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/userrepository/UsersFileRepository.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- UsersFileRepository.java	2001/06/06 13:18:32	1.2
  +++ UsersFileRepository.java	2001/06/11 09:29:35	1.3
  @@ -23,6 +23,7 @@
   import org.apache.avalon.cornerstone.services.store.Store;
   import org.apache.avalon.excalibur.concurrent.Lock;
   import org.apache.james.services.UsersRepository;
  +import org.apache.james.services.User;
   
   /**
    * Implementation of a Repository to store users on the File System.
  @@ -35,12 +36,18 @@
    *
    * @version 1.0.0, 24/04/1999
    * @author  Federico Barbieri <scoobie@pop.systemy.it>
  - * @author Charles Benett <charles@benett1.demon.co.uk>
  + * @author  <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
  + *
  + * Last changed by: $Author: charlesb $ on $Date: 2001/06/11 09:29:35 $
  + * $Revision: 1.3 $
    */
   public class UsersFileRepository
       extends AbstractLoggable
       implements UsersRepository, Component, Configurable, Composable, Initializable {
  + 
  +    protected static boolean DEEP_DEBUG = true;
   
  +    /** @deprecated what was this for? */
       private static final String TYPE = "USERS";
   
       private Store store;
  @@ -60,9 +67,17 @@
   
       public void compose( final ComponentManager componentManager )
           throws ComponentException {
  +
  +	try {
  +            store = (Store)componentManager.
  +                lookup( "org.apache.avalon.cornerstone.services.store.Store" );
  +            lock = new Lock();
   
  -        store = (Store)componentManager.
  -            lookup( "org.apache.avalon.cornerstone.services.store.Store" );
  +        } catch (Exception e) {
  +            final String message = "Failed to retrieve Store component:" + e.getMessage();
  +            getLogger().error( message, e );
  +            throw new ComponentException( message, e );
  +        }
       }
   
       public void initialize()
  @@ -79,9 +94,9 @@
               objectConfiguration.setAttribute( "model", "SYNCHRONOUS" );
   
               or = (ObjectRepository)store.select( objectConfiguration );
  -
  +	    getLogger().debug(this.getClass().getName() + " created in " + destination);
           } catch (Exception e) {
  -            getLogger().error("Failed to retrieve Store component:" + e.getMessage(), e );
  +            getLogger().error("Failed to initialize repository:" + e.getMessage(), e );
               throw e;
           }
       }
  @@ -90,20 +105,81 @@
           return or.list();
       }
   
  -    public synchronized void addUser(String name, Object attributes) {
  +    public synchronized boolean addUser(User user) {
  +	String username = user.getUserName();
  +	if (contains(username)) {
  +	    return false;
  +	}
           try {
  -            or.put(name, attributes);
  +            or.put(username, user);
           } catch (Exception e) {
               throw new RuntimeException("Exception caught while storing user: " + e );
           }
  +	return true;
       }
   
  -    public synchronized Object getAttributes(String name) {
  +    public synchronized 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 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 ) {
  +          throw new RuntimeException("No such user");
  +	}
  +	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 Object getAttributes(String name) {
  +       
  +        throw new RuntimeException("Improper use of deprecated method - read javadocs");
  +        
  +    }
  +
  +    public boolean updateUser(User user) {
  +	String username = user.getUserName();
  +	if (!contains(username)) {
  +	    return false;
  +	}
           try {
  -            return or.get(name);
  +            or.put(username, user);
           } catch (Exception e) {
  -            throw new RuntimeException("Exception while retrieving user: " + e.getMessage());
  +            throw new RuntimeException("Exception caught while storing user: " + e );
           }
  +	return true;
       }
   
       public synchronized void removeUser(String name) {
  @@ -111,7 +187,17 @@
       }
   
       public boolean contains(String name) {
  -        return or.containsKey(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, Object attributes) {
  @@ -120,6 +206,20 @@
           } catch (Exception e) {
               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() {
  
  
  
  1.2       +32 -0     jakarta-james/src/java/org/apache/james/userrepository/UsersLDAPRepository.java
  
  Index: UsersLDAPRepository.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/userrepository/UsersLDAPRepository.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- UsersLDAPRepository.java	2001/05/11 09:52:29	1.1
  +++ UsersLDAPRepository.java	2001/06/11 09:29:36	1.2
  @@ -22,11 +22,15 @@
   import org.apache.avalon.framework.context.Contextualizable;
   import org.apache.avalon.framework.logger.Loggable;
   import org.apache.james.Constants;
  +import org.apache.james.services.User;
   import org.apache.james.services.UsersRepository;
   import org.apache.log.Logger;
   
   /**
    * Implementation of a Repository to store users.
  + *
  + * This clas is a dummy for the proposal!
  + *
    * @version 1.0.0, 24/04/1999
    * @author  Charles Bennett
    */
  @@ -202,6 +206,34 @@
   
   
       // Methods from interface UsersRepository --------------------------
  +
  +    public boolean addUser(User user) {
  +	return false;
  +    }
  +
  +    public  User getUserByName(String name) {
  +	return new DefaultUser("dummy", "dummy");
  +    }
  +
  +    public User getUserByNameCaseInsensitive(String name) {
  +	return getUserByName(name);
  +    }
  +
  +    public boolean containsCaseInsensitive(String name) {
  +        return contains(name);
  +    }
  +
  +    public String getRealName(String name) {
  +	return null;
  +    }
  +
  +    public boolean updateUser(User user) {
  +	return false;
  +    }
  +
  +    public boolean test(String name, String password) {
  +	return false;
  +    }
   
       /**
        * Adds userName to the MemberAttribute (specified in conf.xml) of this
  
  
  
  1.2       +29 -0     jakarta-james/src/java/org/apache/james/userrepository/UsersTownRepository.java
  
  Index: UsersTownRepository.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/userrepository/UsersTownRepository.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- UsersTownRepository.java	2001/05/11 09:52:29	1.1
  +++ UsersTownRepository.java	2001/06/11 09:29:36	1.2
  @@ -15,6 +15,7 @@
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
   import org.apache.avalon.framework.logger.Loggable;
  +import org.apache.james.services.User;
   import org.apache.james.services.UsersRepository;
   import org.apache.log.LogKit;
   import org.apache.log.Logger;
  @@ -53,6 +54,34 @@
       }
   
       // Methods from interface Repository
  +
  +    public boolean addUser(User user) {
  +	return false;
  +    }
  +
  +    public  User getUserByName(String name) {
  +	return new DefaultUser("dummy", "dummy");
  +    }
  +
  +    public User getUserByNameCaseInsensitive(String name) {
  +	return getUserByName(name);
  +    }
  +
  +    public boolean containsCaseInsensitive(String name) {
  +        return contains(name);
  +    }
  +
  +    public String getRealName(String name) {
  +	return null;
  +    }
  +
  +    public boolean updateUser(User user) {
  +	return false;
  +    }
  +
  +    public boolean test(String name, String password) {
  +	return false;
  +    }
   
       public synchronized void addUser(String strUserName, Object attributes) {
           try {
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/userrepository/AbstractUsersRepository.java
  
  Index: AbstractUsersRepository.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.userrepository;
  
  import java.util.*;
  import org.apache.james.services.*;
  import org.apache.avalon.framework.logger.AbstractLoggable;
  
  /**
   * A partial implementation of a Repository to store users on the File System.
   * <p>This implements common functionality found in different UsersRespository 
   * implementations, and makes it easier to create new User repositories.</p>
   *
   * @author Darrell DeBoer <dd@bigdaz.com>
   * @author Charles Benett <charles@benett1.demon.co.uk>
   */
  public abstract class AbstractUsersRepository
      extends AbstractLoggable
      implements UsersRepository
  {
      //
      // Core Abstract methods - override these for a functional UserRepository.
      //
      /**
       * Returns a list populated with all of the Users in the repository.
       * @return an <code>Iterator</code> of <code>JamesUser</code>s.
       */
      protected abstract Iterator listAllUsers();
  
      /**
       * Adds a user to the underlying Repository.
       * The user name must not clash with an existing user.
       */
      protected abstract void doAddUser(DefaultJamesUser user);
  
      /**
       * Removes a user from the underlying repository.
       * If the user doesn't exist, returns ok.
       */
      protected abstract void doRemoveUser(DefaultJamesUser user);
  
      //
      // Extended protected methods.
      // These provide very basic default implementations, which will work,
      // but may need to be overridden by subclasses for performance reasons.
      //
      /**
       * Updates a user record to match the supplied User.
       * This is a very basic, remove-then-insert implementation,
       * which should really be overridden, but will work.
       */
      protected void doUpdateUser(DefaultJamesUser user)
      {
          doRemoveUser(user);
          doAddUser(user);
      }
  
      /**
       * Produces the complete list of User names, with correct case.
       * @return a <code>List</code> of <code>String</code>s representing
       *         user names.
       */
      protected List listUserNames()
      {
          Iterator users = listAllUsers();
          List userNames = new LinkedList();
          while ( users.hasNext() ) {
              JamesUser user = (JamesUser)users.next();
              userNames.add(user.getUserName());
          }
  
          return userNames;
      }
  
      /**
       * Gets a user by name, ignoring case if specified.
       * This implementation gets the entire set of users,
       *  and scrolls through searching for one matching <code>name</code>.
       */
      protected User getUserByName(String name, boolean ignoreCase)
      {
          // Just iterate through all of the users until we find one matching.
          Iterator users = listAllUsers();
          while ( users.hasNext() ) 
          {
              JamesUser user = (JamesUser)users.next();
              String username = user.getUserName();
              if (( !ignoreCase && username.equals(name) ) ||
                  ( ignoreCase && username.equalsIgnoreCase(name) )) {
                  return user;
              }
          }
          // Not found - return null
          return null;
      }
  
      //
      // User conversion.
      //
      /**
       * This method is hackery to get JamesUser instances, regardless of what 
       * user implementation is passed.
       * Ideally, the UsersRepository interface would be updated to accept only 
       *  JamesUsers, or we could combine the 2.
       */
      protected DefaultJamesUser getJamesUser(User user)
      {
          // Return JamesUser instances directly.
          if ( user instanceof DefaultJamesUser ) {
              return (DefaultJamesUser)user;
          }
          // Build a JamesUser with a DefaultUser.
          else if ( user instanceof DefaultUser ) {
              DefaultUser defaultUser = (DefaultUser)user;
              return new DefaultJamesUser(defaultUser.getUserName(), 
                                          defaultUser.getHashedPassword(), 
                                          defaultUser.getHashAlgorithm());
          }
          // Shouldn't be any other implementations.
          else {
              throw new RuntimeException("An unknown implementation of User was found. This implementation cannot be persisted to a UsersJDBCRepsitory.");
          }
  
      }
  
      //
      // UsersRepository interface implementation.
      //
      /**
       * Adds a user to the repository with the specified User object.
       * Users names must be unique-case-insensitive in the repository.
       *
       * @returns true if succesful, false otherwise
       * @since James 1.2.2
       */
      public boolean addUser(User user)
      {
          String username = user.getUserName();
  
          if ( containsCaseInsensitive(username) ) {
              return false;
          }
          
          doAddUser(getJamesUser(user));
          return true;
      }
  
      /**
       * Adds a user to the repository with the specified attributes.  In current
       * implementations, the Object attributes is generally a String password.
       */
      public void addUser(String name, Object attributes) 
      {
          throw new RuntimeException("Improper use of deprecated method - read javadocs");
      }
  
      /**
       * Update the repository with the specified user object. A user object
       * with this username must already exist.
       *
       * @returns true if successful.
       */
      public boolean updateUser(User user)
      {
          // Return false if it's not found.
          if ( ! contains(user.getUserName()) ) {
              return false;
          }
          else {
              doUpdateUser(getJamesUser(user));
              return true;
          }
      }
  
      /**
       * Removes a user from the repository
       */
      public void removeUser(String name)
      {
          User user = getUserByName(name);
          if ( user != null ) {
              doRemoveUser(getJamesUser(user));
          }
      }
  
      /**
       * Gets the attribute for a user.  Not clear on behavior.
       *
       * @deprecated As of James 1.2.2 . Use the {@link #getUserByName(String) getUserByName} method.
       */
      public Object getAttributes(String name)
      {
          throw new RuntimeException("Improper use of deprecated method - read javadocs");
      }
  
      /**
       * Get the user object with the specified user name.  Return null if no
       * such user.
       *
       * @since James 1.2.2
       */
      public User getUserByName(String name)
      {
          return getUserByName(name, false);
      }
  
      /**
       * Get the user object with the specified user name. Match user naems on
       * a case insensitive basis.  Return null if no such user.
       *
       * @since James 1.2.2
       */
      public User getUserByNameCaseInsensitive(String name)
      {
          return getUserByName(name, true);
      }
  
      /**
       * Returns the user name of the user matching name on an equalsIgnoreCase
       * basis. Returns null if no match.
       */
      public String getRealName(String name)
      {
          // Get the user by name, ignoring case, and return the correct name.
          User user = getUserByName(name, true);
          if ( user == null ) {
              return null;
          }
          else {
              return user.getUserName();
          }
      }
  
      /**
       * Returns whether or not this user is in the repository
       */
      public boolean contains(String name)
      {
          User user = getUserByName(name, false);
          return ( user != null );
      }
  
      /**
       * Returns whether or not this user is in the repository. Names are
       * matched on a case insensitive basis.
       */
      public boolean containsCaseInsensitive(String name)
      {
          User user = getUserByName( name, true );
          return ( user != null );
      }
  
      /**
       * Tests a user with the appropriate attributes.  In current implementations,
       * this typically means "check the password" where a String password is passed
       * as the Object attributes.
       *
       * @deprecated As of James 1.2.2, use {@link #test(String, String) test(String name, String password)}
       */
      public boolean test(String name, Object attributes)
      {
          throw new RuntimeException("Improper use of deprecated method - read javadocs");
      }
  
      /**
       * Test if user with name 'name' has password 'password'.
       *
       * @since James 1.2.2
       */
      public boolean test(String name, String password)
      {
          User user = getUserByName(name, false);
          if ( user == null ) {
              return false;
          }
          else {
              return user.verifyPassword(password);
          }
      }
  
      /**
       * Returns a count of the users in the repository.
       */
      public int countUsers()
      {
          List usernames = listUserNames();
          return usernames.size();
      }
  
      /**
       * List users in repository.
       *
       * @returns Iterator over a collection of Strings, each being one user in the repository.
       */
      public Iterator list()
      {
          return listUserNames().iterator();
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/userrepository/DefaultJamesUser.java
  
  Index: DefaultJamesUser.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.userrepository;
  
  import java.io.Serializable;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.james.services.User;
  import org.apache.james.services.JamesUser;
  import org.apache.mailet.MailAddress;
  
  /**
   * Implementation of User Interface.
   *
   * @author Charles Benett <charles@benett1.demon.co.uk>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/06/11 09:29:35 $
   * $Revision: 1.1 $
   */
  
  public class DefaultJamesUser 
          extends DefaultUser
          implements JamesUser, Initializable {
  
      private boolean forwarding;
      private MailAddress forwardingDestination;
      private boolean aliasing;
      private String alias;
  
      public DefaultJamesUser(String name, String alg) {
  	super(name, alg);
      }
  
      public DefaultJamesUser(String name, String passwordHash, String hashAlg) {
          super(name, passwordHash, hashAlg);
      }
  
  
      /**
       * Call initialize when creating a new instance.
       */
      public void initialize() {
  	forwarding = false;
  	forwardingDestination = null;
  	aliasing = false;
  	alias = "";
      }
  
      public void setForwarding(boolean forward) {
  	forwarding = forward;
      }
  
      public boolean getForwarding() {
  	return forwarding;
      }
  
      
      public boolean setForwardingDestination(MailAddress address) {
  	/* Some verification would be good */
  	forwardingDestination = address;
  	return true;
      }
  
      public MailAddress getForwardingDestination() {
  	return forwardingDestination;
      }
  
      public void setAliasing(boolean alias) {
          aliasing = alias;
      }
  
      public boolean getAliasing() {
  	return aliasing;
      }
  
      public boolean setAlias(String address) {
  	/* Some verification would be good */
  	alias = address;
  	return true;
      }
  
      public String getAlias() {
  	return alias;
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/userrepository/DefaultUser.java
  
  Index: DefaultUser.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.userrepository;
  
  import java.io.Serializable;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.util.Arrays;
  import org.apache.james.security.DigestUtil;
  import org.apache.james.services.User;
  
  /**
   * Implementation of User Interface. Instances of this class do not allow
   * the the user name to be reset.
   *
   * @author Charles Benett <charles@benett1.demon.co.uk>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/06/11 09:29:35 $
   * $Revision: 1.1 $
   */
  
  public class DefaultUser implements User, Serializable {
  
      private String userName;
      private String hashedPassword;
      private String algorithm ;
  
      /**
       * Standard constructor.
       *
       * @param name the String name of this user
       */
      public DefaultUser(String name, String hashAlg) {
          userName = name;
  	algorithm = hashAlg;
      }
  
      /**
       * Constructor for repositories that are construcing user objects from
       * separate fields, e.g. databases.
       *
       * @param name the String name of this user
       * @param passwordHash the String hash of this users current password
       * @param hashAlg the String algorithm used to generate the hash of the
       * password
       */
      public DefaultUser(String name, String passwordHash, String hashAlg) {
  	userName = name;
  	hashedPassword = passwordHash;
          algorithm = hashAlg;
      }
  
      /**
       * Accessor for immutable name
       *
       * @returns the String of this users name
       */
      public String getUserName() {
  	return userName;
      }
  
      /**
       *  Method to verify passwords. 
       *
       * @param pass the String that is claimed to be the password for this user
       * @returns true if the hash of pass with the current algorithm matches
       * the stored hash.
       */
      public boolean verifyPassword(String pass) {
          try {
   	    String hashGuess = DigestUtil.digestString(pass, algorithm);
  	    return hashedPassword.equals(hashGuess);
          } catch (NoSuchAlgorithmException nsae) {
  	    throw new RuntimeException("Security error: " + nsae);
  	}
      }
  
      /**
       * Sets new password from String. No checks made on guessability of
       * password.
       *
       * @param newPass the String that is the new password.
       * @returns true if newPass successfuly hashed
       */
      public boolean setPassword(String newPass) {
          try {
              hashedPassword = DigestUtil.digestString(newPass, algorithm);
              return true;
          } catch (NoSuchAlgorithmException nsae) {
  	    throw new RuntimeException("Security error: " + nsae);
  	}
      }
  
      /**
       * Method to access hash of password
       *
       * @returns the String of the hashed Password
       */
      protected String getHashedPassword() {
  	return hashedPassword;
      }
  
      /**
       * Method to access the hashing algorithm of the password.
       */
      protected String getHashAlgorithm() {
          return algorithm;
      }
  
  
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/userrepository/UsersJDBCRepository.java
  
  Index: UsersJDBCRepository.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.userrepository;
  
  import org.apache.james.services.*;
  import org.apache.mailet.MailAddress;
  import org.apache.avalon.framework.activity.*;
  import org.apache.avalon.framework.component.*;
  import org.apache.avalon.framework.configuration.*;
  import org.apache.avalon.framework.logger.*;
  import org.apache.avalon.excalibur.datasource.*;
  
  import java.sql.*;
  import java.util.*;
  
  /**
   * An implementation of a UsersRepository which is backed by a database.<br>
   * This implementation has been tested successfully on:
   * <TABLE BORDER="1" WIDTH="100%">
   * <TR><TH>Database Product</TH><TH>versions</TH><TH>drivers</TH></TR>
   * <TR><TD>MySQL Server</TD><TD>3.23</TD><TD>MM MySQL 2.0.3</TD></TR>
   * <TR><TD>MySQL Server</TD><TD>3.23</TD><TD>JDBC-ODBC bridge</TD></TR>
   * <TR><TD>Oracle8i</TD><TD>8.1.6</TD><TD>Oracle Thin Driver</TD></TR>
   * <TR><TD>Microsoft SQL Server</TD><TD>7</TD><TD>Inet Sprinta</TD></TR>
   * </TABLE>
   * <br>
   * This implementation is known to fail on:
   * <TABLE BORDER="1" WIDTH="100%">
   * <TR><TH>Database Product</TH><TH>versions</TH><TH>drivers</TH></TR>
   * <TR><TD>Microsoft SQL Server</TD><TD>7</TD><TD>JDBC-ODBC bridge.</TD></TR>
   * </TABLE>
   * 
   * @author Darrell DeBoer <dd@bigdaz.com>
   */
  public class UsersJDBCRepository extends AbstractUsersRepository
      implements UsersRepository, Loggable, Component, Configurable, Initializable
  {
      /*
      TODO
          - allow configurable SQL statements.
          - use Connection pooling and management from Avalon framework.
      */
      private String m_dbUrl;
      private String m_dbUser;
      private String m_dbPassword;
  
      private String m_tableName = "JamesUsers";
      
      // Fetches all Users from the db.
      private String m_getUsersSql = "SELECT username, pwdHash, pwdAlgorithm, useForwarding, forwardDestination, useAlias, alias FROM " + m_tableName;
      
      // This statement guarantees that we'll get a case-insensitive match - otherwise it's database dependent.
      private String m_userByNameCaseInsensitiveSql = m_getUsersSql + " WHERE LOWER(username) = ?";
  
      // Insert, update and delete are not guaranteed to be case-insensitive
      // this is handled in code.
      private String m_insertUserSql = "INSERT INTO " + m_tableName + " (username, pwdHash, pwdAlgorithm, useForwarding, forwardDestination, useAlias, alias) VALUES (?,?,?,?,?,?,?)";
      private String m_updateUserSql = "UPDATE " + m_tableName + " SET pwdHash = ?, pwdAlgorithm = ?, useForwarding = ?, forwardDestination = ?, useAlias = ?, alias = ? WHERE username = ?";
      private String m_deleteUserSql = "DELETE FROM " + m_tableName + " WHERE username = ?";
  
      // Creates a single table with "username" the Primary Key.
      private String m_createUserTableSql = "CREATE TABLE " + m_tableName + " (username VARCHAR(50) NOT NULL, pwdHash VARCHAR(50), pwdAlgorithm VARCHAR(20), useForwarding SMALLINT, forwardDestination VARCHAR(250), useAlias SMALLINT, alias VARCHAR(250), PRIMARY KEY(username))";
  
      /**
       * Configures the UserRepository for JDBC access.
       * Required parameters in the config file are:
       * <UL>
       *     <LI>destination.driver.class - the class of the JDBC driver to load.</LI>
       *     <LI>destination.datasource.dburl - the database connection string.</LI>
       * </UL>
       * Optional parameters are:
       * <UL>
       *     <LI>destination.datasource.user - username to connect to the database.</LI>
       *     <LI>destination.datasource.password - password to connect to the database.</LI>
       * </UL>
       */
      public void configure(Configuration configuration) throws ConfigurationException 
      {
          // Load the driver.
  
          String driverName = configuration.getChild("destination").getChild("driver").getAttribute("class");
          getLogger().debug("Loading driver :" + driverName);
          try {
              Class.forName(driverName);
              getLogger().info("Database driver " + driverName + " loaded");
          } 
          catch ( ClassNotFoundException cnfe ) {
              throw new ConfigurationException("Could not load specified driver - " + driverName);
          }
  
          // Get the database connection configuration.
          Configuration dbConfig = configuration.getChild("destination").getChild("datasource");
          m_dbUrl = dbConfig.getChild("dburl").getValue();
          m_dbUser = dbConfig.getChild("user").getValue(null);
          m_dbPassword = dbConfig.getChild("password").getValue(null);
      }
  
      /**
       * Initialises the JDBC repository.
       * 1) Tests the connection to the database.
       * 2) Initialises the database with the required tables, if necessary.
       * 
       * @exception Exception if a database access error occurs.
       */
      public void initialize() throws Exception {
          // Test the connection to the database, by getting the DatabaseMetaData.
          Connection conn = getConnection();
          try{
              DatabaseMetaData dbMetaData = conn.getMetaData();
  
              // Make sure that the Users table is there, if not create it.
  
              // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo.
              // NB this should work, but some drivers (eg mm MySQL) 
              // don't return the right details, hence the hackery below.
              /*
              String tableName = m_tableName;
              if ( dbMetaData.storesLowerCaseIdentifiers() ) {
                  tableName = tableName.toLowerCase();
              }
              else if ( dbMetaData.storesUpperCaseIdentifiers() ) {
                  tableName = tableName.toUpperCase();
              }
              */
  
              // Try UPPER, lower, and MixedCase, to see if the table is there.
              if (! ( tableExists(dbMetaData, m_tableName) ||
                      tableExists(dbMetaData, m_tableName.toUpperCase()) ||
                      tableExists(dbMetaData, m_tableName.toLowerCase()) )) 
              {
                  // Users table doesn't exist - create it.
                  PreparedStatement createStatement = conn.prepareStatement(m_createUserTableSql);
                  createStatement.execute();
                  createStatement.close();
                  getLogger().info("Created \'JamesUsers\' table.");
                  System.out.println("UsersStore - UsersJDBCRepository : Created \'JamesUsers\' table.");
              }
          }
          finally {
              conn.close();
          }
      }
  
      private boolean tableExists(DatabaseMetaData dbMetaData, String tableName)
          throws SQLException
      {
          ResultSet rsTables = dbMetaData.getTables(null, null, tableName, null);
          boolean found = rsTables.next();
          rsTables.close();
          return found;
      }
  
      //
      // Superclass methods.
      //
      /**
       * Returns a list populated with all of the Users in the repository.
       * @return an <code>Iterator</code> of <code>DefaultJamesUser</code>s.
       */
      protected Iterator listAllUsers() 
      {
          List userList = new LinkedList(); // Build the users into this list.
  
          Connection conn = getConnection();
          try {
              // Get a ResultSet containing all users.
              PreparedStatement getUsersStatement = 
                  getConnection().prepareStatement(m_getUsersSql);
              ResultSet rsUsers = getUsersStatement.executeQuery();
  
              // Loop through and build a JamesUser for every row.
              while ( rsUsers.next() ) {
                  DefaultJamesUser user = readUserFromResultSet(rsUsers);
                  userList.add(user);
              }
  
              rsUsers.close();
              getUsersStatement.close();
          }
          catch ( SQLException sqlExc) {
              sqlExc.printStackTrace();
              throw new RuntimeException("Error accessing database");
          }
          finally {
              try {
                  conn.close();
              }
              catch (SQLException sqlExc) {
                  sqlExc.printStackTrace();
                  throw new RuntimeException("Error closing connection");
              }
          }
  
          return userList.iterator();
      }
  
      /**
       * Adds a user to the underlying Repository.
       * The user name must not clash with an existing user.
       */
      protected void doAddUser(DefaultJamesUser user)
      {
          // Get the user details to save.
          String username = user.getUserName();
          String pwdHash = user.getHashedPassword();
          String pwdAlgorithm = user.getHashAlgorithm();
          int useForwarding = user.getForwarding() ? 1 : 0;
          MailAddress forwardAddress = user.getForwardingDestination();
          String forwardDestination = null;
          if ( forwardAddress != null ) {
              forwardDestination = forwardAddress.toString();
          }
          int useAlias = user.getAliasing() ? 1 : 0;
          String alias = user.getAlias();
  
          Connection conn = getConnection();
  
          // Insert into the database.
          try {
              PreparedStatement addUserStatement = conn.prepareStatement(m_insertUserSql);
              
              addUserStatement.setString(1, username);
              addUserStatement.setString(2, pwdHash);
              addUserStatement.setString(3, pwdAlgorithm);
              addUserStatement.setInt(4, useForwarding);
              addUserStatement.setString(5, forwardDestination);
              addUserStatement.setInt(6, useAlias);
              addUserStatement.setString(7, alias);
  
              addUserStatement.execute();
  
              addUserStatement.close();
          }
          catch ( SQLException sqlExc ) {
              sqlExc.printStackTrace();
              throw new RuntimeException("Error accessing database");
          }
          finally {
              try {
                  conn.close();
              }
              catch (SQLException sqlExc) {
                  sqlExc.printStackTrace();
                  throw new RuntimeException("Error closing connection");
              }
          }
      }
  
      /**
       * Removes a user from the underlying repository.
       * If the user doesn't exist, returns ok.
       */
      protected void doRemoveUser(DefaultJamesUser user)
      {
          String username = user.getUserName();
  
          Connection conn = getConnection();
          // Delete from the database.
          try {
              PreparedStatement removeUserStatement = conn.prepareStatement(m_deleteUserSql);
              removeUserStatement.setString(1, username);
              removeUserStatement.execute();
              removeUserStatement.close();
          }
          catch ( SQLException sqlExc ) {
              sqlExc.printStackTrace();
              throw new RuntimeException("Error accessing database");
          }
          finally {
              try {
                  conn.close();
              }
              catch (SQLException sqlExc) {
                  sqlExc.printStackTrace();
                  throw new RuntimeException("Error closing connection");
              }
          }
      }
  
      /**
       * Gets a user by name, ignoring case if specified.
       * This overrides the basic implementation in AbstractUsersRepository
       * to increase performance.
       */
      protected User getUserByName(String name, boolean ignoreCase)
      {
          // Always get the user via case-insensitive SQL,
          // then check case if necessary.
          Connection conn = getConnection();
          try {
              // Get a ResultSet containing all users.
              String sql = m_userByNameCaseInsensitiveSql;
              PreparedStatement getUsersStatement = 
                  getConnection().prepareStatement(sql);
  
              getUsersStatement.setString(1, name.toLowerCase());
  
              ResultSet rsUsers = getUsersStatement.executeQuery();
  
              // For case-insensitive matching, the first matching user will be returned.
              DefaultJamesUser user = null;
              while ( rsUsers.next() ) {
                  DefaultJamesUser rowUser = readUserFromResultSet(rsUsers);
                  String actualName = rowUser.getUserName();
                      
                  // Check case before we assume it's the right one.
                  if ( ignoreCase || actualName.equals(name) ) {
                      user = rowUser;
                      break;
                  }
              }
              return user;
          }
          catch ( SQLException sqlExc ) {
              sqlExc.printStackTrace();
              throw new RuntimeException("Error accessing database");
          }
          finally {
              try {
                  conn.close();
              }
              catch (SQLException sqlExc) {
                  sqlExc.printStackTrace();
                  throw new RuntimeException("Error closing connection");
              }
          }
      }
  
      /**
       * Updates a user record to match the supplied User.
       * This is a very basic, remove-then-insert implementation,
       * which should really be overridden, but will work.
       */
      protected void doUpdateUser(DefaultJamesUser user)
      {
          // Get the user details to save.
          String username = user.getUserName();
          String pwdHash = user.getHashedPassword();
          String pwdAlgorithm = user.getHashAlgorithm();
          int useForwarding = user.getForwarding() ? 1 : 0;
          MailAddress forwardAddress = user.getForwardingDestination();
          String forwardDestination = null;
          if ( forwardAddress != null ) {
              forwardDestination = forwardAddress.toString();
          }
          int useAlias = user.getAliasing() ? 1 : 0;
          String alias = user.getAlias();
  
          Connection conn = getConnection();
  
          // Insert into the database.
          try {
              PreparedStatement updateUserStatement = conn.prepareStatement(m_updateUserSql);
              
              updateUserStatement.setString(1, pwdHash);
              updateUserStatement.setString(2, pwdAlgorithm);
              updateUserStatement.setInt(3, useForwarding);
              updateUserStatement.setString(4, forwardDestination);
              updateUserStatement.setInt(5, useAlias);
              updateUserStatement.setString(6, alias);
              updateUserStatement.setString(7, username);
  
              updateUserStatement.execute();
  
              updateUserStatement.close();
          }
          catch ( SQLException sqlExc ) {
              sqlExc.printStackTrace();
              throw new RuntimeException("Error accessing database");
          }
          finally {
              try {
                  conn.close();
              }
              catch (SQLException sqlExc) {
                  sqlExc.printStackTrace();
                  throw new RuntimeException("Error closing connection");
              }
          }
      }
  
      //
      // Private methods
      //
      /**
       * Opens a database connection.
       */
      private Connection getConnection()
      {
          try {
              if ( m_dbUser == null ) {
                  return DriverManager.getConnection(m_dbUrl);
              }
              else {
                  return DriverManager.getConnection(m_dbUrl, m_dbUser, m_dbPassword);
              }
          }
          catch ( SQLException sqlExc ) {
              sqlExc.printStackTrace();
              throw new RuntimeException("Error connecting to database");
          }
      }
  
      /**
       * Reads a user from the current row in a ResultSet.
       */
      private DefaultJamesUser readUserFromResultSet(ResultSet rsUsers)
          throws SQLException
      {
          // Get the column values
          String username = rsUsers.getString(1);
          String pwdHash = rsUsers.getString(2);
          String pwdAlgorithm = rsUsers.getString(3);
          boolean useForwarding = rsUsers.getBoolean(4);
          String forwardingDestination = rsUsers.getString(5);
          boolean useAlias = rsUsers.getBoolean(6);
          String alias = rsUsers.getString(7);
  
          MailAddress forwardAddress = null;
          if ( forwardingDestination != null ) {
              try {
                  forwardAddress = new MailAddress(forwardingDestination);
              }
              catch (javax.mail.internet.ParseException pe) {
                  throw new RuntimeException("Invalid mail address in database: " + forwardingDestination + ", for user " + username + ".");
              }
          }
  
          // Build a DefaultJamesUser with these values, and add to the list.
          DefaultJamesUser user = new DefaultJamesUser(username, pwdHash, pwdAlgorithm);
          user.setForwarding(useForwarding);
          user.setForwardingDestination(forwardAddress);
          user.setAliasing(useAlias);
          user.setAlias(alias);
  
          return user;
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: james-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: james-dev-help@jakarta.apache.org


Mime
View raw message