Class FileBasedAuthenticator
- java.lang.Object
-
- org.owasp.esapi.reference.AbstractAuthenticator
-
- org.owasp.esapi.reference.FileBasedAuthenticator
-
- All Implemented Interfaces:
Authenticator
public class FileBasedAuthenticator extends AbstractAuthenticator
Reference implementation of the Authenticator interface. This reference implementation is intended to be an EXAMPLE only and is not really suitable for enterprise-wide applications. It is backed by a simple unsorted text file that contains serialized information about users and it uses a relative weak password hashing algorithm. (For further details, see the "See Also" section, below.)Many organizations will want to create their own implementation of the methods provided in the
Authenticator
interface backed by their own user repository as this reference implementation is not very scalable. This reference implementation captures information about users in a simple text file format that contains user information separated by the pipe "|" character.Here's an example of a single line from the users.txt file:
account id | account name | hashed password | roles | lockout | status | old password hashes | last hostname | last change | last login | last failed | expiration | failed --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1203123710837 | mitch | 44k/NAzQUlrCq9musTGGkcMNmdzEGJ8w8qZTLzpxLuQ= | admin,user | unlocked | enabled | u10dW4vTo3ZkoM5xP+blayWCz7KdPKyKUojOn9GJobg= | 192.168.1.255 | 1187201000926 | 1187200991568 | 1187200605330 | 2187200605330 | 1
- Since:
- June 1, 2007
- Author:
- Jeff Williams at Aspect Security, Chris Schmidt (chrisisbeef .at. gmail.com) Digital Ritual Software
- See Also:
Authenticator
,hashPassword(String password, String accountName)
, GitHub Issue #233: Weak password storage
-
-
Field Summary
-
Fields inherited from class org.owasp.esapi.reference.AbstractAuthenticator
USER
-
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description void
changePassword(User user, java.lang.String currentPassword, java.lang.String newPassword, java.lang.String newPassword2)
Changes the password for the specified user.User
createUser(java.lang.String accountName, java.lang.String password1, java.lang.String password2)
Creates a new User with the information provided.java.lang.String
generateStrongPassword()
Generate a strong password.java.lang.String
generateStrongPassword(User user, java.lang.String oldPassword)
Generate strong password that takes into account the user's information and old password.static Authenticator
getInstance()
User
getUser(long accountId)
Returns the User matching the provided accountId.User
getUser(java.lang.String accountName)
Returns the User matching the provided accountName.java.util.Set
getUserNames()
Gets a collection containing all the existing user names.java.lang.String
hashPassword(java.lang.String password, java.lang.String accountName)
Returns a string representation of the hashed password, using the accountName as the salt.protected void
loadUsersIfNecessary()
Load users if they haven't been loaded in a while.protected void
loadUsersImmediately()
static void
main(java.lang.String[] args)
Fail safe main program to add or update an account in an emergency.void
removeUser(java.lang.String accountName)
Removes the account of the specified accountName.void
saveUsers()
Saves the user database to the file system.protected void
saveUsers(java.io.PrintWriter writer)
Save users.void
verifyAccountNameStrength(java.lang.String newAccountName)
Ensures that the account name passes site-specific complexity requirements, like minimum length.boolean
verifyPassword(User user, java.lang.String password)
Verify that the supplied password matches the password for this user.void
verifyPasswordStrength(java.lang.String oldPassword, java.lang.String newPassword, User user)
Ensures that the password meets site-specific complexity requirements, like length or number of character sets.-
Methods inherited from class org.owasp.esapi.reference.AbstractAuthenticator
clearCurrent, exists, getCurrentUser, getUserFromRememberToken, getUserFromSession, login, login, logout, setCurrentUser
-
-
-
-
Method Detail
-
getInstance
public static Authenticator getInstance()
-
main
public static void main(java.lang.String[] args) throws java.lang.Exception
Fail safe main program to add or update an account in an emergency. Warning: this method does not perform the level of validation and checks generally required in ESAPI, and can therefore be used to create a username and password that do not comply with the username and password strength requirements. Example: Use this to add the alice account with the admin role to the users file:java -Dorg.owasp.esapi.resources="/path/resources" -classpath esapi.jar org.owasp.esapi.Authenticator alice password admin
- Parameters:
args
- the arguments (username, password, role)- Throws:
java.lang.Exception
- the exception
-
createUser
public User createUser(java.lang.String accountName, java.lang.String password1, java.lang.String password2) throws AuthenticationException
Creates a new User with the information provided. Implementations should check accountName and password for proper format and strength against brute force attacks ( verifyAccountNameStrength(String), verifyPasswordStrength(String, String) ). Two copies of the new password are required to encourage user interface designers to include a "re-type password" field in their forms. Implementations should verify that both are the same.WARNING: The implementation of this method as defined in the default reference implementation class,
FileBasedAuthenticator
, uses a password hash algorthim that is known to be weak. You are advised to replace the default reference implementation class with your own custom implementation that uses a stronger password hashing algorithm. See class comments in *FileBasedAuthenticator
for further details.- Parameters:
accountName
- the account name of the new userpassword1
- the password of the new userpassword2
- the password of the new user. This field is to encourage user interface designers to include two password fields in their forms.- Returns:
- the User that has been created
- Throws:
AuthenticationException
- if user creation fails due to any of the qualifications listed in this method's description
-
generateStrongPassword
public java.lang.String generateStrongPassword()
Generate a strong password. Implementations should use a large character set that does not include confusing characters, such as i I 1 l 0 o and O. There are many algorithms to generate strong memorable passwords that have been studied in the past.- Returns:
- a password with strong password strength
-
changePassword
public void changePassword(User user, java.lang.String currentPassword, java.lang.String newPassword, java.lang.String newPassword2) throws AuthenticationException
Changes the password for the specified user. This requires the current password, as well as the password to replace it with. The new password should be checked against old hashes to be sure the new password does not closely resemble or equal any recent passwords for that User. Password strength should also be verified. This new password must be repeated to ensure that the user has typed it in correctly.- Parameters:
user
- the user to change the password forcurrentPassword
- the current password for the specified usernewPassword
- the new password to usenewPassword2
- a verification copy of the new password- Throws:
AuthenticationException
- if any errors occur
-
verifyPassword
public boolean verifyPassword(User user, java.lang.String password)
Verify that the supplied password matches the password for this user. Password should be stored as a hash. By default, this method verifies password hashes created via thehashPassword(password, accountName)
method in this class, however see WARNING thehashPassword
method.This method is typically used for "reauthentication" for the most sensitive functions, such as transactions, changing email address, and changing other account information.
- Parameters:
user
- the user who requires verificationpassword
- the hashed user-supplied password- Returns:
- true, if the password is correct for the specified user
- See Also:
Authenticator.hashPassword(String password, String accountName)
-
generateStrongPassword
public java.lang.String generateStrongPassword(User user, java.lang.String oldPassword)
Generate strong password that takes into account the user's information and old password. Implementations should verify that the new password does not include information such as the username, fragments of the old password, and other information that could be used to weaken the strength of the password.- Parameters:
user
- the user whose information to use when generating passwordoldPassword
- the old password to use when verifying strength of new password. The new password may be checked for fragments of oldPassword.- Returns:
- a password with strong password strength
-
getUser
public User getUser(long accountId)
Returns the User matching the provided accountId. If the accoundId is not found, an Anonymous User or null may be returned.- Parameters:
accountId
- the account id- Returns:
- the matching User object, or the Anonymous User if no match exists
-
getUser
public User getUser(java.lang.String accountName)
Returns the User matching the provided accountName. If the accoundId is not found, an Anonymous User or null may be returned.- Parameters:
accountName
- the account name- Returns:
- the matching User object, or the Anonymous User if no match exists
-
getUserNames
public java.util.Set getUserNames()
Gets a collection containing all the existing user names.- Returns:
- a set of all user names
-
hashPassword
public java.lang.String hashPassword(java.lang.String password, java.lang.String accountName) throws EncryptionException
Returns a string representation of the hashed password, using the accountName as the salt. The salt helps to prevent against "rainbow" table attacks where the attacker pre-calculates hashes for known strings. This method specifies the use of the user's account name as the "salt" value. The Encryptor.hash method can be used if a different salt is required.WARNING: The implementation of this method as defined in the default reference implementation class,
FileBasedAuthenticator
, is know to be extremely weak. The reference implementation class was meant to be an example implementation and generally should be avoided and replaced with your own implementation. See class comments inFileBasedAuthenticator
for further details. WARNING: There are several weaknesses in this method:- The salt should really be a randomly generated salt, typically at
least 64-bits, but in this method, the
accountName
parameter is used as the salt. - This salt is then combined with the ESAPI.properties file's
Encryptor.MasterSalt
, meaning that if that property is changed, all previously stored passwords become invalid and need to be reset. - Only 1024 iterations of the hash algorithm (SHA-512) are made. While that may have been fine in 2007, it is no longer considered sufficient.
- Parameters:
password
- the password to hashaccountName
- the account name to use as the salt- Returns:
- the hashed password
- Throws:
EncryptionException
- See Also:
FileBasedAuthenticator, the default reference implementation of this interface.
- The salt should really be a randomly generated salt, typically at
least 64-bits, but in this method, the
-
loadUsersIfNecessary
protected void loadUsersIfNecessary()
Load users if they haven't been loaded in a while.
-
loadUsersImmediately
protected void loadUsersImmediately()
-
removeUser
public void removeUser(java.lang.String accountName) throws AuthenticationException
Removes the account of the specified accountName.- Parameters:
accountName
- the account name to remove- Throws:
AuthenticationException
- the authentication exception if user does not exist
-
saveUsers
public void saveUsers() throws AuthenticationException
Saves the user database to the file system. In this implementation you must call save to commit any changes to the user file. Otherwise changes will be lost when the program ends.- Throws:
AuthenticationException
- if the user file could not be written
-
saveUsers
protected void saveUsers(java.io.PrintWriter writer) throws AuthenticationCredentialsException
Save users.- Parameters:
writer
- the print writer to use for saving- Throws:
AuthenticationCredentialsException
-
verifyAccountNameStrength
public void verifyAccountNameStrength(java.lang.String newAccountName) throws AuthenticationException
Ensures that the account name passes site-specific complexity requirements, like minimum length. This implementation simply verifies that account names are at least 5 characters long. This helps to defeat a brute force attack, however the real strength comes from the name length and complexity.- Parameters:
newAccountName
-- Throws:
AuthenticationException
- if account name does not meet complexity requirements
-
verifyPasswordStrength
public void verifyPasswordStrength(java.lang.String oldPassword, java.lang.String newPassword, User user) throws AuthenticationException
Ensures that the password meets site-specific complexity requirements, like length or number of character sets. This method takes the old password so that the algorithm can analyze the new password to see if it is too similar to the old password. Note that this has to be invoked when the user has entered the old password, as the list of old credentials stored by ESAPI is all hashed. Additionally, the user object is taken in order to verify the password and account name differ. This implementation checks: - for any 3 character substrings of the old password - for use of a length * character sets > 16 (where character sets are upper, lower, digit, and special jtm - 11/16/2010 - added check to verify pw != username (fix for http://code.google.com/p/owasp-esapi-java/issues/detail?id=108)- Parameters:
oldPassword
- the old passwordnewPassword
- the new passworduser
- the user- Throws:
AuthenticationException
- if newPassword is too similar to oldPassword or if newPassword does not meet complexity requirements
-
-