IDEMPIERE-375 Implement Forgot my Password

This commit is contained in:
Carlos Ruiz 2012-09-11 17:05:42 -05:00
parent 7c7a3d9464
commit 42eb30488f
11 changed files with 107 additions and 107 deletions

View File

@ -103,16 +103,6 @@ INSERT INTO AD_Message (MsgType,MsgText,AD_Message_ID,EntityType,AD_Message_UU,V
INSERT INTO AD_Message_Trl (AD_Language,AD_Message_ID, MsgText,MsgTip, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy,AD_Message_Trl_UU ) SELECT l.AD_Language,t.AD_Message_ID, t.MsgText,t.MsgTip, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy,Generate_UUID() FROM AD_Language l, AD_Message t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Message_ID=200045 AND NOT EXISTS (SELECT * FROM AD_Message_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Message_ID=t.AD_Message_ID)
;
-- Sep 10, 2012 5:20:40 PM SGT
-- IDEMPIERE-375 Implement Forgot my Password
INSERT INTO AD_Message (MsgType,MsgText,AD_Message_ID,EntityType,AD_Message_UU,Value,IsActive,Updated,CreatedBy,UpdatedBy,AD_Client_ID,AD_Org_ID,Created) VALUES ('I','Answer',200046,'D','494db2ce-7749-4f52-82a1-d7e9448ab864','Answer','Y',TO_DATE('2012-09-10 17:20:40','YYYY-MM-DD HH24:MI:SS'),100,100,0,0,TO_DATE('2012-09-10 17:20:40','YYYY-MM-DD HH24:MI:SS'))
;
-- Sep 10, 2012 5:20:46 PM SGT
-- IDEMPIERE-375 Implement Forgot my Password
INSERT INTO AD_Message (MsgType,MsgText,AD_Message_ID,EntityType,AD_Message_UU,Value,IsActive,Updated,CreatedBy,UpdatedBy,AD_Client_ID,AD_Org_ID,Created) VALUES ('I','Answer',200047,'D','397a2656-2199-4451-87fe-5850b54957c0','Answer','Y',TO_DATE('2012-09-10 17:20:45','YYYY-MM-DD HH24:MI:SS'),100,100,0,0,TO_DATE('2012-09-10 17:20:45','YYYY-MM-DD HH24:MI:SS'))
;
-- Sep 10, 2012 5:21:23 PM SGT
-- IDEMPIERE-375 Implement Forgot my Password
INSERT INTO AD_Message (MsgType,MsgText,AD_Message_ID,EntityType,AD_Message_UU,Value,IsActive,Updated,CreatedBy,UpdatedBy,AD_Client_ID,AD_Org_ID,Created) VALUES ('E','Security Question is Mandatory',200048,'D','5c73ed0f-6ca9-45bc-8df7-e85f8bc3471d','SecurityQuestionMandatory','Y',TO_DATE('2012-09-10 17:21:22','YYYY-MM-DD HH24:MI:SS'),100,100,0,0,TO_DATE('2012-09-10 17:21:22','YYYY-MM-DD HH24:MI:SS'))

View File

@ -0,0 +1,8 @@
-- Sep 11, 2012 5:02:55 PM COT
-- IDEMPIERE-375 Implement Forgot my Password
INSERT INTO AD_SysConfig (AD_SysConfig_ID,EntityType,ConfigurationLevel,Value,Description,AD_SysConfig_UU,Created,Updated,AD_Client_ID,AD_Org_ID,CreatedBy,IsActive,UpdatedBy,Name) VALUES (200019,'D','S','Y','Show reset password button on login panel','9b0ac996-a542-44e5-9777-a284402a9788',TO_DATE('2012-09-11 17:02:54','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2012-09-11 17:02:54','YYYY-MM-DD HH24:MI:SS'),0,0,100,'Y',100,'LOGIN_SHOW_RESETPASSWORD')
;
SELECT register_migration_script('909_IDEMPIERE-375.sql') FROM dual
;

View File

@ -103,16 +103,6 @@ INSERT INTO AD_Message (MsgType,MsgText,AD_Message_ID,EntityType,AD_Message_UU,V
INSERT INTO AD_Message_Trl (AD_Language,AD_Message_ID, MsgText,MsgTip, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy,AD_Message_Trl_UU ) SELECT l.AD_Language,t.AD_Message_ID, t.MsgText,t.MsgTip, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy,Generate_UUID() FROM AD_Language l, AD_Message t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Message_ID=200045 AND NOT EXISTS (SELECT * FROM AD_Message_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Message_ID=t.AD_Message_ID)
;
-- Sep 10, 2012 5:20:40 PM SGT
-- IDEMPIERE-375 Implement Forgot my Password
INSERT INTO AD_Message (MsgType,MsgText,AD_Message_ID,EntityType,AD_Message_UU,Value,IsActive,Updated,CreatedBy,UpdatedBy,AD_Client_ID,AD_Org_ID,Created) VALUES ('I','Answer',200046,'D','494db2ce-7749-4f52-82a1-d7e9448ab864','Answer','Y',TO_TIMESTAMP('2012-09-10 17:20:40','YYYY-MM-DD HH24:MI:SS'),100,100,0,0,TO_TIMESTAMP('2012-09-10 17:20:40','YYYY-MM-DD HH24:MI:SS'))
;
-- Sep 10, 2012 5:20:46 PM SGT
-- IDEMPIERE-375 Implement Forgot my Password
INSERT INTO AD_Message (MsgType,MsgText,AD_Message_ID,EntityType,AD_Message_UU,Value,IsActive,Updated,CreatedBy,UpdatedBy,AD_Client_ID,AD_Org_ID,Created) VALUES ('I','Answer',200047,'D','397a2656-2199-4451-87fe-5850b54957c0','Answer','Y',TO_TIMESTAMP('2012-09-10 17:20:45','YYYY-MM-DD HH24:MI:SS'),100,100,0,0,TO_TIMESTAMP('2012-09-10 17:20:45','YYYY-MM-DD HH24:MI:SS'))
;
-- Sep 10, 2012 5:21:23 PM SGT
-- IDEMPIERE-375 Implement Forgot my Password
INSERT INTO AD_Message (MsgType,MsgText,AD_Message_ID,EntityType,AD_Message_UU,Value,IsActive,Updated,CreatedBy,UpdatedBy,AD_Client_ID,AD_Org_ID,Created) VALUES ('E','Security Question is Mandatory',200048,'D','5c73ed0f-6ca9-45bc-8df7-e85f8bc3471d','SecurityQuestionMandatory','Y',TO_TIMESTAMP('2012-09-10 17:21:22','YYYY-MM-DD HH24:MI:SS'),100,100,0,0,TO_TIMESTAMP('2012-09-10 17:21:22','YYYY-MM-DD HH24:MI:SS'))

View File

@ -0,0 +1,8 @@
-- Sep 11, 2012 5:02:55 PM COT
-- IDEMPIERE-375 Implement Forgot my Password
INSERT INTO AD_SysConfig (AD_SysConfig_ID,EntityType,ConfigurationLevel,Value,Description,AD_SysConfig_UU,Created,Updated,AD_Client_ID,AD_Org_ID,CreatedBy,IsActive,UpdatedBy,Name) VALUES (200019,'D','S','Y','Show reset password button on login panel','9b0ac996-a542-44e5-9777-a284402a9788',TO_TIMESTAMP('2012-09-11 17:02:54','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2012-09-11 17:02:54','YYYY-MM-DD HH24:MI:SS'),0,0,100,'Y',100,'LOGIN_SHOW_RESETPASSWORD')
;
SELECT register_migration_script('909_IDEMPIERE-375.sql') FROM dual
;

View File

@ -46,6 +46,7 @@ import edu.vt.middleware.password.NonAlphanumericCharacterRule;
import edu.vt.middleware.password.NumericalSequenceRule;
import edu.vt.middleware.password.Password;
import edu.vt.middleware.password.PasswordData;
import edu.vt.middleware.password.PasswordGenerator;
import edu.vt.middleware.password.PasswordValidator;
import edu.vt.middleware.password.QwertySequenceRule;
import edu.vt.middleware.password.RepeatCharacterRegexRule;
@ -63,7 +64,7 @@ public class MPasswordRule extends X_AD_PasswordRule {
/**
*
*/
private static final long serialVersionUID = -4262842010340413022L;
private static final long serialVersionUID = 7376091524332484101L;
/**
* @param ctx
@ -225,4 +226,44 @@ public class MPasswordRule extends X_AD_PasswordRule {
return new MessageResolver(props);
}
public String generate() {
CharacterCharacteristicsRule charRule = new CharacterCharacteristicsRule();
int numValidations = 0;
if (getDigitCharacter() > 0) {
// require at least n digit in passwords
numValidations++;
charRule.getRules().add(new DigitCharacterRule(getDigitCharacter()));
}
if (getNonAlphaNumericCharacter() > 0) {
// require at least n non-alphanumeric char
numValidations++;
charRule.getRules().add(new NonAlphanumericCharacterRule(getNonAlphaNumericCharacter()));
}
if (getUppercaseCharacter() > 0) {
numValidations++;
charRule.getRules().add(new UppercaseCharacterRule(getUppercaseCharacter()));
}
if (getLowercaseCharacter() > 0) {
numValidations++;
charRule.getRules().add(new LowercaseCharacterRule(getLowercaseCharacter()));
}
if (getAlphabeticalCharacter() > 0){
numValidations++;
charRule.getRules().add(new AlphabeticalCharacterRule(getAlphabeticalCharacter()));
}
if (! charRule.getRules().isEmpty()) {
charRule.setNumberOfCharacteristics(numValidations);
}
int len = 10; // suggested length to generate
if (len < getMinLength()) {
len = getMinLength();
}
if (len > getMaxLength()) {
len = getMaxLength();
}
return new PasswordGenerator().generatePassword(len, charRule.getRules());
}
}

View File

@ -37,7 +37,7 @@ public class MSysConfig extends X_AD_SysConfig
/**
*
*/
private static final long serialVersionUID = -9111154530183645884L;
private static final long serialVersionUID = 5434521728516112616L;
public final static String PDF_FONT_DIR = "PDF_FONT_DIR";
public final static String TWOPACK_HANDLE_TRANSLATIONS = "2PACK_HANDLE_TRANSLATIONS";
@ -50,6 +50,7 @@ public class MSysConfig extends X_AD_SysConfig
public static final String ZK_DASHBOARD_REFRESH_INTERVAL = "ZK_DASHBOARD_REFRESH_INTERVAL";
public static final String RecentItems_MaxShown = "RecentItems_MaxShown";
public static final String USE_EMAIL_FOR_LOGIN = "USE_EMAIL_FOR_LOGIN";
public static final String LOGIN_SHOW_RESETPASSWORD = "LOGIN_SHOW_RESETPASSWORD";
public static final String ALogin_ShowOneRole = "ALogin_ShowOneRole";
public static final String ZK_BROWSER_ICON = "ZK_BROWSER_ICON";
public static final String ZK_BROWSER_TITLE = "ZK_BROWSER_TITLE";

View File

@ -212,13 +212,6 @@ public class MUser extends X_AD_User
clientsValidated.add(user.getAD_Client_ID());
boolean valid = false;
if (hash_password) {
String hash = user.getPassword();
String salt = user.getSalt();
// always do calculation to confuse timing based attacks
if ( hash == null )
hash = "0000000000000000";
if ( salt == null )
salt = "0000000000000000";
valid = user.authenticateHash(password);
} else {
// password not hashed

View File

@ -292,28 +292,12 @@ public class Login
MUser user = MTable.get(m_ctx, MUser.Table_ID).createQuery( where, null).setParameters(app_user).firstOnly(); // throws error if username collision occurs
String hash = null;
String salt = null;
int AD_User_ID = -1;
if (user != null )
{
hash = user.getPassword();
salt = user.getSalt();
}
// always do calculation to confuse timing based attacks
if ( user == null )
user = MUser.get(m_ctx, 0);
if ( hash == null )
hash = "0000000000000000";
if ( salt == null )
salt = "0000000000000000";
if ( user.authenticateHash(app_pwd) )
{
authenticated = true;
AD_User_ID = user.getAD_User_ID();
app_pwd = null;
}
}
@ -1396,13 +1380,6 @@ public class Login
clientsValidated.add(user.getAD_Client_ID());
boolean valid = false;
if (hash_password) {
String hash = user.getPassword();
String salt = user.getSalt();
// always do calculation to confuse timing based attacks
if ( hash == null )
hash = "0000000000000000";
if ( salt == null )
salt = "0000000000000000";
valid = user.authenticateHash(app_pwd);
} else {
// password not hashed

View File

@ -51,12 +51,12 @@ import org.zkoss.zul.Image;
*/
public class ChangePasswordPanel extends Window implements EventListener<Event>
{
/**
/**
*
*/
private static final long serialVersionUID = 5323925843783103350L;
private static final long serialVersionUID = 6055606520280550335L;
private static CLogger logger = CLogger.getCLogger(ChangePasswordPanel.class);
private static CLogger logger = CLogger.getCLogger(ChangePasswordPanel.class);
private LoginWindow wndLogin;
@ -260,7 +260,7 @@ public class ChangePasswordPanel extends Window implements EventListener<Event>
{
if (event.getTarget().getId().equals(ConfirmPanel.A_OK))
{
validateChangePassword();
validateChangePassword();
}
else if (event.getTarget().getId().equals(ConfirmPanel.A_CANCEL))
{
@ -317,23 +317,20 @@ public class ChangePasswordPanel extends Window implements EventListener<Event>
throw new AdempiereException("Could not find user");
}
user.setPassword(newPassword);
user.set_ValueOfColumn("Password", newPassword); // will be hashed and validate on saveEx
user.setIsExpired(false);
user.setSecurityQuestion(securityQuestion);
user.setAnswer(answer);
if (!user.save(trx.getTrxName()))
{
trx.rollback();
throw new AdempiereException("Could not update user");
}
user.saveEx(trx.getTrxName());
}
trx.commit();
}
catch (Exception e)
catch (AdempiereException e)
{
if (trx != null)
trx.rollback();
throw e;
}
finally
{

View File

@ -221,18 +221,20 @@ public class LoginPanel extends Window implements EventListener<Event>
td.appendChild(chkRememberMe);
}
tr = new Tr();
tr.setId("rowResetPassword");
table.appendChild(tr);
td = new Td();
tr.appendChild(td);
td.setSclass(ITheme.LOGIN_LABEL_CLASS);
td.appendChild(new Label(""));
td = new Td();
td.setSclass(ITheme.LOGIN_FIELD_CLASS);
tr.appendChild(td);
td.appendChild(btnResetPassword);
btnResetPassword.addEventListener(Events.ON_CLICK, this);
if (MSysConfig.getBooleanValue(MSysConfig.LOGIN_SHOW_RESETPASSWORD, true)) {
tr = new Tr();
tr.setId("rowResetPassword");
table.appendChild(tr);
td = new Td();
tr.appendChild(td);
td.setSclass(ITheme.LOGIN_LABEL_CLASS);
td.appendChild(new Label(""));
td = new Td();
td.setSclass(ITheme.LOGIN_FIELD_CLASS);
tr.appendChild(td);
td.appendChild(btnResetPassword);
btnResetPassword.addEventListener(Events.ON_CLICK, this);
}
div = new Div();
div.setSclass(ITheme.LOGIN_BOX_FOOTER_CLASS);

View File

@ -34,6 +34,7 @@ import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.window.LoginWindow;
import org.compiere.model.MClient;
import org.compiere.model.MMailText;
import org.compiere.model.MPasswordRule;
import org.compiere.model.MSysConfig;
import org.compiere.model.MUser;
import org.compiere.model.Query;
@ -62,7 +63,7 @@ public class ResetPasswordPanel extends Window implements EventListener<Event>
/**
*
*/
private static final long serialVersionUID = 190270426336225224L;
private static final long serialVersionUID = -657724758165769510L;
private static CLogger logger = CLogger.getCLogger(ResetPasswordPanel.class);
@ -326,14 +327,14 @@ public class ResetPasswordPanel extends Window implements EventListener<Event>
throw new AdempiereException(errMsg);
}
boolean hash_password = MSysConfig.getBooleanValue(MSysConfig.USER_PASSWORD_HASH, false);
StringBuilder sqlUpdate = new StringBuilder("UPDATE AD_User ");
sqlUpdate.append("SET IsExpired='Y', Password=? ");
sqlUpdate.append("WHERE AD_User_ID=? ");
SecureRandom random = new SecureRandom();
String newPassword = BigInteger.probablePrime(50, random).toString(Character.MAX_RADIX);
String newPassword;
MPasswordRule pwdrule = MPasswordRule.getRules(Env.getCtx(), null);
if (pwdrule != null) {
newPassword = pwdrule.generate();
} else {
SecureRandom random = new SecureRandom();
newPassword = BigInteger.probablePrime(50, random).toString(Character.MAX_RADIX);
}
String errorMsg = "";
Trx trx = null;
@ -346,17 +347,9 @@ public class ResetPasswordPanel extends Window implements EventListener<Event>
{
user.set_TrxName(trx.getTrxName());
user.setPassword(newPassword);
if (hash_password)
user.setPassword(user.getPassword());
// use SQL to update the password to skip password rule validation
int no = DB.executeUpdate(sqlUpdate.toString(), new Object[] {user.getPassword(), user.getAD_User_ID()}, false, trx.getTrxName());
if (no <= 0)
{
trx.rollback();
logger.severe("Failed to update user '" + m_userName + "'");
throw new AdempiereException("Failed to update user");
}
user.set_ValueOfColumn("Password", newPassword); // will be hashed and validate on saveEx
user.setIsExpired(true);
user.saveEx();
if (sendEmail(user, newPassword))
logger.fine(user.getEMail());
@ -365,7 +358,7 @@ public class ResetPasswordPanel extends Window implements EventListener<Event>
if (errorMsg.length() > 0)
errorMsg += ", ";
errorMsg += user.getEMail();
logger.warning("Failed to send email to user - " + user.getEMail());
throw new AdempiereException("Failed to send email to user - " + user.getEMail());
}
}
@ -408,7 +401,7 @@ public class ResetPasswordPanel extends Window implements EventListener<Event>
return false;
MMailText mailText = new MMailText(m_ctx, R_MailText_ID, null);
to.setPassword(newPassword);
to.set_ValueOfColumn("Password", newPassword); // will be hashed and validate on saveEx
mailText.setUser(to);
String message = mailText.getMailText(true);
message = Env.parseVariable(message, to, to.get_TrxName(), true);