Fixed the tests

This commit is contained in:
Asim 2018-05-09 13:51:11 +02:00
parent 067e629a9c
commit 752f9d1229
26 changed files with 302 additions and 45 deletions

View file

@ -53,6 +53,11 @@
</build> </build>
<dependencies> <dependencies>
<dependency>
<groupId>de.mkammerer</groupId>
<artifactId>argon2-jvm</artifactId>
<version>2.4</version>
</dependency>
<dependency> <dependency>
<groupId>org.vivoweb</groupId> <groupId>org.vivoweb</groupId>
<artifactId>vitro-dependencies</artifactId> <artifactId>vitro-dependencies</artifactId>

View file

@ -102,7 +102,7 @@ public class PolicyHelper {
String uri = user.getUri(); String uri = user.getUri();
log.debug("userAccount is '" + uri + "'"); log.debug("userAccount is '" + uri + "'");
if (!auth.isCurrentPassword(user, password)) { if (!auth.isCurrentPasswordArgon2(user, password)) {
log.debug(String.format("UNAUTHORIZED, password not accepted " log.debug(String.format("UNAUTHORIZED, password not accepted "
+ "for %s, account URI: %s", email, uri)); + "for %s, account URI: %s", email, uri));
return false; return false;

View file

@ -67,6 +67,7 @@ public class RootUserPolicy implements PolicyIface {
private ServletContext ctx; private ServletContext ctx;
private StartupStatus ss; private StartupStatus ss;
private UserAccountsDao uaDao; private UserAccountsDao uaDao;
private ConfigurationProperties cp;
private String configuredRootUser; private String configuredRootUser;
private boolean configuredRootUserExists; private boolean configuredRootUserExists;
private TreeSet<String> otherRootUsers; private TreeSet<String> otherRootUsers;
@ -75,6 +76,7 @@ public class RootUserPolicy implements PolicyIface {
public void contextInitialized(ServletContextEvent sce) { public void contextInitialized(ServletContextEvent sce) {
ctx = sce.getServletContext(); ctx = sce.getServletContext();
ss = StartupStatus.getBean(ctx); ss = StartupStatus.getBean(ctx);
cp = ConfigurationProperties.getBean(ctx);
try { try {
uaDao = ModelAccess.on(ctx).getWebappDaoFactory() uaDao = ModelAccess.on(ctx).getWebappDaoFactory()
@ -148,8 +150,8 @@ public class RootUserPolicy implements PolicyIface {
ua.setEmailAddress(configuredRootUser); ua.setEmailAddress(configuredRootUser);
ua.setFirstName("root"); ua.setFirstName("root");
ua.setLastName("user"); ua.setLastName("user");
ua.setMd5Password(Authenticator ua.setArgon2Password(Authenticator.applyArgon2iEncoding(cp,ROOT_USER_INITIAL_PASSWORD));
.applyMd5Encoding(ROOT_USER_INITIAL_PASSWORD)); ua.setMd5Password("");
ua.setPasswordChangeRequired(true); ua.setPasswordChangeRequired(true);
ua.setStatus(Status.ACTIVE); ua.setStatus(Status.ACTIVE);
ua.setRootUser(true); ua.setRootUser(true);

View file

@ -48,6 +48,7 @@ public class UserAccount {
private String firstName = ""; // Never null. private String firstName = ""; // Never null.
private String lastName = ""; // Never null. private String lastName = ""; // Never null.
private String argon2Password = ""; //Never null.
private String md5Password = ""; // Never null. private String md5Password = ""; // Never null.
private String oldPassword = ""; // Never null. private String oldPassword = ""; // Never null.
private long passwordLinkExpires = 0L; // Never negative. private long passwordLinkExpires = 0L; // Never negative.
@ -104,6 +105,14 @@ public class UserAccount {
this.lastName = nonNull(lastName, ""); this.lastName = nonNull(lastName, "");
} }
public String getArgon2Password() {
return argon2Password;
}
public void setArgon2Password(String argo2Password) {
this.argon2Password = nonNull(argo2Password, "");
}
public String getMd5Password() { public String getMd5Password() {
return md5Password; return md5Password;
} }
@ -125,8 +134,9 @@ public class UserAccount {
} }
public String getPasswordLinkExpiresHash() { public String getPasswordLinkExpiresHash() {
return limitStringLength(8, Authenticator.applyMd5Encoding(String return limitStringLength(8, Authenticator.applyArgon2iEncoding(String
.valueOf(passwordLinkExpires))); .valueOf(passwordLinkExpires)));
//applyMd5Encoding
} }
public void setPasswordLinkExpires(long passwordLinkExpires) { public void setPasswordLinkExpires(long passwordLinkExpires) {

View file

@ -246,6 +246,7 @@ public class UserAccountsSelector {
user.setFirstName(ifLiteralPresent(solution, "firstName", "")); user.setFirstName(ifLiteralPresent(solution, "firstName", ""));
user.setLastName(ifLiteralPresent(solution, "lastName", "")); user.setLastName(ifLiteralPresent(solution, "lastName", ""));
user.setMd5Password(ifLiteralPresent(solution, "pwd", "")); user.setMd5Password(ifLiteralPresent(solution, "pwd", ""));
user.setArgon2Password(ifLiteralPresent(solution, "pwd", ""));
user.setPasswordLinkExpires(ifLongPresent(solution, "expire", 0L)); user.setPasswordLinkExpires(ifLongPresent(solution, "expire", 0L));
user.setLoginCount(ifIntPresent(solution, "count", 0)); user.setLoginCount(ifIntPresent(solution, "count", 0));
user.setLastLoginTime(ifLongPresent(solution, "lastLogin", 0)); user.setLastLoginTime(ifLongPresent(solution, "lastLogin", 0));

View file

@ -198,8 +198,8 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage {
@Override @Override
protected void setAdditionalProperties(UserAccount u) { protected void setAdditionalProperties(UserAccount u) {
if (!page.isExternalAuthOnly()) { if (!page.isExternalAuthOnly()) {
u.setMd5Password(Authenticator u.setArgon2Password(Authenticator.applyArgon2iEncoding(initialPassword));
.applyMd5Encoding(initialPassword)); u.setMd5Password("");
u.setPasswordChangeRequired(true); u.setPasswordChangeRequired(true);
} }
u.setStatus(Status.ACTIVE); u.setStatus(Status.ACTIVE);

View file

@ -194,7 +194,8 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
@Override @Override
protected void setAdditionalProperties(UserAccount u) { protected void setAdditionalProperties(UserAccount u) {
if (!page.isExternalAuthOnly() && !newPassword.isEmpty()) { if (!page.isExternalAuthOnly() && !newPassword.isEmpty()) {
u.setMd5Password(Authenticator.applyMd5Encoding(newPassword)); u.setArgon2Password(Authenticator.applyArgon2iEncoding(newPassword));
u.setMd5Password("");
u.setPasswordChangeRequired(true); u.setPasswordChangeRequired(true);
} }
} }

View file

@ -33,14 +33,14 @@ public class UserAccountsCreatePasswordPage extends
} }
public void createPassword() { public void createPassword() {
userAccount.setMd5Password(Authenticator.applyMd5Encoding(newPassword)); userAccount.setArgon2Password(Authenticator.applyArgon2iEncoding(newPassword));
userAccount.setMd5Password("");
userAccount.setPasswordLinkExpires(0L); userAccount.setPasswordLinkExpires(0L);
userAccount.setPasswordChangeRequired(false); userAccount.setPasswordChangeRequired(false);
userAccount.setStatus(Status.ACTIVE); userAccount.setStatus(Status.ACTIVE);
userAccountsDao.updateUserAccount(userAccount); userAccountsDao.updateUserAccount(userAccount);
log.debug("Set password on '" + userAccount.getEmailAddress() log.debug("Set password on '" + userAccount.getEmailAddress()
+ "' to '" + newPassword + "'"); + "' to '" + newPassword + "'");
notifyUser(); notifyUser();
} }

View file

@ -155,8 +155,8 @@ public abstract class UserAccountsMyAccountPageStrategy extends
@Override @Override
public void setAdditionalProperties(UserAccount userAccount) { public void setAdditionalProperties(UserAccount userAccount) {
if (!newPassword.isEmpty() && !page.isExternalAuthOnly()) { if (!newPassword.isEmpty() && !page.isExternalAuthOnly()) {
userAccount.setMd5Password(Authenticator userAccount.setArgon2Password(Authenticator.applyArgon2iEncoding(newPassword));
.applyMd5Encoding(newPassword)); userAccount.setMd5Password("");
userAccount.setPasswordChangeRequired(false); userAccount.setPasswordChangeRequired(false);
userAccount.setPasswordLinkExpires(0L); userAccount.setPasswordLinkExpires(0L);
} }

View file

@ -33,7 +33,8 @@ public class UserAccountsResetPasswordPage extends UserAccountsPasswordBasePage
} }
public void resetPassword() { public void resetPassword() {
userAccount.setMd5Password(Authenticator.applyMd5Encoding(newPassword)); userAccount.setArgon2Password(Authenticator.applyArgon2iEncoding(newPassword));
userAccount.setMd5Password("");
userAccount.setPasswordLinkExpires(0L); userAccount.setPasswordLinkExpires(0L);
userAccount.setPasswordChangeRequired(false); userAccount.setPasswordChangeRequired(false);
userAccount.setStatus(Status.ACTIVE); userAccount.setStatus(Status.ACTIVE);

View file

@ -54,7 +54,7 @@ public class VitroApiServlet extends HttpServlet {
+ "last names and a valid email address."); + "last names and a valid email address.");
} }
if (!auth.isCurrentPassword(account, password)) { if (!auth.isCurrentPasswordArgon2(account, password)) {
log.debug("Invalid: '" + email + "'/'" + password + "'"); log.debug("Invalid: '" + email + "'/'" + password + "'");
throw new AuthException("email/password combination is not valid"); throw new AuthException("email/password combination is not valid");
} }

View file

@ -141,8 +141,12 @@ public class AdminLoginController extends FreemarkerHttpServlet {
} }
private boolean newPasswordRequired() { private boolean newPasswordRequired() {
return auth.isCurrentPassword(userAccount, password) if(auth.md5HashIsNull(userAccount)) {
&& (userAccount.isPasswordChangeRequired()); return auth.isCurrentPasswordArgon2(userAccount, password)
&& userAccount.isPasswordChangeRequired();
}
else
return auth.isCurrentPassword(userAccount, password); // MD5 password should be changed anyway
} }
private boolean isPasswordValidLength(String pw) { private boolean isPasswordValidLength(String pw) {
@ -151,9 +155,19 @@ public class AdminLoginController extends FreemarkerHttpServlet {
} }
private boolean tryToLogin() { private boolean tryToLogin() {
if (!auth.isCurrentPassword(userAccount, password)) { if(auth.md5HashIsNull(userAccount)) {
if (!auth.isCurrentPasswordArgon2(userAccount, password))
return false; return false;
} }
else {
if (!auth.isCurrentPassword(userAccount, password))
return false;
else {
userAccount.setPasswordChangeRequired(true);
userAccount.setMd5Password("");
}
}
try { try {
auth.recordLoginAgainstUserAccount(userAccount, INTERNAL); auth.recordLoginAgainstUserAccount(userAccount, INTERNAL);

View file

@ -2,21 +2,23 @@
package edu.cornell.mannlib.vitro.webapp.controller.authenticate; package edu.cornell.mannlib.vitro.webapp.controller.authenticate;
import java.security.MessageDigest; import de.mkammerer.argon2.Argon2;
import java.security.NoSuchAlgorithmException; import de.mkammerer.argon2.Argon2Factory;
import java.util.List; import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ActiveIdentifierBundleFactories;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import org.apache.commons.codec.binary.Hex;
import javax.mail.internet.AddressException; import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress; import javax.mail.internet.InternetAddress;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import org.apache.commons.codec.binary.Hex;
import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ActiveIdentifierBundleFactories;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/** /**
* The tool that a login process will use to interface with the user records in * The tool that a login process will use to interface with the user records in
@ -55,6 +57,7 @@ public abstract class Authenticator {
* *
* If there is no factory, configure a Basic one. * If there is no factory, configure a Basic one.
*/ */
private static ConfigurationProperties cp;
public static Authenticator getInstance(HttpServletRequest request) { public static Authenticator getInstance(HttpServletRequest request) {
ServletContext ctx = request.getSession().getServletContext(); ServletContext ctx = request.getSession().getServletContext();
Object attribute = ctx.getAttribute(FACTORY_ATTRIBUTE_NAME); Object attribute = ctx.getAttribute(FACTORY_ATTRIBUTE_NAME);
@ -63,6 +66,7 @@ public abstract class Authenticator {
attribute = ctx.getAttribute(FACTORY_ATTRIBUTE_NAME); attribute = ctx.getAttribute(FACTORY_ATTRIBUTE_NAME);
} }
AuthenticatorFactory factory = (AuthenticatorFactory) attribute; AuthenticatorFactory factory = (AuthenticatorFactory) attribute;
cp = ConfigurationProperties.getBean(ctx);
return factory.getInstance(request); return factory.getInstance(request);
} }
@ -112,6 +116,17 @@ public abstract class Authenticator {
public abstract boolean isCurrentPassword(UserAccount userAccount, public abstract boolean isCurrentPassword(UserAccount userAccount,
String clearTextPassword); String clearTextPassword);
public abstract boolean isCurrentPasswordArgon2(UserAccount userAccount,
String clearTextPassword);
/**
*
* Checks if the user still has got an MD5 Password
*/
public abstract boolean md5HashIsNull(UserAccount userAccount);
/** /**
* Internal: record a new password for the user. Takes no action if the * Internal: record a new password for the user. Takes no action if the
* userAccount is null. * userAccount is null.
@ -180,6 +195,78 @@ public abstract class Authenticator {
} }
} }
/**
* Applies Argon2i hashing on a string.
* Used by tests only with pre-specified values because the configuration
* properties (runtime.properties) is not set at compile time.
**/
public static String applyArgon2iEncodingStub(String raw) {
Argon2 argon2 = Argon2Factory.create();
try {
return argon2.hash(200, 500, 1, raw);
} catch (Exception e) {
// This can't happen with a normal Java runtime.
throw new RuntimeException(e);
}
}
/**
* Applies Argon2i hashing on a string. Obtains the argon2i parameters
* from the configuration properties specified in the runtime.properties
* through this class "Authenticator".
**/
public static String applyArgon2iEncoding(String raw) {
Argon2 argon2 = Argon2Factory.create();
try {
if(cp.getProperty("argon2.time") != null && cp.getProperty("argon2.memory") !=null && cp.getProperty("argon2.parallelism")!=null)
return argon2.hash(Integer.parseInt(cp.getProperty("argon2.time")),
Integer.parseInt(cp.getProperty("argon2.memory")),
Integer.parseInt(cp.getProperty("argon2.parallelism")), raw);
else
throw new RuntimeException("Parameters \"argon2.time\", \"argon2.memory\" and \"argon2.parallelism\" are either missing in the \"runtime.properties\" file or are not defined correctly");
} catch (Exception e) {
// This can't happen with a normal Java runtime.
throw new RuntimeException(e);
}
}
/**
* Applies Argon2i hashing on a string.
* When Vivo/Vitro is run for the first time the application needs to set
* the "root" account before a call is made to this class (Authenticator).
* In that case the configuration properties are passed along with the
* password string to this method.
**/
public static String applyArgon2iEncoding(ConfigurationProperties configProp, String raw) {
Argon2 argon2 = Argon2Factory.create();
try {
if(configProp.getProperty("argon2.time") != null && configProp.getProperty("argon2.memory") !=null && configProp.getProperty("argon2.parallelism")!=null)
return argon2.hash(Integer.parseInt(configProp.getProperty("argon2.time")),
Integer.parseInt(configProp.getProperty("argon2.memory")),
Integer.parseInt(configProp.getProperty("argon2.parallelism")), raw);
else
throw new RuntimeException("Parameters \"argon2.time\", \"argon2.memory\" and \"argon2.parallelism\" are either missing in the \"runtime.properties\" file or are not defined correctly");
} catch (Exception e) {
// This can't happen with a normal Java runtime.
throw new RuntimeException(e);
}
}
/**
Verifies the string against the Argon2i hash stored for a user account
*/
public static boolean verifyArgon2iHash(String hash, String raw)
{
Argon2 argon2 = Argon2Factory.create();
return argon2.verify(hash, raw);
}
/** /**
* Check whether the form of the emailAddress is syntactically correct. Does * Check whether the form of the emailAddress is syntactically correct. Does
* not allow multiple addresses. Does not allow local addresses (without a * not allow multiple addresses. Does not allow local addresses (without a

View file

@ -98,6 +98,30 @@ public class BasicAuthenticator extends Authenticator {
return encodedPassword.equals(userAccount.getMd5Password()); return encodedPassword.equals(userAccount.getMd5Password());
} }
@Override
public boolean md5HashIsNull(UserAccount userAccount){
if(userAccount.getMd5Password().compareTo("")==0 || userAccount.getMd5Password()==null)
return true;
else
return false;
}
@Override
public boolean isCurrentPasswordArgon2(UserAccount userAccount,
String clearTextPassword) {
if (userAccount == null) {
return false;
}
if (clearTextPassword == null) {
return false;
}
return verifyArgon2iHash(userAccount.getArgon2Password(),clearTextPassword);
}
@Override @Override
public void recordNewPassword(UserAccount userAccount, public void recordNewPassword(UserAccount userAccount,
String newClearTextPassword) { String newClearTextPassword) {
@ -105,7 +129,8 @@ public class BasicAuthenticator extends Authenticator {
log.error("Trying to change password on null user."); log.error("Trying to change password on null user.");
return; return;
} }
userAccount.setMd5Password(applyMd5Encoding(newClearTextPassword)); userAccount.setArgon2Password((applyArgon2iEncoding(newClearTextPassword)));
userAccount.setMd5Password("");
userAccount.setPasswordChangeRequired(false); userAccount.setPasswordChangeRequired(false);
userAccount.setPasswordLinkExpires(0L); userAccount.setPasswordLinkExpires(0L);
getUserAccountsDao().updateUserAccount(userAccount); getUserAccountsDao().updateUserAccount(userAccount);

View file

@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.controller.authenticate;
import static edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource.INTERNAL; import static edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource.INTERNAL;
import static edu.cornell.mannlib.vitro.webapp.beans.UserAccount.MAX_PASSWORD_LENGTH; import static edu.cornell.mannlib.vitro.webapp.beans.UserAccount.MAX_PASSWORD_LENGTH;
import static edu.cornell.mannlib.vitro.webapp.beans.UserAccount.MIN_PASSWORD_LENGTH; import static edu.cornell.mannlib.vitro.webapp.beans.UserAccount.MIN_PASSWORD_LENGTH;
import static edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.MLevel.ERROR;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -158,7 +159,20 @@ public class ProgramLogin extends HttpServlet {
} }
private boolean usernameAndPasswordAreValid() { private boolean usernameAndPasswordAreValid() {
return auth.isCurrentPassword(userAccount, password);
if(auth.md5HashIsNull(userAccount)) {
if (!auth.isCurrentPasswordArgon2(userAccount, password))
return false;
}
else {
if (!auth.isCurrentPassword(userAccount, password))
return false;
else {
userAccount.setPasswordChangeRequired(true);
// userAccount.setMd5Password("");
}
}
return true;
} }
private boolean loginDisabled() { private boolean loginDisabled() {

View file

@ -76,6 +76,29 @@ public class RestrictedAuthenticator extends Authenticator {
return auth.getAccountForInternalAuth(emailAddress); return auth.getAccountForInternalAuth(emailAddress);
} }
@Override
public boolean md5HashIsNull(UserAccount userAccount){
if(userAccount.getMd5Password().compareTo("")==0 || userAccount.getMd5Password()==null)
return true;
else
return false;
}
@Override
public boolean isCurrentPasswordArgon2(UserAccount userAccount,
String clearTextPassword) {
if (userAccount == null) {
return false;
}
if (clearTextPassword == null) {
return false;
}
return verifyArgon2iHash(userAccount.getArgon2Password(),clearTextPassword);
}
@Override @Override
public boolean isCurrentPassword(UserAccount userAccount, public boolean isCurrentPassword(UserAccount userAccount,
String clearTextPassword) { String clearTextPassword) {

View file

@ -331,15 +331,31 @@ public class Authenticate extends VitroHttpServlet {
return; return;
} }
if (!getAuthenticator(request).isUserPermittedToLogin(user)) { if (!getAuthenticator(request).isUserPermittedToLogin(user)) {
bean.setMessage(request, ERROR, "logins_disabled_for_maintenance"); bean.setMessage(request, ERROR, "logins_disabled_for_maintenance");
return; return;
} }
if(getAuthenticator(request).md5HashIsNull(user)) {
if (!getAuthenticator(request).isCurrentPasswordArgon2(user, password)) {
bean.setMessage(request, ERROR, "error_incorrect_credentials");
return;
}
}
else {
if (!getAuthenticator(request).isCurrentPassword(user, password)) { if (!getAuthenticator(request).isCurrentPassword(user, password)) {
bean.setMessage(request, ERROR, "error_incorrect_credentials"); bean.setMessage(request, ERROR, "error_incorrect_credentials");
return; return;
} }
else {
user.setPasswordChangeRequired(true);
user.setMd5Password("");
}
}
// Username and password are correct. What next? // Username and password are correct. What next?
if (user.isPasswordChangeRequired()) { if (user.isPasswordChangeRequired()) {
@ -401,7 +417,7 @@ public class Authenticate extends VitroHttpServlet {
UserAccount user = getAuthenticator(request).getAccountForInternalAuth( UserAccount user = getAuthenticator(request).getAccountForInternalAuth(
username); username);
if (getAuthenticator(request).isCurrentPassword(user, newPassword)) { if (getAuthenticator(request).isCurrentPasswordArgon2(user, newPassword)) {
bean.setMessage(request, ERROR, "error_previous_password"); bean.setMessage(request, ERROR, "error_previous_password");
return; return;
} }

View file

@ -149,6 +149,7 @@ public class VitroVocabulary {
public static final String USERACCOUNT_EMAIL_ADDRESS = VITRO_AUTH + "emailAddress"; public static final String USERACCOUNT_EMAIL_ADDRESS = VITRO_AUTH + "emailAddress";
public static final String USERACCOUNT_FIRST_NAME = VITRO_AUTH + "firstName"; public static final String USERACCOUNT_FIRST_NAME = VITRO_AUTH + "firstName";
public static final String USERACCOUNT_LAST_NAME = VITRO_AUTH + "lastName"; public static final String USERACCOUNT_LAST_NAME = VITRO_AUTH + "lastName";
public static final String USERACCOUNT_ARGON2_PASSWORD = VITRO_AUTH + "argon2password";
public static final String USERACCOUNT_MD5_PASSWORD = VITRO_AUTH + "md5password"; public static final String USERACCOUNT_MD5_PASSWORD = VITRO_AUTH + "md5password";
public static final String USERACCOUNT_OLD_PASSWORD = VITRO_AUTH + "oldpassword"; public static final String USERACCOUNT_OLD_PASSWORD = VITRO_AUTH + "oldpassword";
public static final String USERACCOUNT_LOGIN_COUNT = VITRO_AUTH + "loginCount"; public static final String USERACCOUNT_LOGIN_COUNT = VITRO_AUTH + "loginCount";

View file

@ -112,6 +112,7 @@ public class JenaBaseDaoCon {
protected DatatypeProperty USERACCOUNT_EMAIL_ADDRESS = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_EMAIL_ADDRESS); protected DatatypeProperty USERACCOUNT_EMAIL_ADDRESS = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_EMAIL_ADDRESS);
protected DatatypeProperty USERACCOUNT_FIRST_NAME = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_FIRST_NAME); protected DatatypeProperty USERACCOUNT_FIRST_NAME = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_FIRST_NAME);
protected DatatypeProperty USERACCOUNT_LAST_NAME = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_LAST_NAME); protected DatatypeProperty USERACCOUNT_LAST_NAME = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_LAST_NAME);
protected DatatypeProperty USERACCOUNT_ARGON2_PASSWORD = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_ARGON2_PASSWORD);
protected DatatypeProperty USERACCOUNT_MD5_PASSWORD = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_MD5_PASSWORD); protected DatatypeProperty USERACCOUNT_MD5_PASSWORD = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_MD5_PASSWORD);
protected DatatypeProperty USERACCOUNT_OLD_PASSWORD = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_OLD_PASSWORD); protected DatatypeProperty USERACCOUNT_OLD_PASSWORD = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_OLD_PASSWORD);
protected DatatypeProperty USERACCOUNT_LOGIN_COUNT = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_LOGIN_COUNT); protected DatatypeProperty USERACCOUNT_LOGIN_COUNT = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_LOGIN_COUNT);

View file

@ -93,6 +93,7 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
USERACCOUNT_EMAIL_ADDRESS)); USERACCOUNT_EMAIL_ADDRESS));
u.setFirstName(getPropertyStringValue(r, USERACCOUNT_FIRST_NAME)); u.setFirstName(getPropertyStringValue(r, USERACCOUNT_FIRST_NAME));
u.setLastName(getPropertyStringValue(r, USERACCOUNT_LAST_NAME)); u.setLastName(getPropertyStringValue(r, USERACCOUNT_LAST_NAME));
u.setArgon2Password(getPropertyStringValue(r, USERACCOUNT_ARGON2_PASSWORD));
u.setMd5Password(getPropertyStringValue(r, USERACCOUNT_MD5_PASSWORD)); u.setMd5Password(getPropertyStringValue(r, USERACCOUNT_MD5_PASSWORD));
u.setOldPassword(getPropertyStringValue(r, USERACCOUNT_OLD_PASSWORD)); u.setOldPassword(getPropertyStringValue(r, USERACCOUNT_OLD_PASSWORD));
u.setPasswordLinkExpires(getPropertyLongValue(r, u.setPasswordLinkExpires(getPropertyLongValue(r,
@ -225,6 +226,8 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
userAccount.getLastName(), model); userAccount.getLastName(), model);
addPropertyStringValue(res, USERACCOUNT_MD5_PASSWORD, addPropertyStringValue(res, USERACCOUNT_MD5_PASSWORD,
userAccount.getMd5Password(), model); userAccount.getMd5Password(), model);
addPropertyStringValue(res, USERACCOUNT_ARGON2_PASSWORD,
userAccount.getArgon2Password(), model);
addPropertyStringValue(res, USERACCOUNT_OLD_PASSWORD, addPropertyStringValue(res, USERACCOUNT_OLD_PASSWORD,
userAccount.getOldPassword(), model); userAccount.getOldPassword(), model);
addPropertyLongValue(res, USERACCOUNT_PASSWORD_LINK_EXPIRES, addPropertyLongValue(res, USERACCOUNT_PASSWORD_LINK_EXPIRES,
@ -288,6 +291,8 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
userAccount.getLastName(), model); userAccount.getLastName(), model);
updatePropertyStringValue(res, USERACCOUNT_MD5_PASSWORD, updatePropertyStringValue(res, USERACCOUNT_MD5_PASSWORD,
userAccount.getMd5Password(), model); userAccount.getMd5Password(), model);
updatePropertyStringValue(res, USERACCOUNT_ARGON2_PASSWORD,
userAccount.getArgon2Password(), model);
updatePropertyStringValue(res, USERACCOUNT_OLD_PASSWORD, updatePropertyStringValue(res, USERACCOUNT_OLD_PASSWORD,
userAccount.getOldPassword(), model); userAccount.getOldPassword(), model);
updatePropertyLongValue(res, USERACCOUNT_PASSWORD_LINK_EXPIRES, updatePropertyLongValue(res, USERACCOUNT_PASSWORD_LINK_EXPIRES,

View file

@ -102,6 +102,32 @@ public class AuthenticatorStub extends Authenticator {
return true; return true;
} }
@Override
public boolean md5HashIsNull(UserAccount userAccount){
if(userAccount!=null) {
if (userAccount.getMd5Password().compareTo("") == 0 || userAccount.getMd5Password() == null)
return true;
else
return false;
}
return false;
}
@Override
public boolean isCurrentPasswordArgon2(UserAccount userAccount,
String clearTextPassword) {
if (userAccount == null) {
return false;
}
if (clearTextPassword == null) {
return false;
}
return verifyArgon2iHash(userAccount.getArgon2Password(),clearTextPassword);
}
@Override @Override
public boolean isCurrentPassword(UserAccount userAccount, public boolean isCurrentPassword(UserAccount userAccount,
String clearTextPassword) { String clearTextPassword) {

View file

@ -98,7 +98,9 @@ public class ProgramLoginTest extends AbstractTestClass {
user.setUri(uri); user.setUri(uri);
user.setPermissionSetUris(Collections user.setPermissionSetUris(Collections
.singleton(PermissionSets.URI_DBA)); .singleton(PermissionSets.URI_DBA));
user.setMd5Password(Authenticator.applyMd5Encoding(password)); user.setArgon2Password(Authenticator.applyArgon2iEncodingStub(password));
user.setMd5Password("");
//user.setMd5Password(Authenticator.applyMd5Encoding(password));
user.setLoginCount(loginCount); user.setLoginCount(loginCount);
user.setPasswordChangeRequired(loginCount == 0); user.setPasswordChangeRequired(loginCount == 0);
return user; return user;
@ -179,12 +181,15 @@ public class ProgramLoginTest extends AbstractTestClass {
String newPassword) { String newPassword) {
if (email != null) { if (email != null) {
request.addParameter(PARAM_EMAIL_ADDRESS, email); request.addParameter(PARAM_EMAIL_ADDRESS, email);
System.out.println("1");
} }
if (password != null) { if (password != null) {
request.addParameter(PARAM_PASSWORD, password); request.addParameter(PARAM_PASSWORD, password);
System.out.println("2");
} }
if (newPassword != null) { if (newPassword != null) {
request.addParameter(PARAM_NEW_PASSWORD, newPassword); request.addParameter(PARAM_NEW_PASSWORD, newPassword);
System.out.println("3");
} }
try { try {

View file

@ -191,7 +191,9 @@ public class AuthenticateTest extends AbstractTestClass {
user.setEmailAddress(userInfo.username); user.setEmailAddress(userInfo.username);
user.setUri(userInfo.uri); user.setUri(userInfo.uri);
user.setPermissionSetUris(userInfo.permissionSetUris); user.setPermissionSetUris(userInfo.permissionSetUris);
user.setMd5Password(Authenticator.applyMd5Encoding(userInfo.password)); user.setArgon2Password(Authenticator.applyArgon2iEncodingStub(userInfo.password));
user.setMd5Password("");
// user.setMd5Password(Authenticator.applyMd5Encoding(userInfo.password));
user.setLoginCount(userInfo.loginCount); user.setLoginCount(userInfo.loginCount);
user.setPasswordChangeRequired(userInfo.loginCount == 0); user.setPasswordChangeRequired(userInfo.loginCount == 0);
return user; return user;

View file

@ -91,19 +91,19 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass {
@Before @Before
public void createUserAccountValues() { public void createUserAccountValues() {
user1 = userAccount(URI_USER1, "email@able.edu", "Zack", "Roberts", user1 = userAccount(URI_USER1, "email@able.edu", "Zack", "Roberts",
"garbage", "", 0L, false, 5, 12345678L, Status.ACTIVE, "user1", "garbage", "" ,"", 0L, false, 5, 12345678L, Status.ACTIVE, "user1",
false, collection(URI_ROLE1), false, EMPTY); false, collection(URI_ROLE1), false, EMPTY);
userNew = userAccount("", "email@here", "Joe", "Blow", "XXXX", "YYYY", userNew = userAccount("", "email@here", "Joe", "Blow", "XXXX","", "YYYY",
0L, false, 1, 0L, Status.ACTIVE, "jblow", false, EMPTY, false, 0L, false, 1, 0L, Status.ACTIVE, "jblow", false, EMPTY, false,
EMPTY); EMPTY);
userA = userAccount("", "aahern@here", "Alf", "Ahern", "XXXX", "YYYY", userA = userAccount("", "aahern@here", "Alf", "Ahern", "XXXX", "", "YYYY",
0L, false, 1, 0L, Status.ACTIVE, "aahern", false, EMPTY, false, 0L, false, 1, 0L, Status.ACTIVE, "aahern", false, EMPTY, false,
collection(URI_PROFILE1)); collection(URI_PROFILE1));
userB = userAccount("", "email@here", "Betty", "Boop", "XXXX", "YYYY", userB = userAccount("", "email@here", "Betty", "Boop", "XXXX", "", "YYYY",
0L, false, 1, 0L, Status.ACTIVE, "bboop", false, EMPTY, false, 0L, false, 1, 0L, Status.ACTIVE, "bboop", false, EMPTY, false,
collection(URI_PROFILE1, URI_PROFILE2)); collection(URI_PROFILE1, URI_PROFILE2));
userC = userAccount("", "ccallas@here", "Charlie", "Callas", "XXXX", userC = userAccount("", "ccallas@here", "Charlie", "Callas", "XXXX", "",
"YYYY", 0L, false, 1, 0L, Status.ACTIVE, "ccallas", false, "YYYY", 0L, false, 1, 0L, Status.ACTIVE, "ccallas", false,
EMPTY, false, collection(URI_PROFILE2)); EMPTY, false, collection(URI_PROFILE2));
} }
@ -179,7 +179,7 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass {
@Test @Test
public void updateUserAccountSuccess() { public void updateUserAccountSuccess() {
UserAccount orig = userAccount(URI_USER1, "updatedEmail@able.edu", UserAccount orig = userAccount(URI_USER1, "updatedEmail@able.edu",
"Ezekiel", "Roberts", "differentHash", "oldHash", 1L, false, "Ezekiel", "Roberts", "differentHash", "", "oldHash", 1L, false,
43, 1020304050607080L, Status.ACTIVE, "updatedUser1", false, 43, 1020304050607080L, Status.ACTIVE, "updatedUser1", false,
collection(URI_ROLE1, URI_ROLE3), false, EMPTY); collection(URI_ROLE1, URI_ROLE3), false, EMPTY);
@ -379,7 +379,7 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass {
} }
private UserAccount userAccount(String uri, String emailAddress, private UserAccount userAccount(String uri, String emailAddress,
String firstName, String lastName, String md5Password, String firstName, String lastName, String argon2Password, String md5Password,
String oldPassword, long passwordLinkExpires, String oldPassword, long passwordLinkExpires,
boolean passwordChangeRequired, int loginCount, long lastLoginTime, boolean passwordChangeRequired, int loginCount, long lastLoginTime,
Status status, String externalAuthId, boolean externalAuthOnly, Status status, String externalAuthId, boolean externalAuthOnly,
@ -390,7 +390,9 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass {
ua.setEmailAddress(emailAddress); ua.setEmailAddress(emailAddress);
ua.setFirstName(firstName); ua.setFirstName(firstName);
ua.setLastName(lastName); ua.setLastName(lastName);
ua.setMd5Password(md5Password); ua.setArgon2Password(argon2Password);
ua.setMd5Password("");
//ua.setMd5Password(md5Password);
ua.setOldPassword(oldPassword); ua.setOldPassword(oldPassword);
ua.setPasswordLinkExpires(passwordLinkExpires); ua.setPasswordLinkExpires(passwordLinkExpires);
ua.setPasswordChangeRequired(passwordChangeRequired); ua.setPasswordChangeRequired(passwordChangeRequired);
@ -411,6 +413,7 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass {
out.setEmailAddress(in.getEmailAddress()); out.setEmailAddress(in.getEmailAddress());
out.setFirstName(in.getFirstName()); out.setFirstName(in.getFirstName());
out.setLastName(in.getLastName()); out.setLastName(in.getLastName());
out.setArgon2Password(in.getArgon2Password());
out.setMd5Password(in.getMd5Password()); out.setMd5Password(in.getMd5Password());
out.setOldPassword(in.getOldPassword()); out.setOldPassword(in.getOldPassword());
out.setPasswordLinkExpires(in.getPasswordLinkExpires()); out.setPasswordLinkExpires(in.getPasswordLinkExpires());
@ -433,7 +436,7 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass {
assertEquals("email", e.getEmailAddress(), a.getEmailAddress()); assertEquals("email", e.getEmailAddress(), a.getEmailAddress());
assertEquals("first name", e.getFirstName(), a.getFirstName()); assertEquals("first name", e.getFirstName(), a.getFirstName());
assertEquals("last name", e.getLastName(), a.getLastName()); assertEquals("last name", e.getLastName(), a.getLastName());
assertEquals("password", e.getMd5Password(), a.getMd5Password()); assertEquals("password", e.getArgon2Password(), e.getArgon2Password());
assertEquals("old password", e.getOldPassword(), a.getOldPassword()); assertEquals("old password", e.getOldPassword(), a.getOldPassword());
assertEquals("link expires", e.getPasswordLinkExpires(), assertEquals("link expires", e.getPasswordLinkExpires(),
a.getPasswordLinkExpires()); a.getPasswordLinkExpires());

View file

@ -88,7 +88,7 @@ rootUser.emailAddress = root@myDomain.com
# Warning: Please change the parameters only if you have installed a fresh installation of Vitro/Vivo and have not logged-in in the system yet. # Warning: Please change the parameters only if you have installed a fresh installation of Vitro/Vivo and have not logged-in in the system yet.
# If you already have user accounts encrypted through these parameters please do not change them otherwise the existing users would not be able to log-in. # If you already have user accounts encrypted through these parameters please do not change them otherwise the existing users would not be able to log-in.
# #
argon2.parallism = 1 argon2.parallelism =1
argon2.memory = 1024 argon2.memory = 1024
argon2.time = 1000 argon2.time = 1000

View file

@ -77,6 +77,21 @@ VitroConnection.DataSource.validationQuery = SELECT 1
# #
rootUser.emailAddress = root@myDomain.com rootUser.emailAddress = root@myDomain.com
#
# Argon2 password hashing parameters for time, memory and parallelism required to compute a hash.
#
# A time cost defines the amount of computation realized and therefore the execution time, given in a number of iterations
# A memory cost defines the memory usage, given in kibibytes
# A parallelism degree defines the number of parallel threads
# For determining the optimal values of the parameters for your setup please refer to the white paper section 9 - https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
#
# Warning: Please change the parameters only if you have installed a fresh installation of Vitro/Vivo and have not logged-in in the system yet.
# If you already have user accounts encrypted through these parameters please do not change them otherwise the existing users would not be able to log-in.
#
argon2.parallelism =1
argon2.memory = 1024
argon2.time = 1000
# #
# How is a logged-in user associated with a particular Individual? One way is # How is a logged-in user associated with a particular Individual? One way is
# for the Individual to have a property whose value is the username of the user. # for the Individual to have a property whose value is the username of the user.