You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ca...@apache.org on 2006/08/31 02:57:34 UTC

svn commit: r438734 - in /maven/shared/trunk/maven-user/maven-user-model/src: main/java/org/apache/maven/user/model/ main/java/org/apache/maven/user/model/impl/ main/java/org/apache/maven/user/model/rules/ main/mdo/ test/java/org/apache/maven/user/mode...

Author: carlos
Date: Wed Aug 30 17:57:33 2006
New Revision: 438734

URL: http://svn.apache.org/viewvc?rev=438734&view=rev
Log:
Password validation changes
Submitted by: Joakime Erdfelt

Added:
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/PlainTextPasswordEncoder.java   (with props)
Modified:
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordEncoder.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRule.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRuleViolationException.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/UserSecurityPolicy.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/AbstractJAASPasswordEncoder.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserManager.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserSecurityPolicy.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/AlphaPasswordRule.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/CharacterLengthPasswordRule.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/MustHavePasswordRule.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/NumericalPasswordRule.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/ReusePasswordRule.java
    maven/shared/trunk/maven-user/maven-user-model/src/main/mdo/user.xml
    maven/shared/trunk/maven-user/maven-user-model/src/test/java/org/apache/maven/user/model/impl/DefaultUserManagerTest.java

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordEncoder.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordEncoder.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordEncoder.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordEncoder.java Wed Aug 30 17:57:33 2006
@@ -20,50 +20,117 @@
  * Interface for performing authentication operations on a password.
  * </p>
  * 
- * <p>Copied from Acegi Security removing Spring dependencies.</p>
+ * <p>Copied from Acegi Security removing Spring dependencies, reorganizing for default salt.</p>
  *
  * @author colin sampaleanu
  * @version $Id$
  */
 public interface PasswordEncoder
 {
-
     /**
      * Provide the Plexus Component Role.
      */
     public static final String ROLE = PasswordEncoder.class.getName();
+    
+    /**
+     * <p>
+     * Sets the system wide salt to use in the encoder.
+     * </p>
+     * 
+     * <p>
+     * The specified salt will potentially be used by the implementation to "salt" the initial value before
+     * encoding. A salt is usually a user-specific value which is added to the password before the digest is computed.
+     * This means that computation of digests for common dictionary words will be different than those in the backend
+     * store, because the dictionary word digests will not reflect the addition of the salt. If a per-user salt is
+     * used (rather than a system-wide salt), it also means users with the same password will have different digest
+     * encoded passwords in the backend store.
+     * </p>
+     * 
+     * @param salt the salt to use as a default for the encoder.
+     */
+    public void setSystemSalt( Object salt );
 
-    //~ Methods ========================================================================================================
-
     /**
-     * <p>Encodes the specified raw password with an implementation specific algorithm.</p>
-     *  <P>This will generally be a one-way message digest such as MD5 or SHA, but may also be a plaintext
+     * <p>
+     * Encodes the specified raw password with an implementation specific algorithm, using the system wide salt.
+     * </p>
+     * 
+     * <p>
+     * This will generally be a one-way message digest such as MD5 or SHA, but may also be a plaintext
+     * variant which does no encoding at all, but rather returns the same password it was fed. The latter is useful to
+     * plug in when the original password must be stored as-is.
+     * </p>
+     * 
+     * @param rawPass the password to encode
+     *
+     * @return encoded password
+     */
+    public String encodePassword( String rawPass );
+    
+    /**
+     * <p>
+     * Encodes the specified raw password with an implementation specific algorithm, using user specific salt.
+     * </p>
+     * 
+     * <p>
+     * This will generally be a one-way message digest such as MD5 or SHA, but may also be a plaintext
      * variant which does no encoding at all, but rather returns the same password it was fed. The latter is useful to
-     * plug in when the original password must be stored as-is.</p>
-     *  <p>The specified salt will potentially be used by the implementation to "salt" the initial value before
+     * plug in when the original password must be stored as-is.
+     * </p>
+     * 
+     * <p>
+     * The specified salt will potentially be used by the implementation to "salt" the initial value before
      * encoding. A salt is usually a user-specific value which is added to the password before the digest is computed.
      * This means that computation of digests for common dictionary words will be different than those in the backend
      * store, because the dictionary word digests will not reflect the addition of the salt. If a per-user salt is
      * used (rather than a system-wide salt), it also means users with the same password will have different digest
-     * encoded passwords in the backend store.</p>
-     *  <P>If a salt value is provided, the same salt value must be use when calling the  {@link
-     * #isPasswordValid(String, String, Object)} method. Note that a specific implementation may choose to ignore the
-     * salt value (via <code>null</code>), or provide its own.</p>
-     *
+     * encoded passwords in the backend store.
+     * </p>
+     * 
      * @param rawPass the password to encode
-     * @param salt optionally used by the implementation to "salt" the raw password before encoding. A
-     *        <code>null</code> value is legal.
-     *
+     * @param salt optionally used by the implementation to "salt" the raw password before encoding. 
+     *             A <code>null</code> value is legal.
      * @return encoded password
      */
     public String encodePassword( String rawPass, Object salt );
+    
 
     /**
-     * <p>Validates a specified "raw" password against an encoded password.</p>
-     *  <P>The encoded password should have previously been generated by {@link #encodePassword(String,
+     * <p>
+     * Validates a specified "raw" password against an encoded password, using the system wide salt.
+     * </p>
+     * 
+     * <p>
+     * The encoded password should have previously been generated by {@link #encodePassword(String)}. 
+     * This method will encode the <code>rawPass</code> (using the system wide <code>salt</code>),  and then
+     * compared it with the presented <code>encPass</code>.
+     * </p>
+     * 
+     * <p>
+     * For an explanation of salts, please refer to {@link #setSystemSalt(Object)}.
+     * </p>
+     *
+     * @param encPass a pre-encoded password
+     * @param rawPass a raw password to encode and compare against the pre-encoded password
+     *
+     * @return true if the password is valid , false otherwise
+     */
+    public boolean isPasswordValid( String encPass, String rawPass );
+    
+    /**
+     * <p>
+     * Validates a specified "raw" password against an encoded password, using a user specific salt.
+     * </p>
+     * 
+     * <p>
+     * The encoded password should have previously been generated by {@link #encodePassword(String,
      * Object)}. This method will encode the <code>rawPass</code> (using the optional <code>salt</code>),  and then
-     * compared it with the presented <code>encPass</code>.</p>
-     *  <p>For a discussion of salts, please refer to {@link #encodePassword(String, Object)}.</p>
+     * compared it with the presented <code>encPass</code>.
+     * </p>
+     * 
+     * <p>
+     * For a discussion of salts, please refer to {@link #encodePassword(String, Object)}.
+     * </p>
      *
      * @param encPass a pre-encoded password
      * @param rawPass a raw password to encode and compare against the pre-encoded password

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRule.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRule.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRule.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRule.java Wed Aug 30 17:57:33 2006
@@ -28,9 +28,21 @@
      * Provide the Plexus Component Role.
      */
     public static final String ROLE = PasswordRule.class.getName();
+    
+    /**
+     * Sets the User Security Policy to use.
+     * 
+     * The policy is set once per instance of a PasswordRule object.
+     * 
+     * @param policy the policy to use.
+     */
+    void setUserSecurityPolicy(UserSecurityPolicy policy);
 
     /**
      * Tests the {@link User#getPassword()} for a valid password, based on rule.
+     * 
+     * @param violations the place to add any password rule violations that this rule has discovered.
+     * @param user the User to test.    
      */
-    void testPassword( PasswordRuleViolations violations, User user, UserSecurityPolicy securityPolicy );
+    void testPassword( PasswordRuleViolations violations, User user );
 }

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRuleViolationException.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRuleViolationException.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRuleViolationException.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/PasswordRuleViolationException.java Wed Aug 30 17:57:33 2006
@@ -23,7 +23,7 @@
  * @version $Id$
  */
 public class PasswordRuleViolationException
-    extends Exception
+    extends RuntimeException
 {
     private static final long serialVersionUID = -4686338829234880328L;
 

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/UserSecurityPolicy.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/UserSecurityPolicy.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/UserSecurityPolicy.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/UserSecurityPolicy.java Wed Aug 30 17:57:33 2006
@@ -16,21 +16,80 @@
  * limitations under the License.
  */
 
+import java.util.List;
+
 /**
  * User Security Policy Settings.  
+ * 
+ * @version $Id$
+ * @todo roll password management into it's own object.
  */
 public interface UserSecurityPolicy
 {
     public static final String ROLE = UserSecurityPolicy.class.getName();
+    
+    // ----------------------------------------------------------------------
+    // Password Management
+    // ----------------------------------------------------------------------
 
-    public int getAllowedLoginAttempts();
+    /**
+     * Gets the password encoder to use.
+     * 
+     * @return the PasswordEncoder implementation to use.
+     */
+    public PasswordEncoder getPasswordEncoder();
+    
+    
+    /**
+     * Add a Specific Rule to the Password Rules List.
+     * 
+     * @param rule the rule to add. 
+     */
+    void addPasswordRule( PasswordRule rule );
+    
+    /**
+     * Get the Password Rules List.
+     * 
+     * @return the list of {@link PasswordRule} objects.
+     */
+    List getPasswordRules();
 
+    /**
+     * Set the Password Rules List.
+     * 
+     * @param rules the list of {@link PasswordRule} objects.
+     */
+    void setPasswordRules( List rules );
+    
+    /**
+     * Gets the count of Previous Passwords that should be tracked.
+     * 
+     * @return the count of previous passwords to track.
+     */
     public int getPreviousPasswordsCount();
+    
+    /**
+     * Sets the count of previous passwords that should be tracked.
+     * 
+     * @param count the count of previous passwords to track.
+     */
+    public void setPreviousPasswordsCount( int count );
+
+    // ----------------------------------------------------------------------
+    // Login Attempt Management
+    // ----------------------------------------------------------------------
+
+    /**
+     * Gets the count of login attempts to allow before locking out a user.
+     * 
+     * @return the number of login attempts to allow before lockout.
+     */
+    public int getAllowedLoginAttempts();
 
     /**
-     * Salt to be used in addiotion to the algorithm when encoding a password
+     * Set the count of login attempts to allow before locking out a user.
      * 
-     * @return the salt
+     * @param count the number of login attempt to allow before lockout.
      */
-    public String getSalt();
+    public void setAllowedLoginAttempts( int count );
 }

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/AbstractJAASPasswordEncoder.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/AbstractJAASPasswordEncoder.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/AbstractJAASPasswordEncoder.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/AbstractJAASPasswordEncoder.java Wed Aug 30 17:57:33 2006
@@ -37,12 +37,18 @@
     implements PasswordEncoder
 {
     private String algorithm;
+    private Object systemSalt;
 
     public AbstractJAASPasswordEncoder( String algorithm )
     {
         this.algorithm = algorithm;
     }
 
+    public void setSystemSalt( Object salt )
+    {
+        this.systemSalt = salt;
+    }
+    
     public String encodePassword( String rawPass, Object salt )
     {
         MessageDigest md = null;
@@ -87,4 +93,15 @@
         String testPass = encodePassword( rawPass, salt );
         return ( encPass.equals( testPass ) );
     }
+
+    public String encodePassword( String rawPass )
+    {
+        return encodePassword( rawPass, this.systemSalt );
+    }
+
+    public boolean isPasswordValid( String encPass, String rawPass )
+    {
+        return isPasswordValid( encPass, rawPass, this.systemSalt );
+    }
+
 }

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserManager.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserManager.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserManager.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserManager.java Wed Aug 30 17:57:33 2006
@@ -54,19 +54,9 @@
     private UserStore userStore;
 
     /**
-     * @plexus.requirement role-hint="sha256"
-     */
-    private PasswordEncoder passwordEncoder;
-
-    /**
      * @plexus.requirement
      */
     private UserSecurityPolicy securityPolicy;
-    
-    /**
-     * The List of {@link PasswordRule} objects.
-     */
-    private List rules;
 
     // ----------------------------------------------------------------------
     // Component Lifecycle
@@ -75,10 +65,7 @@
     public void initialize()
         throws InitializationException
     {
-        rules = new ArrayList();
-
-        // TODO: Find way to have plexus initialize this list with only 1 item.
-        addPasswordRule( new MustHavePasswordRule() );
+        
     }
 
     public boolean login( String username, String rawPassword )
@@ -97,8 +84,7 @@
         // Ensure that user cannot set password during login.
         user.setPassword( null );
         
-        boolean validPassword = this.passwordEncoder.isPasswordValid( user.getEncodedPassword(), rawPassword,
-                                                                      securityPolicy.getSalt() );
+        boolean validPassword = securityPolicy.getPasswordEncoder().isPasswordValid( user.getEncodedPassword(), rawPassword );
         
         if ( validPassword )
         {
@@ -113,15 +99,7 @@
                 user.setLocked( true );
             }
             
-            try
-            {
-                this.updateUser( user );
-            }
-            catch ( PasswordRuleViolationException e )
-            {
-                // not possible here.
-                throw new RuntimeException( e );
-            }
+            this.updateUser( user );
         } 
         
         return validPassword;
@@ -163,20 +141,23 @@
     private void processPasswordChange( User user )
         throws PasswordRuleViolationException
     {
-        if ( user.isGuest() )
+        if(user.isGuest())
         {
             user.setEncodedPassword( null );
-            //TODO we shouldn't allow password changes for guest users, throw exception before getting here
             return;
         }
         
         validatePassword( user );
         
-        // remember the previous password.
+        // set the current encoded password.
+        user.setEncodedPassword( securityPolicy.getPasswordEncoder().encodePassword( user.getPassword() ) );
+        user.setPassword( null );
+        
+        // push new password onto list of previous password.
         List previousPasswords = new ArrayList();
         previousPasswords.add( user.getEncodedPassword() );
         
-        if ( ( user.getPreviousEncodedPasswords() != null ) && !user.getPreviousEncodedPasswords().isEmpty() )
+        if ( !user.getPreviousEncodedPasswords().isEmpty() )
         {
             int oldCount = Math.min( securityPolicy.getPreviousPasswordsCount() - 1, 
                                      user.getPreviousEncodedPasswords().size() );
@@ -184,12 +165,9 @@
             previousPasswords.addAll( sublist );
         }
         user.setPreviousEncodedPasswords( previousPasswords );
-        
-        // set the current encoded password.
-        user.setEncodedPassword( encodePassword( user.getPassword() ) );
-        user.setPassword( null );
 
-        user.setLastPasswordChange( new Date() ); // update timestamp to now.
+        // Update timestamp for password change.
+        user.setLastPasswordChange( new Date() );
     }
 
     private void validatePassword( User user )
@@ -200,11 +178,11 @@
         
         PasswordRuleViolations violations = new PasswordRuleViolations();
 
-        Iterator it = this.rules.iterator();
+        Iterator it = securityPolicy.getPasswordRules().iterator();
         while ( it.hasNext() )
         {
             PasswordRule rule = (PasswordRule) it.next();
-            rule.testPassword( violations, user, securityPolicy );
+            rule.testPassword( violations, user );
         }
 
         if ( violations.hasViolations() )
@@ -290,69 +268,6 @@
     public void removeUserGroup( String userGroupName )
     {
         userStore.removeUserGroup( userGroupName );
-    }
-
-    /**
-     * Set the password encoder to be used for password operations 
-     * 
-     * @param passwordEncoder
-     */
-    public void setPasswordEncoder( PasswordEncoder passwordEncoder )
-    {
-        this.passwordEncoder = passwordEncoder;
-    }
-
-    /**
-     * Get the password encoder to be used for password operations
-     * 
-     * @return the encoder
-     */
-    public PasswordEncoder getPasswordEncoder()
-    {
-        return passwordEncoder;
-    }
-
-    /**
-     * Encode arbitrary password using configured encoder and salt.
-     * 
-     * @param rawpassword the raw password to encode.
-     * @return the encoded form of the password.
-     */
-    public String encodePassword( String rawpassword )
-    {
-        return this.passwordEncoder.encodePassword( rawpassword, securityPolicy.getSalt() );
-    }
-
-    /**
-     * Add a Specific Rule to the Password Rules List.
-     * 
-     * @param rule the rule to add. 
-     */
-    public void addPasswordRule( PasswordRule rule )
-    {
-        // TODO: check for duplicates? if so, check should only be based on Rule class name.
-
-        this.rules.add( rule );
-    }
-
-    /**
-     * Get the Password Rules List.
-     * 
-     * @return the list of {@link PasswordRule} objects.
-     */
-    public List getPasswordRules()
-    {
-        return this.rules;
-    }
-
-    /**
-     * Set the Password Rules List.
-     * 
-     * @param rules the list of {@link PasswordRule} objects.
-     */
-    public void setPasswordRules( List rules )
-    {
-        this.rules = rules;
     }
 
     public void updateUser( User user )

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserSecurityPolicy.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserSecurityPolicy.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserSecurityPolicy.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/DefaultUserSecurityPolicy.java Wed Aug 30 17:57:33 2006
@@ -16,7 +16,16 @@
  * limitations under the License.
  */
 
+import org.apache.maven.user.model.PasswordEncoder;
+import org.apache.maven.user.model.PasswordRule;
 import org.apache.maven.user.model.UserSecurityPolicy;
+import org.apache.maven.user.model.rules.MustHavePasswordRule;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
 /**
  * User Security Policy. 
@@ -27,7 +36,7 @@
  * @version $Id$
  */
 public class DefaultUserSecurityPolicy
-    implements UserSecurityPolicy
+    implements UserSecurityPolicy, Initializable
 {
     /**
      * @plexus.configuration default-value="3"
@@ -38,11 +47,21 @@
      * @plexus.configuration default-value="6"
      */
     private int previousPasswordsCount;
+    
+    /**
+     * @plexus.requirement role-hint="sha256"
+     */
+    private PasswordEncoder passwordEncoder;
 
     /**
      * @plexus.configuration default-value="Step doog ekam Skravdraa"
      */
-    private String salt;
+    private String systemSalt;
+    
+    /**
+     * The List of {@link PasswordRule} objects.
+     */
+    private List rules;
 
     public int getAllowedLoginAttempts()
     {
@@ -54,23 +73,92 @@
         return previousPasswordsCount;
     }
 
+    /**
+     * Set the count of login attempts to allow before locking out a user.
+     * 
+     * @param allowedLoginAttempts the number of login attempt to allow before lockout.
+     */
     public void setAllowedLoginAttempts( int allowedLoginAttempts )
     {
         this.allowedLoginAttempts = allowedLoginAttempts;
     }
 
+    /**
+     * Sets the count of previous passwords that should be tracked.
+     * 
+     * @param previousPasswordsCount the count of previous passwords to track.
+     */
     public void setPreviousPasswordsCount( int previousPasswordsCount )
     {
         this.previousPasswordsCount = previousPasswordsCount;
     }
 
-    public void setSalt( String salt )
+    /**
+     * Get the password encoder to be used for password operations
+     * 
+     * @return the encoder
+     */
+    public PasswordEncoder getPasswordEncoder()
+    {
+        return passwordEncoder;
+    }
+
+    /**
+     * Add a Specific Rule to the Password Rules List.
+     * 
+     * @param rule the rule to add. 
+     */
+    public void addPasswordRule( PasswordRule rule )
     {
-        this.salt = salt;
+        // TODO: check for duplicates? if so, check should only be based on Rule class name.
+        
+        rule.setUserSecurityPolicy( this );
+        this.rules.add( rule );
     }
 
-    public String getSalt()
+    /**
+     * Get the Password Rules List.
+     * 
+     * @return the list of {@link PasswordRule} objects.
+     */
+    public List getPasswordRules()
     {
-        return salt;
+        return this.rules;
+    }
+
+    /**
+     * Set the Password Rules List.
+     * 
+     * @param newRules the list of {@link PasswordRule} objects.
+     */
+    public void setPasswordRules( List newRules )
+    {
+        this.rules.clear();
+        
+        if ( newRules == null )
+        {
+            return;
+        }
+        
+        // Intentionally iterating to ensure policy settings in provided rules.
+        
+        Iterator it = newRules.iterator();
+        while ( it.hasNext() )
+        {
+            PasswordRule rule = (PasswordRule) it.next();
+            rule.setUserSecurityPolicy( this );
+            this.rules.add( rule );
+        }
+    }
+
+    public void initialize()
+        throws InitializationException
+    {
+        rules = new ArrayList();
+
+        // TODO: Find way to have plexus initialize this list with only 1 item.
+        addPasswordRule( new MustHavePasswordRule() );
+        
+        getPasswordEncoder().setSystemSalt( systemSalt );
     }
 }

Added: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/PlainTextPasswordEncoder.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/PlainTextPasswordEncoder.java?rev=438734&view=auto
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/PlainTextPasswordEncoder.java (added)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/PlainTextPasswordEncoder.java Wed Aug 30 17:57:33 2006
@@ -0,0 +1,61 @@
+package org.apache.maven.user.model.impl;
+
+/*
+ * Copyright 2001-2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.maven.user.model.PasswordEncoder;
+
+/**
+ * PlainText PasswordEncoder for use in situtations where the password needs to be saved as-is.
+ * See {@link PasswordEncoder#encodePassword(String)} for details. 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class PlainTextPasswordEncoder
+    implements PasswordEncoder
+{
+
+    public String encodePassword( String rawPass )
+    {
+        return rawPass;
+    }
+
+    public String encodePassword( String rawPass, Object salt )
+    {
+        return rawPass;
+    }
+
+    public boolean isPasswordValid( String encPass, String rawPass )
+    {
+        if ( encPass == null && rawPass != null )
+        {
+            return false;
+        }
+
+        return encPass.equals( rawPass );
+    }
+
+    public boolean isPasswordValid( String encPass, String rawPass, Object salt )
+    {
+        return isPasswordValid( encPass, rawPass );
+    }
+
+    public void setSystemSalt( Object salt )
+    {
+        // Ignore, not used.
+    }
+}

Propchange: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/PlainTextPasswordEncoder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/impl/PlainTextPasswordEncoder.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/AlphaPasswordRule.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/AlphaPasswordRule.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/AlphaPasswordRule.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/AlphaPasswordRule.java Wed Aug 30 17:57:33 2006
@@ -41,24 +41,6 @@
         minimumCount = 1;
     }
 
-    public int getMinimumCount()
-    {
-        return minimumCount;
-    }
-
-    public void setMinimumCount( int minimumCount )
-    {
-        this.minimumCount = minimumCount;
-    }
-
-    public void testPassword( PasswordRuleViolations violations, User user, UserSecurityPolicy securityPolicy )
-    {
-        if ( countAlphaCharacters( user.getPassword() ) < this.minimumCount )
-        {
-            violations.addViolation( "user.password.violation.alpha", new Object[] { new Integer( minimumCount ) } ); //$NON-NLS-1$
-        }
-    }
-
     private int countAlphaCharacters( String password )
     {
         int count = 0;
@@ -68,11 +50,24 @@
             return count;
         }
 
-        // Doing this via iteration of code points to take in account localized passwords.
+        /* TODO: Eventually upgrade to the JDK 1.5 Technique
+         * 
+         * // Doing this via iteration of code points to take in account localized passwords.
+         * for ( int i = 0; i < password.length(); i++ )
+         * {
+         *     int codepoint = password.codePointAt( i );
+         *     if ( Character.isLetter( codepoint ) )
+         *     {
+         *        count++;
+         *     }
+         * }
+         */
+
+        // JDK 1.4 Technique - NOT LOCALIZED.
         for ( int i = 0; i < password.length(); i++ )
         {
-            int codepoint = password.codePointAt( i );
-            if ( Character.isLetter( codepoint ) )
+            char c = password.charAt( i );
+            if ( Character.isLetter( c ) )
             {
                 count++;
             }
@@ -81,4 +76,26 @@
         return count;
     }
 
+    public int getMinimumCount()
+    {
+        return minimumCount;
+    }
+
+    public void setMinimumCount( int minimumCount )
+    {
+        this.minimumCount = minimumCount;
+    }
+
+    public void setUserSecurityPolicy( UserSecurityPolicy policy )
+    {
+        // Ignore, policy not needed in this rule.
+    }
+
+    public void testPassword( PasswordRuleViolations violations, User user )
+    {
+        if ( countAlphaCharacters( user.getPassword() ) < this.minimumCount )
+        {
+            violations.addViolation( "user.password.violation.alpha", new Object[] { new Integer( minimumCount ) } ); //$NON-NLS-1$
+        }
+    }
 }

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/CharacterLengthPasswordRule.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/CharacterLengthPasswordRule.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/CharacterLengthPasswordRule.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/CharacterLengthPasswordRule.java Wed Aug 30 17:57:33 2006
@@ -63,7 +63,12 @@
         this.minimumCharacters = minimumCharacters;
     }
 
-    public void testPassword( PasswordRuleViolations violations, User user, UserSecurityPolicy securityPolicy )
+    public void setUserSecurityPolicy( UserSecurityPolicy policy )
+    {
+        // Ignore, policy not needed in this rule.
+    }
+
+    public void testPassword( PasswordRuleViolations violations, User user )
     {
         if(minimumCharacters > maximumCharacters)
         {

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/MustHavePasswordRule.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/MustHavePasswordRule.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/MustHavePasswordRule.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/MustHavePasswordRule.java Wed Aug 30 17:57:33 2006
@@ -33,12 +33,17 @@
 public class MustHavePasswordRule
     implements PasswordRule
 {
-    public void testPassword( PasswordRuleViolations violations, User user, UserSecurityPolicy securityPolicy )
+    public void setUserSecurityPolicy( UserSecurityPolicy policy )
+    {
+        // Ignore, policy not needed in this rule.
+    }
+
+    public void testPassword( PasswordRuleViolations violations, User user )
     {
         if ( StringUtils.isEmpty( user.getPassword() ) )
         {
             violations.addViolation( "user.password.violation.missing" ); //$NON-NLS-1$
         }
     }
-
 }
+

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/NumericalPasswordRule.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/NumericalPasswordRule.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/NumericalPasswordRule.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/NumericalPasswordRule.java Wed Aug 30 17:57:33 2006
@@ -32,33 +32,15 @@
  * @version $Id$
  */
 public class NumericalPasswordRule
-    implements PasswordRule
+implements PasswordRule
 {
     private int minimumCount;
-
+    
     public NumericalPasswordRule()
     {
         this.minimumCount = 1;
     }
 
-    public int getMinimumCount()
-    {
-        return minimumCount;
-    }
-
-    public void setMinimumCount( int minimumCount )
-    {
-        this.minimumCount = minimumCount;
-    }
-
-    public void testPassword( PasswordRuleViolations violations, User user, UserSecurityPolicy securityPolicy )
-    {
-        if ( countDigitCharacters( user.getPassword() ) < this.minimumCount )
-        {
-            violations.addViolation( "user.password.violation.digit", new Object[] { new Integer( minimumCount ) } ); //$NON-NLS-1$
-        }
-    }
-
     private int countDigitCharacters( String password )
     {
         int count = 0;
@@ -68,11 +50,24 @@
             return count;
         }
 
-        // Doing this via iteration of code points to take in account localized passwords.
+        /* TODO: Eventually upgrade to the JDK 1.5 Technique
+         * 
+         * // Doing this via iteration of code points to take in account localized numbers.
+         * for ( int i = 0; i < password.length(); i++ )
+         * {
+         *     int codepoint = password.codePointAt( i );
+         *     if ( Character.isDigit( codepoint ) )
+         *     {
+         *         count++;
+         *     }
+         * }
+         */
+        
+        // JDK 1.4 Technique - NOT LOCALIZED.
         for ( int i = 0; i < password.length(); i++ )
         {
-            int codepoint = password.codePointAt( i );
-            if ( Character.isDigit( codepoint ) )
+            char c = password.charAt( i );
+            if ( Character.isDigit( c ) )
             {
                 count++;
             }
@@ -81,4 +76,26 @@
         return count;
     }
 
+    public int getMinimumCount()
+    {
+        return minimumCount;
+    }
+
+    public void setMinimumCount( int minimumCount )
+    {
+        this.minimumCount = minimumCount;
+    }
+
+    public void setUserSecurityPolicy( UserSecurityPolicy policy )
+    {
+        // Ignore, policy not needed in this rule.
+    }
+    
+    public void testPassword( PasswordRuleViolations violations, User user )
+    {
+        if ( countDigitCharacters( user.getPassword() ) < this.minimumCount )
+        {
+            violations.addViolation( "user.password.violation.digit", new Object[] { new Integer( minimumCount ) } ); //$NON-NLS-1$
+        }
+    }
 }

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/ReusePasswordRule.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/ReusePasswordRule.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/ReusePasswordRule.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/java/org/apache/maven/user/model/rules/ReusePasswordRule.java Wed Aug 30 17:57:33 2006
@@ -16,15 +16,14 @@
  * limitations under the License.
  */
 
-import java.util.Iterator;
-
-import org.apache.maven.user.model.PasswordEncoder;
 import org.apache.maven.user.model.PasswordRule;
 import org.apache.maven.user.model.PasswordRuleViolations;
 import org.apache.maven.user.model.User;
 import org.apache.maven.user.model.UserSecurityPolicy;
 import org.codehaus.plexus.util.StringUtils;
 
+import java.util.Iterator;
+
 /**
  * Password Rule, Checks supplied password found at {@link User#getPassword()} against 
  * the {@link User#getPreviousEncodedPasswords()} to ensure that a password is not reused.  
@@ -37,41 +36,37 @@
 public class ReusePasswordRule
     implements PasswordRule
 {
-    /**
-     * @plexus.requirement
-     */
-    private PasswordEncoder passwordEncoder;
-    
-    private int previousPasswordCount;
-
-    /**
-     * Create a rule that will check last 3 passwords
-     */
+    private UserSecurityPolicy securityPolicy;
+
     public ReusePasswordRule()
     {
-        this.previousPasswordCount = 3;
     }
 
-    public int getPreviousPasswordCount()
+    public void setUserSecurityPolicy( UserSecurityPolicy policy )
     {
-        return previousPasswordCount;
+        this.securityPolicy = policy;
     }
 
-    public void setPreviousPasswordCount( int previousPasswordCount )
+    public int getPreviousPasswordCount()
     {
-        this.previousPasswordCount = previousPasswordCount;
+        return securityPolicy.getPreviousPasswordsCount();
     }
 
-    private boolean hasReusedPassword( User user, String password, String salt )
+    private boolean hasReusedPassword( User user, String password )
     {
+        if ( this.securityPolicy == null )
+        {
+            throw new IllegalStateException( "The security policy has not yet been set." );
+        }
+
         if ( StringUtils.isEmpty( password ) )
         {
             return false;
         }
 
-        String encodedPassword = passwordEncoder.encodePassword( password, salt );
+        String encodedPassword = securityPolicy.getPasswordEncoder().encodePassword( password );
 
-        int checkCount = previousPasswordCount;
+        int checkCount = getPreviousPasswordCount();
 
         Iterator it = user.getPreviousEncodedPasswords().iterator();
 
@@ -88,15 +83,19 @@
         return false;
     }
 
-    public void testPassword( PasswordRuleViolations violations, User user, UserSecurityPolicy securityPolicy )
+    public void setPreviousPasswordCount( int previousPasswordCount )
+    {
+        securityPolicy.setPreviousPasswordsCount( previousPasswordCount );
+    }
+
+    public void testPassword( PasswordRuleViolations violations, User user )
     {
         String password = user.getPassword();
 
-        if ( hasReusedPassword( user, password, securityPolicy.getSalt() ) )
+        if ( hasReusedPassword( user, password ) )
         {
-            violations
-                .addViolation( "user.password.violation.reuse", new Object[] { new Integer( previousPasswordCount ) } ); //$NON-NLS-1$
+            violations.addViolation( "user.password.violation.reuse", new Object[] { 
+                new Integer( getPreviousPasswordCount() ) } ); //$NON-NLS-1$
         }
     }
-
 }

Modified: maven/shared/trunk/maven-user/maven-user-model/src/main/mdo/user.xml
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/main/mdo/user.xml?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/main/mdo/user.xml (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/main/mdo/user.xml Wed Aug 30 17:57:33 2006
@@ -144,9 +144,15 @@
         <codeSegment>
           <version>1.0.0+</version>
           <code><![CDATA[
+              public User()
+              {
+                 // Intentionally initialize List to avoid JPOX NullPointerException Issues.
+              	 previousEncodedPasswords = new java.util.ArrayList();
+              }
+          
               public int incrementFailedLoginAttempts() 
               {
-                 return failedLoginAttempts++;
+                 return ++failedLoginAttempts;
               }
           ]]></code>
         </codeSegment>

Modified: maven/shared/trunk/maven-user/maven-user-model/src/test/java/org/apache/maven/user/model/impl/DefaultUserManagerTest.java
URL: http://svn.apache.org/viewvc/maven/shared/trunk/maven-user/maven-user-model/src/test/java/org/apache/maven/user/model/impl/DefaultUserManagerTest.java?rev=438734&r1=438733&r2=438734&view=diff
==============================================================================
--- maven/shared/trunk/maven-user/maven-user-model/src/test/java/org/apache/maven/user/model/impl/DefaultUserManagerTest.java (original)
+++ maven/shared/trunk/maven-user/maven-user-model/src/test/java/org/apache/maven/user/model/impl/DefaultUserManagerTest.java Wed Aug 30 17:57:33 2006
@@ -165,11 +165,11 @@
         User fetched = getUserManager().getUser( "jgarner" ); //$NON-NLS-1$
         assertNotNull( "User should not be null.", fetched ); //$NON-NLS-1$
         assertEquals( "James Garner", fetched.getFullName() ); //$NON-NLS-1$
-        
+
         // Change the full name, and update the user.
         fetched.setFullName( "Flight Lt. Hendley" ); //$NON-NLS-1$
         getUserManager().updateUser( fetched );
-        
+
         // Should not change number of users being tracked.
         assertEquals( 1, getUserManager().getUsers().size() );
 
@@ -472,32 +472,37 @@
         assertEquals( 2, actual.getPermissions().size() );
     }
 
-    public void testPolicyLoginFailureLock() throws Exception
+    public void testPolicyLoginFailureLock()
+        throws Exception
     {
         assertNotNull( getUserManager() );
-        
+
         assertEquals( "New UserManager should contain no users.", 0, getUserManager().getUsers().size() ); //$NON-NLS-1$
         assertEquals( "New UserManager should contain no groups.", 0, getUserManager().getUserGroups().size() ); //$NON-NLS-1$
         assertNotNull( "New UserManager should have a Security Policy", getUserManager().getSecurityPolicy() ); //$NON-NLS-1$
-        
+
         User rattenborough = new User();
         rattenborough.setUsername( "rattenborough" ); //$NON-NLS-1$
         rattenborough.setFullName( "Richard Attenborough" ); //$NON-NLS-1$
         rattenborough.setPassword( "the big x" ); //$NON-NLS-1$
 
         getUserManager().addUser( rattenborough );
-        
+
         assertEquals( 1, getUserManager().getUsers().size() );
-        
+
         // Setup the policy.
         ( (DefaultUserSecurityPolicy) getUserManager().getSecurityPolicy() ).setAllowedLoginAttempts( 3 );
-        
+
         assertFalse( getUserManager().login( "rattenborough", "the big lebowski" ) );
         assertFalse( getUserManager().getUser( "rattenborough" ).isLocked() );
-        
+
+        assertEquals( 1, getUserManager().getUsers().size() );
+
         assertFalse( getUserManager().login( "rattenborough", "the big cheese" ) );
         assertFalse( getUserManager().getUser( "rattenborough" ).isLocked() );
-        
+
+        assertEquals( 1, getUserManager().getUsers().size() );
+
         assertFalse( getUserManager().login( "rattenborough", "big x" ) );
         assertTrue( getUserManager().getUser( "rattenborough" ).isLocked() );
     }