Merge with aa6c509f154d3cfec350ea4cf1803ac7af982bda
This commit is contained in:
commit
cb10841f6f
|
@ -0,0 +1,78 @@
|
|||
-- 29/06/2011 1:33:27 PM
|
||||
-- -
|
||||
UPDATE AD_Column SET FieldLength=1024,Updated=TO_DATE('2011-06-29 13:33:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=417
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:33:31 PM
|
||||
-- -
|
||||
ALTER TABLE AD_User MODIFY Password NVARCHAR2(1024) DEFAULT NULL
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:34:52 PM
|
||||
-- -
|
||||
INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,Description,EntityType,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,55218,0,'Salt',TO_DATE('2011-06-29 13:34:50','YYYY-MM-DD HH24:MI:SS'),100,'Random data added to improve password hash effectiveness','D','Y','Salt','Salt',TO_DATE('2011-06-29 13:34:50','YYYY-MM-DD HH24:MI:SS'),100)
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:34:52 PM
|
||||
-- -
|
||||
INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=55218 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID)
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:36:39 PM
|
||||
-- -
|
||||
ALTER TABLE AD_User ADD Salt NVARCHAR2(16) DEFAULT NULL
|
||||
;
|
||||
|
||||
|
||||
-- 29/06/2011 1:37:48 PM
|
||||
-- -
|
||||
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,61756,55218,0,10,114,'Salt',TO_DATE('2011-06-29 13:37:47','YYYY-MM-DD HH24:MI:SS'),100,'Random data added to improve password hash effectiveness','D',16,'Y','Y','N','N','N','N','N','N','N','N','N','N','N','Salt',0,TO_DATE('2011-06-29 13:37:47','YYYY-MM-DD HH24:MI:SS'),100,0)
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:37:48 PM
|
||||
-- -
|
||||
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=61756 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
|
||||
;
|
||||
|
||||
|
||||
-- 29/06/2011 4:59:43 PM
|
||||
-- -
|
||||
INSERT INTO AD_Process (AccessLevel,AD_Client_ID,AD_Org_ID,AD_Process_ID,Classname,CopyFromProcess,Created,CreatedBy,Description,EntityType,Help,IsActive,IsBetaFunctionality,IsDirectPrint,IsReport,IsServerProcess,Name,ShowHelp,Statistic_Count,Statistic_Seconds,Updated,UpdatedBy,Value) VALUES ('4',0,0,53259,'org.compiere.process.HashPasswords','N',TO_DATE('2011-06-29 16:59:41','YYYY-MM-DD HH24:MI:SS'),100,'Convert existing plain text/encrypted user passwords to one way hash','D','This process will overwrite existing user passwords with a salted SHA-512 hash of the password so that they cannot be recovered if your database is compromised.
|
||||
(Note: If your password column is currently encrypted, the hash will also be encrypted.)','Y','N','N','N','N','Convert passwords to hashes','Y',0,0,TO_DATE('2011-06-29 16:59:41','YYYY-MM-DD HH24:MI:SS'),100,'AD_User_HashPassword')
|
||||
;
|
||||
|
||||
-- 29/06/2011 4:59:43 PM
|
||||
-- -
|
||||
INSERT INTO AD_Process_Trl (AD_Language,AD_Process_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Process_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Process t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Process_ID=53259 AND NOT EXISTS (SELECT * FROM AD_Process_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Process_ID=t.AD_Process_ID)
|
||||
;
|
||||
|
||||
-- 29/06/2011 5:00:28 PM
|
||||
-- -
|
||||
INSERT INTO AD_Menu (Action,AD_Client_ID,AD_Menu_ID,AD_Org_ID,AD_Process_ID,Created,CreatedBy,EntityType,IsActive,IsCentrallyMaintained,IsReadOnly,IsSOTrx,IsSummary,Name,Updated,UpdatedBy) VALUES ('P',0,53348,0,53259,TO_DATE('2011-06-29 17:00:27','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','Y','N','N','N','Hash Passwords',TO_DATE('2011-06-29 17:00:27','YYYY-MM-DD HH24:MI:SS'),100)
|
||||
;
|
||||
|
||||
-- 29/06/2011 5:00:28 PM
|
||||
-- -
|
||||
INSERT INTO AD_Menu_Trl (AD_Language,AD_Menu_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Menu_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Menu t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Menu_ID=53348 AND NOT EXISTS (SELECT * FROM AD_Menu_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Menu_ID=t.AD_Menu_ID)
|
||||
;
|
||||
|
||||
-- 29/06/2011 5:00:28 PM
|
||||
-- -
|
||||
INSERT INTO AD_TreeNodeMM (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo) SELECT t.AD_Client_ID, 0, 'Y', SysDate, 100, SysDate, 100,t.AD_Tree_ID, 53348, 0, 999 FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='MM' AND NOT EXISTS (SELECT * FROM AD_TreeNodeMM e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=53348)
|
||||
;
|
||||
|
||||
-- 29/06/2011 5:00:53 PM
|
||||
-- -
|
||||
UPDATE AD_TreeNodeMM SET Parent_ID=367, SeqNo=999, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=53348
|
||||
;
|
||||
|
||||
-- Jul 24, 2012 5:50:06 PM COT
|
||||
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 (200013,'D','S','N','Enable hash passwords, please use Hash Password process to enable','569577c3-3bfa-4d0f-a2e3-d98752164667',TO_DATE('2012-07-24 17:50:04','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2012-07-24 17:50:04','YYYY-MM-DD HH24:MI:SS'),0,0,0,'Y',0,'USER_PASSWORD_HASH')
|
||||
;
|
||||
|
||||
UPDATE AD_System
|
||||
SET LastMigrationScriptApplied='854_PasswordHash_IDEMPIERE-347.sql'
|
||||
WHERE LastMigrationScriptApplied<'854_PasswordHash_IDEMPIERE-347.sql'
|
||||
OR LastMigrationScriptApplied IS NULL
|
||||
;
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
-- 29/06/2011 1:33:27 PM
|
||||
-- -
|
||||
UPDATE AD_Column SET FieldLength=1024,Updated=TO_TIMESTAMP('2011-06-29 13:33:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=417
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:33:31 PM
|
||||
-- -
|
||||
INSERT INTO t_alter_column values('ad_user','Password','VARCHAR(1024)',null,'NULL')
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:34:52 PM
|
||||
-- -
|
||||
INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,Description,EntityType,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,55218,0,'Salt',TO_TIMESTAMP('2011-06-29 13:34:50','YYYY-MM-DD HH24:MI:SS'),100,'Random data added to improve password hash effectiveness','D','Y','Salt','Salt',TO_TIMESTAMP('2011-06-29 13:34:50','YYYY-MM-DD HH24:MI:SS'),100)
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:34:52 PM
|
||||
-- -
|
||||
INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=55218 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID)
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:36:39 PM
|
||||
-- -
|
||||
ALTER TABLE AD_User ADD COLUMN Salt VARCHAR(16) DEFAULT NULL
|
||||
;
|
||||
|
||||
|
||||
-- 29/06/2011 1:37:48 PM
|
||||
-- -
|
||||
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,61756,55218,0,10,114,'Salt',TO_TIMESTAMP('2011-06-29 13:37:47','YYYY-MM-DD HH24:MI:SS'),100,'Random data added to improve password hash effectiveness','D',16,'Y','Y','N','N','N','N','N','N','N','N','N','N','N','Salt',0,TO_TIMESTAMP('2011-06-29 13:37:47','YYYY-MM-DD HH24:MI:SS'),100,0)
|
||||
;
|
||||
|
||||
-- 29/06/2011 1:37:48 PM
|
||||
-- -
|
||||
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=61756 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
|
||||
;
|
||||
|
||||
|
||||
-- 29/06/2011 4:59:43 PM
|
||||
-- -
|
||||
INSERT INTO AD_Process (AccessLevel,AD_Client_ID,AD_Org_ID,AD_Process_ID,Classname,CopyFromProcess,Created,CreatedBy,Description,EntityType,Help,IsActive,IsBetaFunctionality,IsDirectPrint,IsReport,IsServerProcess,Name,ShowHelp,Statistic_Count,Statistic_Seconds,Updated,UpdatedBy,Value) VALUES ('4',0,0,53259,'org.compiere.process.HashPasswords','N',TO_TIMESTAMP('2011-06-29 16:59:41','YYYY-MM-DD HH24:MI:SS'),100,'Convert existing plain text/encrypted user passwords to one way hash','D','This process will overwrite existing user passwords with a salted SHA-512 hash of the password so that they cannot be recovered if your database is compromised.
|
||||
(Note: If your password column is currently encrypted, the hash will also be encrypted.)','Y','N','N','N','N','Convert passwords to hashes','Y',0,0,TO_TIMESTAMP('2011-06-29 16:59:41','YYYY-MM-DD HH24:MI:SS'),100,'AD_User_HashPassword')
|
||||
;
|
||||
|
||||
-- 29/06/2011 4:59:43 PM
|
||||
-- -
|
||||
INSERT INTO AD_Process_Trl (AD_Language,AD_Process_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Process_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Process t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Process_ID=53259 AND NOT EXISTS (SELECT * FROM AD_Process_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Process_ID=t.AD_Process_ID)
|
||||
;
|
||||
|
||||
-- 29/06/2011 5:00:28 PM
|
||||
-- -
|
||||
INSERT INTO AD_Menu (Action,AD_Client_ID,AD_Menu_ID,AD_Org_ID,AD_Process_ID,Created,CreatedBy,EntityType,IsActive,IsCentrallyMaintained,IsReadOnly,IsSOTrx,IsSummary,Name,Updated,UpdatedBy) VALUES ('P',0,53348,0,53259,TO_TIMESTAMP('2011-06-29 17:00:27','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','Y','N','N','N','Hash Passwords',TO_TIMESTAMP('2011-06-29 17:00:27','YYYY-MM-DD HH24:MI:SS'),100)
|
||||
;
|
||||
|
||||
-- 29/06/2011 5:00:28 PM
|
||||
-- -
|
||||
INSERT INTO AD_Menu_Trl (AD_Language,AD_Menu_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Menu_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Menu t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Menu_ID=53348 AND NOT EXISTS (SELECT * FROM AD_Menu_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Menu_ID=t.AD_Menu_ID)
|
||||
;
|
||||
|
||||
-- 29/06/2011 5:00:28 PM
|
||||
-- -
|
||||
INSERT INTO AD_TreeNodeMM (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo) SELECT t.AD_Client_ID, 0, 'Y', CURRENT_TIMESTAMP, 100, CURRENT_TIMESTAMP, 100,t.AD_Tree_ID, 53348, 0, 999 FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='MM' AND NOT EXISTS (SELECT * FROM AD_TreeNodeMM e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=53348)
|
||||
;
|
||||
|
||||
-- 29/06/2011 5:00:53 PM
|
||||
-- -
|
||||
UPDATE AD_TreeNodeMM SET Parent_ID=367, SeqNo=999, Updated=CURRENT_TIMESTAMP WHERE AD_Tree_ID=10 AND Node_ID=53348
|
||||
;
|
||||
|
||||
-- Jul 24, 2012 5:50:06 PM COT
|
||||
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 (200013,'D','S','N','Enable hash passwords, please use Hash Password process to enable','569577c3-3bfa-4d0f-a2e3-d98752164667',TO_TIMESTAMP('2012-07-24 17:50:04','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2012-07-24 17:50:04','YYYY-MM-DD HH24:MI:SS'),0,0,0,'Y',0,'USER_PASSWORD_HASH')
|
||||
;
|
||||
|
||||
UPDATE AD_System
|
||||
SET LastMigrationScriptApplied='854_PasswordHash_IDEMPIERE-347.sql'
|
||||
WHERE LastMigrationScriptApplied<'854_PasswordHash_IDEMPIERE-347.sql'
|
||||
OR LastMigrationScriptApplied IS NULL
|
||||
;
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/******************************************************************************
|
||||
* Product: Adempiere ERP & CRM Smart Business Solution *
|
||||
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
|
||||
* This program is free software; you can redistribute it and/or modify it *
|
||||
* under the terms version 2 of the GNU General Public License as published *
|
||||
* by the Free Software Foundation. This program is distributed in the hope *
|
||||
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* See the GNU General Public License for more details. *
|
||||
* You should have received a copy of the GNU General Public License along *
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., *
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||
* For the text or an alternative of this public license, you may reach us *
|
||||
* ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
|
||||
* or via info@compiere.org or http://www.compiere.org/license.html *
|
||||
*****************************************************************************/
|
||||
package org.compiere.process;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.adempiere.exceptions.AdempiereException;
|
||||
import org.compiere.model.MSysConfig;
|
||||
import org.compiere.model.MTable;
|
||||
import org.compiere.model.MUser;
|
||||
import org.compiere.model.SystemIDs;
|
||||
|
||||
/**
|
||||
* Hash existing passwords
|
||||
*
|
||||
*/
|
||||
public class HashPasswords extends SvrProcess
|
||||
{
|
||||
/**
|
||||
* Prepare - e.g., get Parameters.
|
||||
*/
|
||||
protected void prepare()
|
||||
{
|
||||
} // prepare
|
||||
|
||||
/**
|
||||
* Perform process.
|
||||
* @return Message
|
||||
* @throws Exception if not successful
|
||||
*/
|
||||
protected String doIt() throws Exception
|
||||
{
|
||||
boolean hash_password = MSysConfig.getBooleanValue("USER_PASSWORD_HASH", false);
|
||||
if (hash_password)
|
||||
throw new AdempiereException("Passwords already hashed");
|
||||
|
||||
String where = " Password IS NOT NULL AND Salt IS NULL ";
|
||||
|
||||
// update the sysconfig key to Y out of trx and reset the cache
|
||||
MSysConfig conf = new MSysConfig(getCtx(), SystemIDs.SYSCONFIG_USER_HASH_PASSWORD, null);
|
||||
conf.setValue("Y");
|
||||
conf.saveEx();
|
||||
MSysConfig.resetCache();
|
||||
|
||||
int count = 0;
|
||||
try {
|
||||
List<MUser> users = MTable.get(getCtx(), MUser.Table_ID).createQuery( where, get_TrxName()).list();
|
||||
for ( MUser user : users )
|
||||
{
|
||||
user.setPassword(user.getPassword());
|
||||
count++;
|
||||
user.saveEx();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// reset to N on exception
|
||||
conf.setValue("N");
|
||||
conf.saveEx();
|
||||
throw e;
|
||||
}
|
||||
|
||||
return "@Updated@ " + count;
|
||||
} // doIt
|
||||
|
||||
} // HashPasswords
|
|
@ -18,8 +18,8 @@ package org.compiere.process;
|
|||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.compiere.model.MSysConfig;
|
||||
import org.compiere.model.MUser;
|
||||
import org.compiere.util.DB;
|
||||
import org.compiere.util.Util;
|
||||
|
||||
/**
|
||||
|
@ -78,7 +78,7 @@ public class UserPassword extends SvrProcess
|
|||
MUser operator = MUser.get(getCtx(), getAD_User_ID());
|
||||
log.fine("User=" + user + ", Operator=" + operator);
|
||||
|
||||
|
||||
boolean hash_password = MSysConfig.getBooleanValue("USER_PASSWORD_HASH", false);
|
||||
|
||||
// Do we need a password ?
|
||||
if (Util.isEmpty(p_OldPassword)) // Password required
|
||||
|
@ -88,31 +88,17 @@ public class UserPassword extends SvrProcess
|
|||
|| !operator.isAdministrator())
|
||||
throw new IllegalArgumentException("@OldPasswordMandatory@");
|
||||
}
|
||||
|
||||
// is entered Password correct ?
|
||||
else if (!p_OldPassword.equals(user.getPassword()))
|
||||
else {
|
||||
if (hash_password){
|
||||
if (!user.authenticateHash(p_OldPassword) )
|
||||
throw new IllegalArgumentException("@OldPasswordNoMatch@");
|
||||
} else{
|
||||
if (!p_OldPassword.equals(user.getPassword()))
|
||||
throw new IllegalArgumentException("@OldPasswordNoMatch@");
|
||||
|
||||
// Change Super User
|
||||
if (p_AD_User_ID == 0)
|
||||
{
|
||||
String sql = "UPDATE AD_User SET Updated=SysDate, UpdatedBy=" + getAD_User_ID();
|
||||
if (!Util.isEmpty(p_NewPassword))
|
||||
sql += ", Password=" + DB.TO_STRING(p_NewPassword);
|
||||
if (!Util.isEmpty(p_NewEMail))
|
||||
sql += ", Email=" + DB.TO_STRING(p_NewEMail);
|
||||
if (!Util.isEmpty(p_NewEMailUser))
|
||||
sql += ", EmailUser=" + DB.TO_STRING(p_NewEMailUser);
|
||||
if (!Util.isEmpty(p_NewEMailUserPW))
|
||||
sql += ", EmailUserPW=" + DB.TO_STRING(p_NewEMailUserPW);
|
||||
sql += " WHERE AD_User_ID=0";
|
||||
if (DB.executeUpdate(sql, get_TrxName()) == 1)
|
||||
return "OK";
|
||||
else
|
||||
return "@Error@";
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
if (!Util.isEmpty(p_NewPassword))
|
||||
user.setPassword(p_NewPassword);
|
||||
if (!Util.isEmpty(p_NewEMail))
|
||||
|
@ -121,13 +107,9 @@ public class UserPassword extends SvrProcess
|
|||
user.setEMailUser(p_NewEMailUser);
|
||||
if (!Util.isEmpty(p_NewEMailUserPW))
|
||||
user.setEMailUserPW(p_NewEMailUserPW);
|
||||
//
|
||||
if (user.save())
|
||||
user.saveEx();
|
||||
|
||||
return "OK";
|
||||
else
|
||||
return "@Error@";
|
||||
}
|
||||
} // doIt
|
||||
|
||||
} // UserPassword
|
||||
|
||||
|
|
|
@ -1443,18 +1443,9 @@ public class GridTable extends AbstractTableModel
|
|||
&& (Env.getAD_User_ID(m_ctx) == USER_SYSTEM || Env.getAD_User_ID(m_ctx) == USER_SUPERUSER) // user must know what is doing -> just allowed to System or SuperUser (Hardcoded)
|
||||
&& getKeyID(m_rowChanged) == 0) { // the record being changed has ID = 0
|
||||
String tablename = getTableName(); // just the allowed tables (HardCoded)
|
||||
if (tablename.equals("AD_Org") ||
|
||||
tablename.equals("AD_ReportView") ||
|
||||
tablename.equals("AD_Role") ||
|
||||
tablename.equals("AD_System") ||
|
||||
tablename.equals("AD_User") ||
|
||||
tablename.equals("C_DocType") ||
|
||||
tablename.equals("GL_Category") ||
|
||||
tablename.equals("M_AttributeSet") ||
|
||||
tablename.equals("M_AttributeSetInstance")) {
|
||||
if (MTable.isZeroIDTable(tablename))
|
||||
specialZeroUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check Mandatory
|
||||
String missingColumns = getMandatory(rowData);
|
||||
|
|
|
@ -459,6 +459,19 @@ public interface I_AD_User
|
|||
/** Get Process Now */
|
||||
public boolean isProcessing();
|
||||
|
||||
/** Column name Salt */
|
||||
public static final String COLUMNNAME_Salt = "Salt";
|
||||
|
||||
/** Set Salt.
|
||||
* Random data added to improve password hash effectiveness
|
||||
*/
|
||||
public void setSalt (String Salt);
|
||||
|
||||
/** Get Salt.
|
||||
* Random data added to improve password hash effectiveness
|
||||
*/
|
||||
public String getSalt();
|
||||
|
||||
/** Column name Supervisor_ID */
|
||||
public static final String COLUMNNAME_Supervisor_ID = "Supervisor_ID";
|
||||
|
||||
|
|
|
@ -50,11 +50,10 @@ import org.compiere.util.DB;
|
|||
*/
|
||||
public class MTable extends X_AD_Table
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -2367316254623142732L;
|
||||
private static final long serialVersionUID = 8264472455498363565L;
|
||||
|
||||
public final static int MAX_OFFICIAL_ID = 999999;
|
||||
|
||||
|
@ -587,4 +586,20 @@ public class MTable extends X_AD_Table
|
|||
return sb.toString ();
|
||||
} // toString
|
||||
|
||||
/**
|
||||
* Verify if the table contains ID=0
|
||||
* @return true if table has zero ID
|
||||
*/
|
||||
public static boolean isZeroIDTable(String tablename) {
|
||||
return (tablename.equals("AD_Org") ||
|
||||
tablename.equals("AD_ReportView") ||
|
||||
tablename.equals("AD_Role") ||
|
||||
tablename.equals("AD_System") ||
|
||||
tablename.equals("AD_User") ||
|
||||
tablename.equals("C_DocType") ||
|
||||
tablename.equals("GL_Category") ||
|
||||
tablename.equals("M_AttributeSet") ||
|
||||
tablename.equals("M_AttributeSetInstance"));
|
||||
}
|
||||
|
||||
} // MTable
|
|
@ -16,6 +16,9 @@
|
|||
*****************************************************************************/
|
||||
package org.compiere.model;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -33,6 +36,7 @@ import org.compiere.util.CCache;
|
|||
import org.compiere.util.CLogger;
|
||||
import org.compiere.util.DB;
|
||||
import org.compiere.util.Env;
|
||||
import org.compiere.util.Secure;
|
||||
import org.compiere.util.SecureEngine;
|
||||
|
||||
/**
|
||||
|
@ -50,7 +54,7 @@ public class MUser extends X_AD_User
|
|||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -5845477151929518375L;
|
||||
private static final long serialVersionUID = -5343496366428193731L;
|
||||
|
||||
/**
|
||||
* Get active Users of BPartner
|
||||
|
@ -167,9 +171,13 @@ public class MUser extends X_AD_User
|
|||
s_log.warning ("Invalid Name/Password = " + name + "/" + password);
|
||||
return null;
|
||||
}
|
||||
boolean hash_password = MSysConfig.getBooleanValue("USER_PASSWORD_HASH", false);
|
||||
MUser retValue = null;
|
||||
if (!hash_password)
|
||||
{
|
||||
int AD_Client_ID = Env.getAD_Client_ID(ctx);
|
||||
|
||||
MUser retValue = null;
|
||||
|
||||
String sql = "SELECT * FROM AD_User "
|
||||
+ "WHERE COALESCE(LDAPUser, Name)=? " // #1
|
||||
+ " AND ((Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='N') " // #2
|
||||
|
@ -204,6 +212,40 @@ public class MUser extends X_AD_User
|
|||
DB.close(rs, pstmt);
|
||||
rs = null; pstmt = null;
|
||||
}
|
||||
} else {
|
||||
String where = " COALESCE(LDAPUser,Name) = ? AND" +
|
||||
" EXISTS (SELECT * FROM AD_User_Roles ur" +
|
||||
" INNER JOIN AD_Role r ON (ur.AD_Role_ID=r.AD_Role_ID)" +
|
||||
" WHERE ur.AD_User_ID=AD_User.AD_User_ID AND ur.IsActive='Y' AND r.IsActive='Y') AND " +
|
||||
" EXISTS (SELECT * FROM AD_Client c" +
|
||||
" WHERE c.AD_Client_ID=AD_User.AD_Client_ID" +
|
||||
" AND c.IsActive='Y') AND " +
|
||||
" AD_User.IsActive='Y'";
|
||||
|
||||
MUser user = MTable.get(ctx, MUser.Table_ID).createQuery( where, null).setParameters(name).firstOnly(); // throws error if username collision occurs
|
||||
|
||||
String hash = null;
|
||||
String salt = null;
|
||||
|
||||
if (user != null )
|
||||
{
|
||||
hash = user.getPassword();
|
||||
salt = user.getSalt();
|
||||
}
|
||||
|
||||
// always do calculation to confuse timing based attacks
|
||||
if ( user == null )
|
||||
user = MUser.get(ctx, 0);
|
||||
if ( hash == null )
|
||||
hash = "0000000000000000";
|
||||
if ( salt == null )
|
||||
salt = "0000000000000000";
|
||||
|
||||
if ( user.authenticateHash(password) )
|
||||
{
|
||||
retValue=user;
|
||||
}
|
||||
}
|
||||
return retValue;
|
||||
} // get
|
||||
|
||||
|
@ -308,6 +350,8 @@ public class MUser extends X_AD_User
|
|||
private Boolean m_isAdministrator = null;
|
||||
/** User Access Rights */
|
||||
private X_AD_UserBPAccess[] m_bpAccess = null;
|
||||
/** Password Hashed **/
|
||||
private boolean hashed = false;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -376,6 +420,77 @@ public class MUser extends X_AD_User
|
|||
return sb.toString ();
|
||||
} // cleanValue
|
||||
|
||||
/**
|
||||
* Convert Password to SHA-512 hash with salt * 1000 iterations https://www.owasp.org/index.php/Hashing_Java
|
||||
* @param password -- plain text password
|
||||
*/
|
||||
@Override
|
||||
public void setPassword(String password) {
|
||||
if ( password == null )
|
||||
{
|
||||
super.setPassword(password);
|
||||
return;
|
||||
}
|
||||
boolean hash_password = MSysConfig.getBooleanValue("USER_PASSWORD_HASH", false);
|
||||
|
||||
if(!hash_password){
|
||||
super.setPassword(password);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( hashed )
|
||||
return;
|
||||
|
||||
hashed = true; // prevents double call from beforeSave
|
||||
|
||||
// Uses a secure Random not a simple Random
|
||||
SecureRandom random;
|
||||
try {
|
||||
random = SecureRandom.getInstance("SHA1PRNG");
|
||||
// Salt generation 64 bits long
|
||||
byte[] bSalt = new byte[8];
|
||||
random.nextBytes(bSalt);
|
||||
// Digest computation
|
||||
String hash;
|
||||
hash = SecureEngine.getSHA512Hash(1000,password,bSalt);
|
||||
|
||||
String sSalt = Secure.convertToHexString(bSalt);
|
||||
super.setPassword(hash);
|
||||
setSalt(sSalt);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
super.setPassword(password);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
super.setPassword(password);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if hashed password matches
|
||||
*/
|
||||
public boolean authenticateHash (String password) {
|
||||
|
||||
String hash = null;
|
||||
String salt = null;
|
||||
|
||||
hash = getPassword();
|
||||
salt = getSalt();
|
||||
|
||||
// always do calculation to prevent timing based attacks
|
||||
if ( hash == null )
|
||||
hash = "0000000000000000";
|
||||
if ( salt == null )
|
||||
salt = "0000000000000000";
|
||||
|
||||
try {
|
||||
return SecureEngine.getSHA512Hash(1000, password, Secure.convertHexString(salt)).equals(hash);
|
||||
} catch (NoSuchAlgorithmException ignored) {
|
||||
log.log(Level.WARNING, "Password hashing not supported by JVM");
|
||||
} catch (UnsupportedEncodingException ignored) {
|
||||
log.log(Level.WARNING, "Password hashing not supported by JVM");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get First Name
|
||||
* @return first name
|
||||
|
@ -801,6 +916,13 @@ public class MUser extends X_AD_User
|
|||
setEMailVerifyDate(null);
|
||||
if (newRecord || super.getValue() == null || is_ValueChanged("Value"))
|
||||
setValue(super.getValue());
|
||||
|
||||
if (newRecord || is_ValueChanged("Password")) {
|
||||
boolean hash_password = MSysConfig.getBooleanValue("USER_PASSWORD_HASH", false);
|
||||
if (hash_password)
|
||||
setPassword(getPassword());
|
||||
}
|
||||
|
||||
return true;
|
||||
} // beforeSave
|
||||
|
||||
|
|
|
@ -1921,6 +1921,8 @@ public abstract class PO
|
|||
continue;
|
||||
return false; // one value is non-zero
|
||||
}
|
||||
if (MTable.isZeroIDTable(get_TableName()))
|
||||
return false;
|
||||
return true;
|
||||
} // is_new
|
||||
|
||||
|
|
|
@ -145,4 +145,6 @@ public interface SystemIDs
|
|||
public final static int WINDOW_SHIPMENT_CUSTOMER = 169;
|
||||
public final static int WINDOW_WAREHOUSE_LOCATOR = 139;
|
||||
public final static int WINDOW_WINDOW_TAB_FIELD = 102;
|
||||
|
||||
public final static int SYSCONFIG_USER_HASH_PASSWORD = 200013;
|
||||
}
|
||||
|
|
|
@ -665,6 +665,25 @@ public class X_AD_User extends PO implements I_AD_User, I_Persistent
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Salt.
|
||||
*
|
||||
* @param Salt
|
||||
* Random data added to improve password hash effectiveness
|
||||
*/
|
||||
public void setSalt(String Salt) {
|
||||
set_ValueNoCheck(COLUMNNAME_Salt, Salt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Salt.
|
||||
*
|
||||
* @return Random data added to improve password hash effectiveness
|
||||
*/
|
||||
public String getSalt() {
|
||||
return (String) get_Value(COLUMNNAME_Salt);
|
||||
}
|
||||
|
||||
public I_AD_User getSupervisor() throws RuntimeException
|
||||
{
|
||||
return (I_AD_User)MTable.get(getCtx(), I_AD_User.Table_Name)
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
*****************************************************************************/
|
||||
package org.compiere.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Principal;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
|
@ -35,8 +37,11 @@ import org.compiere.model.MAcctSchema;
|
|||
import org.compiere.model.MClientInfo;
|
||||
import org.compiere.model.MCountry;
|
||||
import org.compiere.model.MRole;
|
||||
import org.compiere.model.MSysConfig;
|
||||
import org.compiere.model.MSystem;
|
||||
import org.compiere.model.MTable;
|
||||
import org.compiere.model.MTree_Base;
|
||||
import org.compiere.model.MUser;
|
||||
import org.compiere.model.ModelValidationEngine;
|
||||
|
||||
|
||||
|
@ -233,6 +238,7 @@ public class Login
|
|||
private KeyNamePair[] getRoles (String app_user, String app_pwd, boolean force)
|
||||
{
|
||||
log.info("User=" + app_user);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
if (app_user == null)
|
||||
{
|
||||
|
@ -240,7 +246,7 @@ public class Login
|
|||
return null;
|
||||
}
|
||||
|
||||
// Authentification
|
||||
// Authentication
|
||||
boolean authenticated = false;
|
||||
MSystem system = MSystem.get(m_ctx);
|
||||
if (system == null)
|
||||
|
@ -251,40 +257,130 @@ public class Login
|
|||
log.warning("No Apps Password");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (system.isLDAP())
|
||||
{
|
||||
authenticated = system.isLDAP(app_user, app_pwd);
|
||||
if (authenticated)
|
||||
if (authenticated){
|
||||
app_pwd = null;
|
||||
authenticated=true;
|
||||
}
|
||||
|
||||
// if not authenticated, use AD_User as backup
|
||||
}
|
||||
|
||||
boolean hash_password=MSysConfig.getBooleanValue("USER_PASSWORD_HASH", false);
|
||||
KeyNamePair[] retValue = null;
|
||||
ArrayList<KeyNamePair> list = new ArrayList<KeyNamePair>();
|
||||
//
|
||||
|
||||
if(hash_password){
|
||||
// adaxa-pb: try to authenticate using hashed password -- falls back to plain text/encrypted
|
||||
String where = " COALESCE(LDAPUser,Name) = ? AND" +
|
||||
" EXISTS (SELECT * FROM AD_User_Roles ur" +
|
||||
" INNER JOIN AD_Role r ON (ur.AD_Role_ID=r.AD_Role_ID)" +
|
||||
" WHERE ur.AD_User_ID=AD_User.AD_User_ID AND ur.IsActive='Y' AND r.IsActive='Y') AND " +
|
||||
" EXISTS (SELECT * FROM AD_Client c" +
|
||||
" WHERE c.AD_Client_ID=AD_User.AD_Client_ID" +
|
||||
" AND c.IsActive='Y') AND " +
|
||||
" AD_User.IsActive='Y'";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
else{
|
||||
StringBuffer sql = new StringBuffer("SELECT u.AD_User_ID,")
|
||||
.append(" u.ConnectionProfile ")
|
||||
.append(" FROM AD_User u");
|
||||
sql.append(" WHERE COALESCE(u.LDAPUser,u.Name)=?");
|
||||
sql.append(" AND u.IsActive='Y'").append(" AND EXISTS (SELECT * FROM AD_Client c WHERE u.AD_Client_ID=c.AD_Client_ID AND c.IsActive='Y')");
|
||||
|
||||
if (app_pwd != null)
|
||||
sql.append(" AND ((u.Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='N') "
|
||||
+ "OR (u.Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='Y'))"); // #2/3
|
||||
|
||||
PreparedStatement pstmt1=null;
|
||||
ResultSet rs1=null;
|
||||
|
||||
try{
|
||||
pstmt1 = DB.prepareStatement(sql.toString(), null);
|
||||
pstmt1.setString(1, app_user);
|
||||
if (app_pwd != null)
|
||||
{
|
||||
pstmt1.setString(2, app_pwd);
|
||||
pstmt1.setString(3, SecureEngine.encrypt(app_pwd));
|
||||
}
|
||||
rs1 = pstmt1.executeQuery();
|
||||
|
||||
while(rs1.next()){
|
||||
authenticated=true;
|
||||
}
|
||||
|
||||
}catch (Exception ex) {
|
||||
// TODO: handle exception
|
||||
log.log(Level.SEVERE, sql.toString(), ex);
|
||||
log.saveError("DBLogin", ex);
|
||||
retValue = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
DB.close(rs1, pstmt1);
|
||||
rs1 = null; pstmt1 = null;
|
||||
}
|
||||
}
|
||||
|
||||
if(authenticated){
|
||||
StringBuffer sql = new StringBuffer("SELECT u.AD_User_ID, r.AD_Role_ID,r.Name,")
|
||||
.append(" u.ConnectionProfile ")
|
||||
.append("FROM AD_User u")
|
||||
.append(" INNER JOIN AD_User_Roles ur ON (u.AD_User_ID=ur.AD_User_ID AND ur.IsActive='Y')")
|
||||
.append(" INNER JOIN AD_Role r ON (ur.AD_Role_ID=r.AD_Role_ID AND r.IsActive='Y') ")
|
||||
.append("WHERE COALESCE(u.LDAPUser,u.Name)=?") // #1
|
||||
.append(" AND u.IsActive='Y'")
|
||||
.append(" AND EXISTS (SELECT * FROM AD_Client c WHERE u.AD_Client_ID=c.AD_Client_ID AND c.IsActive='Y')");
|
||||
if (app_pwd != null)
|
||||
.append(" INNER JOIN AD_Role r ON (ur.AD_Role_ID=r.AD_Role_ID AND r.IsActive='Y') ");
|
||||
|
||||
sql.append("WHERE COALESCE(u.LDAPUser,u.Name)=?"); // #1
|
||||
|
||||
sql.append(" AND u.IsActive='Y'").append(" AND EXISTS (SELECT * FROM AD_Client c WHERE u.AD_Client_ID=c.AD_Client_ID AND c.IsActive='Y')");
|
||||
|
||||
/* if (app_pwd != null && !hash_password)
|
||||
sql.append(" AND ((u.Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='N') "
|
||||
+ "OR (u.Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='Y'))"); // #2/3
|
||||
+ "OR (u.Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='Y'))"); // #2/3*/
|
||||
|
||||
sql.append(" ORDER BY r.Name");
|
||||
|
||||
PreparedStatement pstmt = null;
|
||||
ResultSet rs = null;
|
||||
try
|
||||
{
|
||||
pstmt = DB.prepareStatement(sql.toString(), null);
|
||||
pstmt.setString(1, app_user);
|
||||
if (app_pwd != null)
|
||||
|
||||
/*if (app_pwd != null && !hash_password)
|
||||
{
|
||||
pstmt.setString(2, app_pwd);
|
||||
pstmt.setString(3, SecureEngine.encrypt(app_pwd));
|
||||
}
|
||||
}*/
|
||||
// execute a query
|
||||
rs = pstmt.executeQuery();
|
||||
|
||||
|
@ -313,7 +409,7 @@ public class Login
|
|||
Env.setContext(m_ctx, "#AD_User_Name", app_user);
|
||||
Env.setContext(m_ctx, "#AD_User_ID", rs.getInt(1));
|
||||
Env.setContext(m_ctx, "#SalesRep_ID", rs.getInt(1));
|
||||
//
|
||||
|
||||
if (Ini.isClient())
|
||||
{
|
||||
if (MSystem.isSwingRememberUserAllowed())
|
||||
|
@ -350,7 +446,9 @@ public class Login
|
|||
retValue = new KeyNamePair[list.size()];
|
||||
list.toArray(retValue);
|
||||
log.fine("User=" + app_user + " - roles #" + retValue.length);
|
||||
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE, sql.toString(), ex);
|
||||
|
@ -363,6 +461,7 @@ public class Login
|
|||
DB.close(rs, pstmt);
|
||||
rs = null; pstmt = null;
|
||||
}
|
||||
}
|
||||
long ms = System.currentTimeMillis () - start;
|
||||
return retValue;
|
||||
} // getRoles
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*****************************************************************************/
|
||||
package org.compiere.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.MessageDigest;
|
||||
|
@ -378,6 +379,30 @@ public class Secure implements SecureInterface
|
|||
return (convertHexString(value) != null);
|
||||
} // isDigest
|
||||
|
||||
/**
|
||||
* Convert String and salt to SHA-512 hash with iterations
|
||||
* https://www.owasp.org/index.php/Hashing_Java
|
||||
*
|
||||
* @param value message
|
||||
* @return HexString of message (length = 128 characters)
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public String getSHA512Hash (int iterations, String value, byte[] salt) throws NoSuchAlgorithmException, UnsupportedEncodingException
|
||||
{
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-512");
|
||||
digest.reset();
|
||||
digest.update(salt);
|
||||
byte[] input = digest.digest(value.getBytes("UTF-8"));
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
digest.reset();
|
||||
input = digest.digest(input);
|
||||
}
|
||||
digest.reset();
|
||||
//
|
||||
return convertToHexString(input);
|
||||
} // getSHA512Hash
|
||||
|
||||
/**
|
||||
* String Representation
|
||||
* @return info
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
*****************************************************************************/
|
||||
package org.compiere.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -70,6 +72,22 @@ public class SecureEngine
|
|||
return s_engine.implementation.getClass().getName();
|
||||
} // getClassName
|
||||
|
||||
/**
|
||||
* Convert String and salt to SHA-512 hash with iterations
|
||||
* https://www.owasp.org/index.php/Hashing_Java
|
||||
*
|
||||
* @param value message
|
||||
* @return HexString of message (length = 128 characters)
|
||||
* @throws UnsupportedEncodingException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public static String getSHA512Hash (int iterations, String value, byte[] salt) throws NoSuchAlgorithmException, UnsupportedEncodingException
|
||||
{
|
||||
if (s_engine == null)
|
||||
init(System.getProperties());
|
||||
return s_engine.implementation.getSHA512Hash(iterations, value, salt);
|
||||
} // getDigest
|
||||
|
||||
/**
|
||||
* Convert String to Digest.
|
||||
* JavaScript version see - http://pajhome.org.uk/crypt/md5/index.html
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
*****************************************************************************/
|
||||
package org.compiere.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
|
@ -126,4 +128,15 @@ public interface SecureInterface
|
|||
*/
|
||||
public boolean isDigest (String value);
|
||||
|
||||
/**
|
||||
* Convert String and salt to SHA-512 hash with iterations
|
||||
* https://www.owasp.org/index.php/Hashing_Java
|
||||
*
|
||||
* @param value message
|
||||
* @return HexString of message (length = 128 characters)
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public String getSHA512Hash (int iterations, String value, byte[] salt) throws NoSuchAlgorithmException, UnsupportedEncodingException;
|
||||
|
||||
} // SecureInterface
|
||||
|
|
|
@ -30,6 +30,8 @@ import org.compiere.model.MBPartner;
|
|||
import org.compiere.model.MBPartnerLocation;
|
||||
import org.compiere.model.MLocation;
|
||||
import org.compiere.model.MRefList;
|
||||
import org.compiere.model.MSysConfig;
|
||||
import org.compiere.model.MTable;
|
||||
import org.compiere.model.MUser;
|
||||
|
||||
/**
|
||||
|
@ -367,6 +369,7 @@ public class WebUser
|
|||
m_loc = new MLocation (m_ctx, 0, null);
|
||||
//
|
||||
log.info("= " + m_bp + " - " + m_bpc);
|
||||
|
||||
} // load
|
||||
|
||||
/**
|
||||
|
@ -669,8 +672,84 @@ public class WebUser
|
|||
public boolean login (String password)
|
||||
{
|
||||
m_loggedIn = isValid () // we have a contact
|
||||
&& WebUtil.exists (password) // we have a password
|
||||
&& password.equals (getPassword ());
|
||||
&& WebUtil.exists (password); // we have a password
|
||||
//&& password.equals (getPassword ());
|
||||
boolean retValue = false;
|
||||
if(m_loggedIn)
|
||||
{
|
||||
boolean hash_password=MSysConfig.getBooleanValue("USER_PASSWORD_HASH", false);
|
||||
if(!hash_password)
|
||||
{
|
||||
String sql = "SELECT * FROM AD_User "
|
||||
+ "WHERE COALESCE(LDAPUser, Name)=? " // #1
|
||||
+ " AND ((Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='N') " // #2
|
||||
+ "OR (Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='Y'))" // #3
|
||||
+ " AND IsActive='Y' " // #4
|
||||
;
|
||||
PreparedStatement pstmt = null;
|
||||
ResultSet rs = null;
|
||||
try
|
||||
{
|
||||
pstmt = DB.prepareStatement (sql, null);
|
||||
pstmt.setString (1, m_bpc.getName());
|
||||
pstmt.setString (2, password);
|
||||
pstmt.setString (3, SecureEngine.encrypt(password));
|
||||
rs = pstmt.executeQuery ();
|
||||
if (rs.next ())
|
||||
{
|
||||
retValue = true;
|
||||
if (rs.next())
|
||||
log.warning ("More then one user with Name/Password = " + m_bpc.getName());
|
||||
}
|
||||
else
|
||||
log.fine("No record");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.log(Level.SEVERE, sql, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DB.close(rs, pstmt);
|
||||
rs = null; pstmt = null;
|
||||
}
|
||||
}
|
||||
else{
|
||||
String where = " COALESCE(LDAPUser,Name) = ? AND" +
|
||||
" EXISTS (SELECT * FROM AD_User_Roles ur" +
|
||||
" INNER JOIN AD_Role r ON (ur.AD_Role_ID=r.AD_Role_ID)" +
|
||||
" WHERE ur.AD_User_ID=AD_User.AD_User_ID AND ur.IsActive='Y' AND r.IsActive='Y') AND " +
|
||||
" EXISTS (SELECT * FROM AD_Client c" +
|
||||
" WHERE c.AD_Client_ID=AD_User.AD_Client_ID" +
|
||||
" AND c.IsActive='Y') AND " +
|
||||
" AD_User.IsActive='Y'";
|
||||
|
||||
MUser user = MTable.get(m_ctx, MUser.Table_ID).createQuery( where, null).setParameters(m_bpc.getName()).firstOnly(); // throws error if username collision occurs
|
||||
|
||||
String hash = null;
|
||||
String salt = null;
|
||||
|
||||
if (user != null )
|
||||
{
|
||||
hash = user.getPassword();
|
||||
salt = user.getSalt();
|
||||
}
|
||||
|
||||
// always do calculation to confuse timing based attacks
|
||||
if ( user == null )
|
||||
user = MUser.get(null, 0);
|
||||
if ( hash == null )
|
||||
hash = "0000000000000000";
|
||||
if ( salt == null )
|
||||
salt = "0000000000000000";
|
||||
|
||||
if ( user.authenticateHash(password) )
|
||||
{
|
||||
retValue=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_loggedIn=m_loggedIn && retValue;
|
||||
setPasswordOK (m_loggedIn, password);
|
||||
log.fine("success=" + m_loggedIn);
|
||||
if (m_loggedIn)
|
||||
|
|
Loading…
Reference in New Issue