Index: account-validator-tool/src/validation.properties
===================================================================
--- account-validator-tool/src/validation.properties	(revision 0)
+++ account-validator-tool/src/validation.properties	(working copy)
@@ -0,0 +1 @@
+
Index: account-validator-tool/src/bundle/org/sakaiproject/accountvalidator/bundle/messages.properties
===================================================================
--- account-validator-tool/src/bundle/org/sakaiproject/accountvalidator/bundle/messages.properties	(revision 123370)
+++ account-validator-tool/src/bundle/org/sakaiproject/accountvalidator/bundle/messages.properties	(working copy)
@@ -6,6 +6,7 @@
 
 validate.invalidPassword=Password is incorrect
 validate.passNotMatch=Passwords don't match
+validate.tooWeak=Password does not meet requirements; must be long, complex, and significantly different than your username
 validate.acceptTerms=You must accept the terms and conditions.
 validate.welcome1=Welcome to {0}!
 validate.welcome1.reset=Reset your password on {0}
Index: account-validator-tool/src/ESAPI.properties
===================================================================
--- account-validator-tool/src/ESAPI.properties	(revision 0)
+++ account-validator-tool/src/ESAPI.properties	(working copy)
@@ -0,0 +1,24 @@
+# #############################################################################
+# bbailla2:
+# This file is required for ESAPI's password validation. These properties 
+# prevent some unnecessary logging to std out
+# #############################################################################
+
+# Logging
+ApplicationName=account-validator
+
+ESAPI.Logger=org.owasp.esapi.reference.JavaLogFactory
+ESAPI.LogLevel=OFF
+
+Validator.ConfigurationFile=./validation.properties
+ESAPI.printProperties=false
+Encryptor.CipherTransformation=AES/CBC/PKCS5Padding
+Logger.LogApplicationName=true
+Logger.LogServerIP=true
+Logger.ApplicationName=account-validator
+ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
+Logger.LogEncodingRequired=false
+ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
+HttpUtilities.MaxUploadFileBytes=0
+ESAPI.Authenticator=org.owasp.esapi.reference.FileBasedAuthenticator
+

Property changes on: account-validator-tool/src/ESAPI.properties
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: account-validator-tool/src/java/org/sakaiproject/accountvalidator/tool/otp/AcountValidationLocator.java
===================================================================
--- account-validator-tool/src/java/org/sakaiproject/accountvalidator/tool/otp/AcountValidationLocator.java	(revision 123370)
+++ account-validator-tool/src/java/org/sakaiproject/accountvalidator/tool/otp/AcountValidationLocator.java	(working copy)
@@ -31,6 +31,7 @@
 import org.joda.time.DateTime;
 import org.joda.time.format.DateTimeFormatter;
 import org.joda.time.format.ISODateTimeFormat;
+import org.owasp.esapi.reference.FileBasedAuthenticator;
 import org.sakaiproject.accountvalidator.logic.ValidationLogic;
 import org.sakaiproject.accountvalidator.model.ValidationAccount;
 import org.sakaiproject.authz.api.SecurityAdvisor;
@@ -225,6 +226,30 @@
 						tml.addMessage(new TargettedMessage("validate.passNotMatch", new Object[]{}, TargettedMessage.SEVERITY_ERROR));
 						return "error!";
 					}
+
+					if (serverConfigurationService.getBoolean("account-validator.validate.passwords", false))
+					{
+						//Prepare to use the verifyPasswordStrength method from esapi
+						FileBasedAuthenticator auth = (FileBasedAuthenticator) FileBasedAuthenticator.getInstance();
+
+						//Create an esapi user object whose username is our user's eid (this way esapi will compare the password with the eid)
+						SimpleUser esapiUser = new SimpleUser(u.getEid());
+
+						try
+						{
+							//first parameter is the old password, but we don't know it (nor should we)
+							//second parameter is the new password
+							//third parameter is the esapi user we created so that we can compare the new password with the eid
+							auth.verifyPasswordStrength(null, item.getPassword(), esapiUser);
+						}
+						catch (org.owasp.esapi.errors.AuthenticationException e)
+						{
+							userDirectoryService.cancelEdit(u);
+							tml.addMessage(new TargettedMessage("validate.tooWeak", new Object[]{}, TargettedMessage.SEVERITY_ERROR));
+							return "error!";
+						}
+					}
+
 					u.setPassword(item.getPassword());
 					
 					// Do they have to accept terms and conditions.
Index: account-validator-tool/src/java/org/sakaiproject/accountvalidator/tool/otp/SimpleUser.java
===================================================================
--- account-validator-tool/src/java/org/sakaiproject/accountvalidator/tool/otp/SimpleUser.java	(revision 0)
+++ account-validator-tool/src/java/org/sakaiproject/accountvalidator/tool/otp/SimpleUser.java	(working copy)
@@ -0,0 +1,367 @@
+package org.sakaiproject.accountvalidator.tool.otp;
+
+import java.io.Serializable;
+import java.security.Principal;
+import java.util.*;
+import javax.servlet.http.HttpSession;
+
+import org.owasp.esapi.Encoder;
+import org.owasp.esapi.errors.AuthenticationException;
+import org.owasp.esapi.errors.AuthenticationHostException;
+import org.owasp.esapi.errors.EncryptionException;
+import org.owasp.esapi.ESAPI;
+import org.owasp.esapi.User;
+
+
+/**
+ * @author bbailla2
+ * We needed an esapi User object to use the password strength algorithm, but the api doesn't provide a dummy implementation, so I created this
+ **/
+public class SimpleUser implements User 
+{
+	private static String accountName;
+	
+	private static final long serialVersionUID = -1850916950784965503L;
+
+	private String csrfToken = "";
+	private Set sessions = new HashSet();
+	private Locale locale = null;
+	
+	public SimpleUser(String accountName)
+	{
+		this.accountName=accountName;
+	}
+    
+	/**
+	* {@inheritDoc}
+	*/
+	public void addRole(String role) throws AuthenticationException {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void addRoles(Set newRoles) throws AuthenticationException {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void changePassword(String oldPassword, String newPassword1,
+	    String newPassword2) throws AuthenticationException,
+	    EncryptionException {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void disable() {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void enable() {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public long getAccountId() {
+	    return 0;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public String getAccountName() {
+	    return accountName;
+	}
+	
+	    /**
+	     * Alias method that is equivalent to getAccountName()
+	     * 
+	     * @return the name of the current user's account
+	*/
+	public String getName() {
+	    return getAccountName();
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public String getCSRFToken() {
+	    return csrfToken;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public Date getExpirationTime() {
+	    return null;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public int getFailedLoginCount() {
+	    return 0;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public Date getLastFailedLoginTime() throws AuthenticationException {
+	    return null;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public String getLastHostAddress() {
+	    return "unknown";
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public Date getLastLoginTime() {
+	    return null;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public Date getLastPasswordChangeTime() {
+	    return null;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public Set<String> getRoles() {
+	    return new HashSet<String>();
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public String getScreenName() {
+	    return "Anonymous";
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void addSession(HttpSession s)  {
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void removeSession(HttpSession s)  {
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public Set getSessions()  {
+	return sessions;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void incrementFailedLoginCount() {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public boolean isAnonymous() {
+	    return true;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public boolean isEnabled() {
+	    return false;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public boolean isExpired() {
+	    return false;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public boolean isInRole(String role) {
+	    return false;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public boolean isLocked() {
+	    return false;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public boolean isLoggedIn() {
+	    return false;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public boolean isSessionAbsoluteTimeout() {
+	    return false;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public boolean isSessionTimeout() {
+	    return false;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void lock() {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void loginWithPassword(String password)
+	    throws AuthenticationException {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void logout() {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void removeRole(String role) throws AuthenticationException {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public String resetCSRFToken() throws AuthenticationException {
+	    csrfToken = ESAPI.randomizer().getRandomString(8, Encoder.CHAR_ALPHANUMERICS);
+	    return csrfToken;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void setAccountName(String accountName) {
+	    this.accountName = accountName;
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void setExpirationTime(Date expirationTime) {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void setRoles(Set roles) throws AuthenticationException {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void setScreenName(String screenName) {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void unlock() {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public boolean verifyPassword(String password) throws EncryptionException {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void setLastFailedLoginTime(Date lastFailedLoginTime) {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void setLastLoginTime(Date lastLoginTime) {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	* {@inheritDoc}
+	*/
+	public void setLastHostAddress(String remoteHost) {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	    
+	/**
+	* {@inheritDoc}
+	*/
+	public void setLastPasswordChangeTime(Date lastPasswordChangeTime) {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	
+	/**
+	*  {@inheritDoc}
+	*/
+	public HashMap getEventMap() {
+	    throw new RuntimeException("Invalid operation for the anonymous user");
+	}
+	/**
+	* @return the locale
+	*/
+	public Locale getLocale() {
+	    return locale;
+	}
+	
+	/**
+	* @param locale the locale to set
+	*/
+	public void setLocale(Locale locale) {
+	    this.locale = locale;
+	}
+
+}
Index: account-validator-tool/pom.xml
===================================================================
--- account-validator-tool/pom.xml	(revision 123370)
+++ account-validator-tool/pom.xml	(working copy)
@@ -101,6 +101,11 @@
 			<artifactId>joda-time</artifactId>
 			<version>1.6.2</version>
 		</dependency>
+		<dependency>
+			<groupId>org.owasp.esapi</groupId>
+			<artifactId>esapi</artifactId>
+			<version>2.0.1</version>
+		</dependency>
    </dependencies>
 
    
@@ -133,6 +138,12 @@
           <include>**/*.*</include>
         </includes>
       </resource>
+      <resource>
+        <directory>${basedir}/src</directory>
+        <includes>
+          <include>**/*.properties</include>
+        </includes>
+      </resource>
     </resources>
 	</build>
 
