Skip to content

Commit

Permalink
https://github.com/rreganjr/Requel/issues/2
Browse files Browse the repository at this point in the history
In UserImpl the password encryption algorithm is now a property so that it can be updated periodically and automatically when a user resets a password or logs in to the system and the current algorithm used isn't the preferred algorithm. The preferred algorithm is defined as a static final property on the UserImpl class versus being configurable so that it can't be accidentally configured with an insecure algorithm. The intent is that new version will update the UserImpl class with security improvements and when deployed users' passwords will be re-encrypted as they use the system. The preferred algorithm is set to PBKDF2WITHHMACSHA512, which is a private key password encoder that supports an iteration count. The iteration count is also a property and the preferred value is set to 50,000 iterations. PBKDF2 is the minimum recommended by OWASP, but also the only recommended algorithm built-in to Java.

There is now also a password salt property generated using a SecureRandom SHA1PRNG it is reset when upgrading the encryption or resetting the password.

There is now password validation. A password must be between 1 and 128 characters long and can't be only whitespace.

There is now a UserImplTest that covers all the new password changes plus most of the original UserImpl methods.

Signed-off-by: rreganjr <[email protected]>
  • Loading branch information
rreganjr committed Feb 16, 2018
1 parent 2c2e7d0 commit c912bcd
Show file tree
Hide file tree
Showing 11 changed files with 740 additions and 239 deletions.
8 changes: 0 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@
<target>1.8</target>
</configuration>
</plugin>
<!-- for after move to git
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.4</version>
</plugin>
-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
Expand Down Expand Up @@ -319,6 +312,5 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>

</dependencies>
</project>
16 changes: 12 additions & 4 deletions src/main/java/com/rreganjr/ApplicationException.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ public class ApplicationException extends RuntimeException {
protected static String MSG_NO_RESOURCE_BUNDLE = "No resource bundle was supplied.";

/**
* @param name -
* the name used to find a project that doesn't exist
* @return
* @return ApplicationException with message {@link #MSG_NOT_IMPLEMENTED}
*/
public static ApplicationException notImplemented() {
return new ApplicationException(MSG_NOT_IMPLEMENTED);
Expand Down Expand Up @@ -158,5 +156,15 @@ static private String pretty(Object o) {
} else {
return o.toString();
}
}
}

@Override
public int hashCode() {
return toString().hashCode();
}

@Override
public boolean equals(Object obj) {
return this == obj || (getClass().equals(obj.getClass()) && this.toString().equals(obj.toString()));
}
}
93 changes: 0 additions & 93 deletions src/main/java/com/rreganjr/HashUtils.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
*/
package com.rreganjr.requel;

import com.rreganjr.requel.user.User;
import com.rreganjr.requel.user.exception.NoSuchUserException;
import org.hibernate.validator.InvalidStateException;
import org.hibernate.validator.InvalidValue;

Expand All @@ -34,6 +36,12 @@ public class EntityValidationException extends EntityException {

protected static String MSG_VALIDATION_FAILED = "validation failed: %s";
protected static String MSG_EMPTY_VALUE = "%s cannot be empty.";
protected static String MSG_PASSWORD_AND_REPASSWORD_DONT_MATCH = "The password fields don't match.";


public static EntityValidationException passwordAndRePasswordDontMatch(Class<?> entityType) {
return validationFailed(entityType, "password", MSG_PASSWORD_AND_REPASSWORD_DONT_MATCH);
}

/**
* Create an EntityException for an empty property that is required.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,6 @@ public void setEntity(ProjectOrDomainEntity entity) throws IllegalArgumentExcept
* UpdatedEntityNotifier that the entity has been updated.<br>
* NOTE: sub classes should call super.analyze() and not analyzeName()
* directly so that the UpdatedEntityNotifier is called.
*
* @param entity
*/
public void analyze() {
// remove any lexical annotations that apply to all the properties
Expand Down
35 changes: 35 additions & 0 deletions src/main/java/com/rreganjr/requel/user/PasswordException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.rreganjr.requel.user;

import com.rreganjr.requel.RequelException;

public class PasswordException extends RequelException {

public static final String MSG_PROBLEM_ENCRYPTING_PASSWORD = "There was a problem encrypting the user's password.";
public static final String MSG_PROBLEM_ENCRYPTING_PASSWORD_WITH_MESSAGE = "There was a problem encrypting the user's password: %s";
public static final String MSG_PROBLEM_GENERATING_PASSWORD_SALT = "There was a problem generating the password salt value.";
public static final String MSG_BAD_ALGORITHM_NAME = "The supplied algorithm name '%s' is not a supported SecretKeyFactory or MessageDigest algorithm name.";

public static PasswordException problemEncryptingPassword(Exception e) {
return new PasswordException(e, MSG_PROBLEM_ENCRYPTING_PASSWORD);
}

public static PasswordException problemEncryptingPassword(String message) {
return new PasswordException(MSG_PROBLEM_ENCRYPTING_PASSWORD_WITH_MESSAGE, message);
}

public static PasswordException badAlgorithmName(String badAlgorithmName) {
return new PasswordException(MSG_BAD_ALGORITHM_NAME, badAlgorithmName);
}

public static PasswordException problemGeneratingPasswordSalt(Exception e) {
return new PasswordException(e, MSG_PROBLEM_GENERATING_PASSWORD_SALT);
}

protected PasswordException(String format, Object... args) {
super(format, args);
}

protected PasswordException(Throwable cause, String format, Object... args) {
super(cause, format, args);
}
}
29 changes: 12 additions & 17 deletions src/main/java/com/rreganjr/requel/user/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
import java.util.Comparator;
import java.util.Set;

import javax.xml.bind.ValidationException;

import com.rreganjr.requel.EntityValidationException;
import com.rreganjr.requel.OrganizedEntity;
import com.rreganjr.requel.user.exception.NoSuchRoleForUserException;

Expand Down Expand Up @@ -82,11 +81,11 @@ public interface User extends Comparable<User>, OrganizedEntity {
*
* @param password -
* the user's new password as plain text.
* @throws ValidationException
* @throws EntityValidationException
* if the supplied string doesn't meet the password criteria
* TODO: what is the password criteria?
*/
public void resetPassword(String password);
public void resetPassword(String password) throws EntityValidationException;

/**
* Return true if the supplied plain text password matches the user's
Expand All @@ -113,8 +112,6 @@ public interface User extends Comparable<User>, OrganizedEntity {
*
* @param emailAddress -
* the email address to assign
* @throws ValidationException
* if the emailAddress is ill-formed
*/
public void setEmailAddress(String emailAddress);

Expand All @@ -132,20 +129,18 @@ public interface User extends Comparable<User>, OrganizedEntity {
*
* @param phoneNumber -
* the phone number to assign
* @throws ValidationException
* if the phone number is ill-formed
*/
public void setPhoneNumber(String phoneNumber);

/**
* The system administrator can create accounts intended to be shared by
* multiple users conceivably for reading the projects status. The
* administrator can lock these accounts so they can not be edited by the
* user.
*
* @return true if the account is editable by the user, false if the account
* can only be edited by the administrator
*/
/**
* The system administrator can create accounts intended to be shared by
* multiple users conceivably for reading the projects status. The
* administrator can lock these accounts so they can not be edited by the
* user.
*
* @return true if the account is editable by the user, false if the account
* can only be edited by the administrator
*/
public boolean isEditable();

/**
Expand Down
Loading

0 comments on commit c912bcd

Please sign in to comment.