IDEMPIERE-613 Column Encryption Enhancement.

This commit is contained in:
Heng Sin Low 2013-02-06 18:03:42 +08:00
parent 11603bc4fe
commit b6af6a3489
14 changed files with 404 additions and 205 deletions

View File

@ -117,7 +117,7 @@ public class ColumnEncryption extends SvrProcess {
if (column.isKey() || column.isParent() || column.isStandardColumn() if (column.isKey() || column.isParent() || column.isStandardColumn()
|| column.isVirtualColumn() || column.isIdentifier() || column.isVirtualColumn() || column.isIdentifier()
|| column.isTranslated() || DisplayType.isLookup(dt) || column.isTranslated() || DisplayType.isLookup(dt)
|| DisplayType.isLOB(dt) || DisplayType.isLOB(dt) || DisplayType.isDate(dt) || DisplayType.isNumeric(dt)
|| "DocumentNo".equalsIgnoreCase(column.getColumnName()) || "DocumentNo".equalsIgnoreCase(column.getColumnName())
|| "Value".equalsIgnoreCase(column.getColumnName()) || "Value".equalsIgnoreCase(column.getColumnName())
|| "Name".equalsIgnoreCase(column.getColumnName())) { || "Name".equalsIgnoreCase(column.getColumnName())) {
@ -126,7 +126,7 @@ public class ColumnEncryption extends SvrProcess {
column.saveEx(); column.saveEx();
} }
StringBuilder msgreturn = new StringBuilder().append(columnName).append(": cannot be encrypted"); StringBuilder msgreturn = new StringBuilder().append(columnName).append(": cannot be encrypted");
return msgreturn.toString(); throw new Exception(msgreturn.toString());
} }
// Start // Start
@ -137,10 +137,10 @@ public class ColumnEncryption extends SvrProcess {
// Test Value // Test Value
if (p_TestValue != null && p_TestValue.length() > 0) { if (p_TestValue != null && p_TestValue.length() > 0) {
String encString = SecureEngine.encrypt(p_TestValue); String encString = SecureEngine.encrypt(p_TestValue, 0);
msglog = new StringBuilder("Encrypted Test Value=").append(encString); msglog = new StringBuilder("Encrypted Test Value=").append(encString);
addLog(0, null, null, msglog.toString()); addLog(0, null, null, msglog.toString());
String clearString = SecureEngine.decrypt(encString); String clearString = SecureEngine.decrypt(encString, 0);
if (p_TestValue.equals(clearString)){ if (p_TestValue.equals(clearString)){
msglog = new StringBuilder("Decrypted=").append(clearString) msglog = new StringBuilder("Decrypted=").append(clearString)
.append(" (same as test value)"); .append(" (same as test value)");
@ -181,7 +181,7 @@ public class ColumnEncryption extends SvrProcess {
.append("Test=").append(testClear.toString()).append(" (").append(p_MaxLength).append(")"); .append("Test=").append(testClear.toString()).append(" (").append(p_MaxLength).append(")");
log.config(msglog.toString()); log.config(msglog.toString());
// //
String encString = SecureEngine.encrypt(testClear.toString()); String encString = SecureEngine.encrypt(testClear.toString(), 0);
int encLength = encString.length(); int encLength = encString.length();
msglog = new StringBuilder("Test Max Length=").append(testClear.length()) msglog = new StringBuilder("Test Max Length=").append(testClear.length())
.append(" -> ").append(encLength); .append(" -> ").append(encLength);
@ -224,7 +224,7 @@ public class ColumnEncryption extends SvrProcess {
// Check if the encryption exceeds the current length. // Check if the encryption exceeds the current length.
int oldLength = column.getFieldLength(); int oldLength = column.getFieldLength();
int newLength = encryptedColumnLength(oldLength); int newLength = encryptedColumnLength(oldLength);
if (newLength > oldLength) if (newLength > oldLength) {
if (changeFieldLength(columnID, columnName, newLength, if (changeFieldLength(columnID, columnName, newLength,
tableName) == -1) { tableName) == -1) {
log.warning("EncryptError [ChangeFieldLength]: " log.warning("EncryptError [ChangeFieldLength]: "
@ -232,6 +232,7 @@ public class ColumnEncryption extends SvrProcess {
+ newLength); + newLength);
throw new Exception(); throw new Exception();
} }
}
// Encrypt column contents. // Encrypt column contents.
if (encryptColumnContents(columnName, column.getAD_Table_ID()) == -1) { if (encryptColumnContents(columnName, column.getAD_Table_ID()) == -1) {
@ -295,7 +296,7 @@ public class ColumnEncryption extends SvrProcess {
StringBuilder idColumnName = new StringBuilder(tableName).append("_ID"); StringBuilder idColumnName = new StringBuilder(tableName).append("_ID");
StringBuilder selectSql = new StringBuilder(); StringBuilder selectSql = new StringBuilder();
selectSql.append("SELECT ").append(idColumnName).append(",").append(columnName); selectSql.append("SELECT ").append(idColumnName).append(",").append(columnName).append(",AD_Client_ID");
selectSql.append(" FROM ").append(tableName); selectSql.append(" FROM ").append(tableName);
selectSql.append(" ORDER BY ").append(idColumnName); selectSql.append(" ORDER BY ").append(idColumnName);
@ -306,32 +307,36 @@ public class ColumnEncryption extends SvrProcess {
PreparedStatement selectStmt = null; PreparedStatement selectStmt = null;
PreparedStatement updateStmt = null; PreparedStatement updateStmt = null;
ResultSet rs = null;
selectStmt = m_conn.prepareStatement(selectSql.toString(),
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); try {
updateStmt = m_conn.prepareStatement(updateSql.toString()); selectStmt = m_conn.prepareStatement(selectSql.toString(),
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = selectStmt.executeQuery(); updateStmt = m_conn.prepareStatement(updateSql.toString());
for (recordsEncrypted = 0; rs.next(); ++recordsEncrypted) { rs = selectStmt.executeQuery();
// Get the row id and column value
int id = rs.getInt(1); for (recordsEncrypted = 0; rs.next(); ++recordsEncrypted) {
String value = rs.getString(2); // Get the row id and column value
// Encrypt the value int id = rs.getInt(1);
value = SecureEngine.encrypt(value); String value = rs.getString(2);
// Update the row int AD_Client_ID = rs.getInt(3);
updateStmt.setString(1, value); // Encrypt the value
updateStmt.setInt(2, id); value = SecureEngine.encrypt(value, AD_Client_ID);
if (updateStmt.executeUpdate() != 1) { // Update the row
log.warning("EncryptError: Table=" + tableName + ", ID=" + id); updateStmt.setString(1, value);
throw new Exception(); updateStmt.setInt(2, id);
if (updateStmt.executeUpdate() != 1) {
log.severe("EncryptError: Table=" + tableName + ", ID=" + id);
throw new Exception();
}
} }
} finally {
DB.close(rs);
DB.close(selectStmt);
DB.close(updateStmt);
} }
rs.close();
selectStmt.close();
updateStmt.close();
return recordsEncrypted; return recordsEncrypted;
} // encryptColumnContents } // encryptColumnContents
@ -348,7 +353,7 @@ public class ColumnEncryption extends SvrProcess {
for (int i = 0; i < colLength; i++) { for (int i = 0; i < colLength; i++) {
str.append("1"); str.append("1");
} }
str = new StringBuilder().append(SecureEngine.encrypt(str.toString())); str = new StringBuilder().append(SecureEngine.encrypt(str.toString(), 0));
return str.length(); return str.length();
} // encryptedColumnLength } // encryptedColumnLength
@ -387,34 +392,36 @@ public class ColumnEncryption extends SvrProcess {
updateSql.append(" WHERE AD_Column_ID=").append(columnID); updateSql.append(" WHERE AD_Column_ID=").append(columnID);
PreparedStatement selectStmt = null; PreparedStatement selectStmt = null;
ResultSet rs = null;
selectStmt = m_conn.prepareStatement(selectSql.toString(),
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); try {
selectStmt = m_conn.prepareStatement(selectSql.toString(),
selectStmt.setInt(1, columnID); ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = selectStmt.executeQuery();
selectStmt.setInt(1, columnID);
if (rs.next()) { rs = selectStmt.executeQuery();
// Change the column size physically.
if (DB.executeUpdate(alterSql.toString(), false, m_trx if (rs.next()) {
.getTrxName()) == -1) { // Change the column size physically.
log.warning("EncryptError [ChangeFieldLength]: ColumnID=" if (DB.executeUpdate(alterSql.toString(), false, m_trx
+ columnID + ", NewLength=" + length); .getTrxName()) == -1) {
throw new Exception(); log.severe("EncryptError [ChangeFieldLength]: ColumnID="
} + columnID + ", NewLength=" + length);
throw new Exception();
// Change the column size in AD. }
if (DB.executeUpdate(updateSql.toString(), false, m_trx
.getTrxName()) == -1) { // Change the column size in AD.
log.warning("EncryptError [ChangeFieldLength]: ColumnID=" if (DB.executeUpdate(updateSql.toString(), false, m_trx
+ columnID + ", NewLength=" + length); .getTrxName()) == -1) {
throw new Exception(); log.severe("EncryptError [ChangeFieldLength]: ColumnID="
+ columnID + ", NewLength=" + length);
throw new Exception();
}
} }
} finally {
DB.close(rs, selectStmt);
} }
rs.close();
selectStmt.close();
// Update number of rows effected. // Update number of rows effected.
rowsEffected++; rowsEffected++;

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.adempiere.base.keystore.default">
<implementation class="org.compiere.util.DefaultKeyStore"/>
<service>
<provide interface="org.adempiere.base.IKeyStore"/>
</service>
</scr:component>

View File

@ -104,6 +104,14 @@ public class Core {
return Service.locator().locate(ModelValidator.class, "org.adempiere.base.ModelValidator", serviceId, null).getService(); return Service.locator().locate(ModelValidator.class, "org.adempiere.base.ModelValidator", serviceId, null).getService();
} }
/**
*
* @return keystore
*/
public static IKeyStore getKeyStore(){
return Service.locator().locate(IKeyStore.class).getService();
}
/** /**
* Get payment processor instance * Get payment processor instance
* @param mbap payment processor model * @param mbap payment processor model

View File

@ -0,0 +1,39 @@
/******************************************************************************
* Copyright (C) 2013 Deepak *
* Copyright (C) 2013 Trek Global *
* 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. *
*****************************************************************************/
package org.adempiere.base;
import javax.crypto.SecretKey;
/**
*
* @author deepak
*
*/
public interface IKeyStore {
/**
*
* @param AD_Client_ID
* @return secret key
*/
public SecretKey getKey(int AD_Client_ID);
/**
* @return encryption algorithm id, for e.g AES
*/
public String getAlgorithm();
}

View File

@ -1814,7 +1814,7 @@ public class GridTable extends AbstractTableModel
else else
iii = new Integer(dd.toString()); iii = new Integer(dd.toString());
if (encrypted) if (encrypted)
iii = (Integer)encrypt(iii); iii = (Integer)encrypt(iii, getAD_Client_ID());
if (manualUpdate) if (manualUpdate)
createUpdateSql (columnName, String.valueOf (iii)); createUpdateSql (columnName, String.valueOf (iii));
else else
@ -1834,7 +1834,7 @@ public class GridTable extends AbstractTableModel
{ {
BigDecimal bd = (BigDecimal)rowData[col]; BigDecimal bd = (BigDecimal)rowData[col];
if (encrypted) if (encrypted)
bd = (BigDecimal)encrypt(bd); bd = (BigDecimal)encrypt(bd, getAD_Client_ID());
if (manualUpdate) if (manualUpdate)
createUpdateSql (columnName, bd.toString ()); createUpdateSql (columnName, bd.toString ());
else else
@ -1846,7 +1846,7 @@ public class GridTable extends AbstractTableModel
{ {
Timestamp ts = (Timestamp)rowData[col]; Timestamp ts = (Timestamp)rowData[col];
if (encrypted) if (encrypted)
ts = (Timestamp)encrypt(ts); ts = (Timestamp)encrypt(ts, getAD_Client_ID());
if (manualUpdate) if (manualUpdate)
createUpdateSql (columnName, DB.TO_DATE (ts, false)); createUpdateSql (columnName, DB.TO_DATE (ts, false));
else else
@ -1884,7 +1884,7 @@ public class GridTable extends AbstractTableModel
{ {
String str = rowData[col].toString (); String str = rowData[col].toString ();
if (encrypted) if (encrypted)
str = (String)encrypt(str); str = (String)encrypt(str, getAD_Client_ID());
if (manualUpdate) if (manualUpdate)
createUpdateSql (columnName, DB.TO_STRING (str)); createUpdateSql (columnName, DB.TO_STRING (str));
else else
@ -3121,7 +3121,7 @@ public class GridTable extends AbstractTableModel
{ {
String str = rs.getString(j+1); String str = rs.getString(j+1);
if (field.isEncryptedColumn()) if (field.isEncryptedColumn())
str = (String)decrypt(str); str = (String)decrypt(str, getAD_Client_ID());
rowData[j] = new Boolean ("Y".equals(str)); // Boolean rowData[j] = new Boolean ("Y".equals(str)); // Boolean
} }
// LOB // LOB
@ -3152,7 +3152,7 @@ public class GridTable extends AbstractTableModel
rowData[j] = rs.getString(j+1); // String rowData[j] = rs.getString(j+1); // String
// Encrypted // Encrypted
if (field.isEncryptedColumn() && displayType != DisplayType.YesNo) if (field.isEncryptedColumn() && displayType != DisplayType.YesNo)
rowData[j] = decrypt(rowData[j]); rowData[j] = decrypt(rowData[j], getAD_Client_ID());
} }
} }
catch (SQLException e) catch (SQLException e)
@ -3167,11 +3167,11 @@ public class GridTable extends AbstractTableModel
* @param xx clear data * @param xx clear data
* @return encrypted value * @return encrypted value
*/ */
private Object encrypt (Object xx) private Object encrypt (Object xx, int AD_Client_ID)
{ {
if (xx == null) if (xx == null)
return null; return null;
return SecureEngine.encrypt(xx); return SecureEngine.encrypt(xx, AD_Client_ID);
} // encrypt } // encrypt
/** /**
@ -3179,13 +3179,23 @@ public class GridTable extends AbstractTableModel
* @param yy encrypted data * @param yy encrypted data
* @return clear data * @return clear data
*/ */
private Object decrypt (Object yy) private Object decrypt (Object yy, int AD_Client_ID)
{ {
if (yy == null) if (yy == null)
return null; return null;
return SecureEngine.decrypt(yy); return SecureEngine.decrypt(yy, AD_Client_ID);
} // decrypt } // decrypt
private int getAD_Client_ID()
{
int AD_Client_ID = Env.getAD_Client_ID(Env.getCtx());
GridField field = getField("AD_Client_ID");
if (field != null && field.getValue() != null) {
AD_Client_ID = ((Number)field.getValue()).intValue();
}
return AD_Client_ID;
}
/************************************************************************** /**************************************************************************
* Remove Data Status Listener * Remove Data Status Listener
* @param l listener * @param l listener

View File

@ -3020,8 +3020,9 @@ public abstract class PO
{ {
if (xx == null) if (xx == null)
return null; return null;
if (index != -1 && p_info.isEncrypted(index)) if (index != -1 && p_info.isEncrypted(index)) {
return SecureEngine.encrypt(xx); return SecureEngine.encrypt(xx, getAD_Client_ID());
}
return xx; return xx;
} // encrypt } // encrypt
@ -3035,8 +3036,9 @@ public abstract class PO
{ {
if (yy == null) if (yy == null)
return null; return null;
if (index != -1 && p_info.isEncrypted(index)) if (index != -1 && p_info.isEncrypted(index)) {
return SecureEngine.decrypt(yy); return SecureEngine.decrypt(yy, getAD_Client_ID());
}
return yy; return yy;
} // decrypt } // decrypt

View File

@ -0,0 +1,137 @@
/******************************************************************************
* Copyright (C) 2013 Deepak *
* Copyright (C) 2013 Heng Sin Low *
* Copyright (C) 2013 Trek Global *
* 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. *
*****************************************************************************/
package org.compiere.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.KeyStore.PasswordProtection;
import java.security.KeyStore.SecretKeyEntry;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import org.adempiere.base.IKeyStore;
/**
* @author deepak
* @author hengsin
*
*/
public class DefaultKeyStore implements IKeyStore {
private static final String LEGACY_ALGORITHM = "DES";
private static final String IDEMPIERE_KEYSTORE_PROPERTIES = "idempiere-ks.properties";
private static final String IDEMPIERE_KEYSTORE = "idempiere.ks";
/** Logger */
private static Logger log = Logger.getLogger (DefaultKeyStore.class.getName());
/** Adempiere Key */
private SecretKey m_key = null;
private KeyStore keyStore;
private char[] password = null;
private String algorithm;
public DefaultKeyStore(){
File file = new File(Ini.getAdempiereHome(), IDEMPIERE_KEYSTORE_PROPERTIES);
if (file.exists()) {
try{
Properties p = new Properties();
p.load(new FileInputStream(file));
String s = p.getProperty("password");
String a = p.getProperty("algorithm");
if (!Util.isEmpty(s) && !Util.isEmpty(a)) {
password = s.toCharArray();
algorithm = a;
keyStore = KeyStore.getInstance("JCEKS");
file = new File(Ini.getAdempiereHome(), IDEMPIERE_KEYSTORE);
if (file.exists()) {
FileInputStream stream = new FileInputStream(file);
keyStore.load(stream, password );
} else {
keyStore.load(null, password );
}
} else {
createLegacyKey();
}
} catch (Exception ex) {
log.log(Level.SEVERE, "", ex);
password = null;
createLegacyKey();
}
} else {
createLegacyKey();
}
}
private void createLegacyKey() {
m_key = new javax.crypto.spec.SecretKeySpec
(new byte[] {100,25,28,-122,-26,94,-3,-26}, LEGACY_ALGORITHM);
}
@Override
public SecretKey getKey(int AD_Client_ID) {
if (password != null) {
try {
PasswordProtection protParam = new PasswordProtection(password);
String alias = "ad_client_"+AD_Client_ID;
SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(alias, protParam);
if (entry == null) {
KeyGenerator generator = KeyGenerator.getInstance(algorithm);
SecretKey key = generator.generateKey();
entry = new SecretKeyEntry((SecretKey) key);
keyStore.setEntry(alias, entry, protParam);
File file = new File(IDEMPIERE_KEYSTORE);
FileOutputStream stream = null;
try {
stream = new FileOutputStream(file);
keyStore.store(stream, password);
stream.flush();
} finally {
if (stream != null) {
try {
stream.close();
} catch (Exception e) {}
}
}
}
return entry.getSecretKey();
} catch (Exception ex) {
log.log(Level.SEVERE, "", ex);
}
}
return m_key;
}
@Override
public String getAlgorithm() {
if (algorithm == null)
return LEGACY_ALGORITHM;
else
return algorithm;
}
}

View File

@ -515,7 +515,7 @@ public final class Ini implements Serializable
else if (!isClient()) else if (!isClient())
result = s_prop.getProperty (key, SecureInterface.CLEARVALUE_START + defaultValue + SecureInterface.CLEARVALUE_END); result = s_prop.getProperty (key, SecureInterface.CLEARVALUE_START + defaultValue + SecureInterface.CLEARVALUE_END);
else else
result = s_prop.getProperty (key, SecureEngine.encrypt(defaultValue)); result = s_prop.getProperty (key, SecureEngine.encrypt(defaultValue, 0));
s_prop.setProperty (key, result); s_prop.setProperty (key, result);
return result; return result;
} // checkProperty } // checkProperty
@ -577,7 +577,7 @@ public final class Ini implements Serializable
s_prop.setProperty(key, ""); s_prop.setProperty(key, "");
else else
{ {
String eValue = SecureEngine.encrypt(value); String eValue = SecureEngine.encrypt(value, 0);
if (eValue == null) if (eValue == null)
s_prop.setProperty(key, ""); s_prop.setProperty(key, "");
else else
@ -619,7 +619,7 @@ public final class Ini implements Serializable
if (retStr == null || retStr.length() == 0) if (retStr == null || retStr.length() == 0)
return ""; return "";
// //
String value = SecureEngine.decrypt(retStr); String value = SecureEngine.decrypt(retStr, 0);
// getLogger().finer(key + "=" + value); // getLogger().finer(key + "=" + value);
if (value == null) if (value == null)
return ""; return "";

View File

@ -304,35 +304,27 @@ public class Login
if ( user.authenticateHash(app_pwd) ) if ( user.authenticateHash(app_pwd) )
{ {
authenticated = true; authenticated = true;
app_pwd = null;
} }
} }
else{ else{
StringBuffer sql = new StringBuffer("SELECT AD_User.AD_User_ID,") StringBuffer sql = new StringBuffer("SELECT AD_User.AD_User_ID ").append(" FROM AD_User ");
.append(" AD_User.ConnectionProfile ")
.append(" FROM AD_User ");
sql.append(" WHERE ").append(userNameCol).append("=?"); sql.append(" WHERE ").append(userNameCol).append("=?");
sql.append(" AND AD_User.IsActive='Y'").append(" AND EXISTS (SELECT * FROM AD_Client c WHERE AD_User.AD_Client_ID=c.AD_Client_ID AND c.IsActive='Y')"); sql.append(" AND AD_User.IsActive='Y'").append(" AND EXISTS (SELECT * FROM AD_Client c WHERE AD_User.AD_Client_ID=c.AD_Client_ID AND c.IsActive='Y')");
if (app_pwd != null)
sql.append(" AND ((AD_User.Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='N') "
+ "OR (AD_User.Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='Y'))"); // #2/3
PreparedStatement pstmt1=null; PreparedStatement pstmt1=null;
ResultSet rs1=null; ResultSet rs1=null;
try{ try{
pstmt1 = DB.prepareStatement(sql.toString(), null); pstmt1 = DB.prepareStatement(sql.toString(), null);
pstmt1.setString(1, app_user); pstmt1.setString(1, app_user);
if (app_pwd != null)
{
pstmt1.setString(2, app_pwd);
pstmt1.setString(3, SecureEngine.encrypt(app_pwd));
}
rs1 = pstmt1.executeQuery(); rs1 = pstmt1.executeQuery();
while(rs1.next()){ while(rs1.next()){
authenticated=true; MUser user = new MUser(m_ctx, rs1.getInt(1), null);
if (user.getPassword() != null && user.getPassword().equals(app_pwd)) {
authenticated=true;
}
} }
}catch (Exception ex) { }catch (Exception ex) {
@ -349,9 +341,8 @@ public class Login
} }
if(authenticated){ if(authenticated){
StringBuffer sql = new StringBuffer("SELECT AD_User.AD_User_ID, r.AD_Role_ID,r.Name,") StringBuffer sql = new StringBuffer("SELECT AD_User.AD_User_ID, r.AD_Role_ID,r.Name")
.append(" AD_User.ConnectionProfile ") .append(" FROM AD_User ")
.append("FROM AD_User ")
.append(" INNER JOIN AD_User_Roles ur ON (AD_User.AD_User_ID=ur.AD_User_ID AND ur.IsActive='Y')") .append(" INNER JOIN AD_User_Roles ur ON (AD_User.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(" INNER JOIN AD_Role r ON (ur.AD_Role_ID=r.AD_Role_ID AND r.IsActive='Y') ");
@ -359,10 +350,6 @@ public class Login
sql.append(" AND AD_User.IsActive='Y'").append(" AND EXISTS (SELECT * FROM AD_Client c WHERE AD_User.AD_Client_ID=c.AD_Client_ID AND c.IsActive='Y')"); sql.append(" AND AD_User.IsActive='Y'").append(" AND EXISTS (SELECT * FROM AD_Client c WHERE AD_User.AD_Client_ID=c.AD_Client_ID AND c.IsActive='Y')");
/* if (app_pwd != null && !hash_password)
sql.append(" AND ((AD_User.Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='N') "
+ "OR (AD_User.Password=? AND (SELECT IsEncrypted FROM AD_Column WHERE AD_Column_ID=417)='Y'))"); // #2/3*/
sql.append(" ORDER BY r.Name"); sql.append(" ORDER BY r.Name");
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
@ -372,11 +359,6 @@ public class Login
pstmt = DB.prepareStatement(sql.toString(), null); pstmt = DB.prepareStatement(sql.toString(), null);
pstmt.setString(1, app_user); pstmt.setString(1, app_user);
/*if (app_pwd != null && !hash_password)
{
pstmt.setString(2, app_pwd);
pstmt.setString(3, SecureEngine.encrypt(app_pwd));
}*/
// execute a query // execute a query
rs = pstmt.executeQuery(); rs = pstmt.executeQuery();
@ -413,13 +395,16 @@ public class Login
} }
do // read all roles do // read all roles
{ {
int AD_Role_ID = rs.getInt(2); MUser user = new MUser(m_ctx, rs.getInt(1), null);
if (AD_Role_ID == 0) if (user.getPassword() != null && user.getPassword().equals(app_pwd)) {
Env.setContext(m_ctx, "#SysAdmin", "Y"); int AD_Role_ID = rs.getInt(2);
String Name = rs.getString(3); if (AD_Role_ID == 0)
KeyNamePair p = new KeyNamePair(AD_Role_ID, Name); Env.setContext(m_ctx, "#SysAdmin", "Y");
list.add(p); String Name = rs.getString(3);
KeyNamePair p = new KeyNamePair(AD_Role_ID, Name);
list.add(p);
}
} }
while (rs.next()); while (rs.next());
// //
@ -440,6 +425,7 @@ public class Login
{ {
DB.close(rs, pstmt); DB.close(rs, pstmt);
rs = null; pstmt = null; rs = null; pstmt = null;
app_pwd = null;
} }
} }
//long ms = System.currentTimeMillis () - start; //long ms = System.currentTimeMillis () - start;
@ -1333,7 +1319,7 @@ public class Login
valid = user.authenticateHash(app_pwd); valid = user.authenticateHash(app_pwd);
} else { } else {
// password not hashed // password not hashed
valid = user.getPassword().equals(app_pwd); valid = user.getPassword() != null && user.getPassword().equals(app_pwd);
} }
if (valid ) { if (valid ) {
if (user.isLocked()) if (user.isLocked())

View File

@ -26,7 +26,9 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import org.adempiere.base.Core;
import org.adempiere.base.IKeyStore;
/** /**
* Security Services. * Security Services.
@ -128,14 +130,11 @@ public class Secure implements SecureInterface
{ {
initCipher(); initCipher();
} // Secure } // Secure
/** Adempiere Cipher */
private Cipher m_cipher = null;
/** Adempiere Key */
private SecretKey m_key = null;
/** Message Digest */ /** Message Digest */
private MessageDigest m_md = null; private MessageDigest m_md = null;
private IKeyStore m_keyStore = null;
/** Logger */ /** Logger */
private static Logger log = Logger.getLogger (Secure.class.getName()); private static Logger log = Logger.getLogger (Secure.class.getName());
@ -144,34 +143,10 @@ public class Secure implements SecureInterface
*/ */
private synchronized void initCipher() private synchronized void initCipher()
{ {
if (m_cipher != null) if(m_keyStore==null){
return; m_keyStore = getKeyStore();
Cipher cc = null;
try
{
cc = Cipher.getInstance("DES/ECB/PKCS5Padding");
// Key
/*if (false)
{
KeyGenerator keygen = KeyGenerator.getInstance("DES");
m_key = keygen.generateKey();
byte[] key = m_key.getEncoded();
StringBuffer sb = new StringBuffer ("Key ")
.append(m_key.getAlgorithm())
.append("(").append(key.length).append(")= ");
for (int i = 0; i < key.length; i++)
sb.append(key[i]).append(",");
log.info(sb.toString());
}
else*/
m_key = new javax.crypto.spec.SecretKeySpec
(new byte[] {100,25,28,-122,-26,94,-3,-26}, "DES");
} }
catch (Exception ex)
{
log.log(Level.SEVERE, "", ex);
}
m_cipher = cc;
} // initCipher } // initCipher
@ -179,35 +154,35 @@ public class Secure implements SecureInterface
/** /**
* Encryption. * Encryption.
* @param value clear value * @param value clear value
* @param AD_Client_ID
* @return encrypted String * @return encrypted String
*/ */
public String encrypt (String value) public String encrypt (String value,int AD_Client_ID)
{ {
String clearText = value; String clearText = value;
if (clearText == null) if (clearText == null)
clearText = ""; clearText = "";
// Init // Init
if (m_cipher == null) if (m_keyStore == null)
initCipher(); initCipher();
// Encrypt
if (m_cipher != null) // Encrypt
{ try {
try Cipher cipher = Cipher.getInstance(m_keyStore.getAlgorithm());
{
m_cipher.init(Cipher.ENCRYPT_MODE, m_key); cipher.init(Cipher.ENCRYPT_MODE, m_keyStore.getKey(AD_Client_ID));
byte[] encBytes = m_cipher.doFinal(clearText.getBytes("UTF8")); byte[] encBytes = cipher.doFinal(clearText.getBytes("UTF8"));
String encString = convertToHexString(encBytes);
// globalqss - [ 1577737 ] Security Breach - show database password String encString = convertToHexString(encBytes);
// log.log (Level.ALL, value + " => " + encString); // globalqss - [ 1577737 ] Security Breach - show database password
return encString; // log.log (Level.ALL, value + " => " + encString);
} return encString;
catch (Exception ex) } catch (Exception ex) {
{ // log.log(Level.INFO, value, ex);
// log.log(Level.INFO, value, ex); log.log(Level.INFO, "Problem encrypting string", ex);
log.log(Level.INFO, "Problem encrypting string", ex);
}
} }
// Fallback
// Fallback
return CLEARVALUE_START + value + CLEARVALUE_END; return CLEARVALUE_START + value + CLEARVALUE_END;
} // encrypt } // encrypt
@ -215,9 +190,10 @@ public class Secure implements SecureInterface
* Decryption. * Decryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value encrypted value * @param value encrypted value
* @param AD_Client_ID
* @return decrypted String * @return decrypted String
*/ */
public String decrypt (String value) public String decrypt (String value,int AD_Client_ID)
{ {
if (value == null || value.length() == 0) if (value == null || value.length() == 0)
return value; return value;
@ -238,17 +214,18 @@ public class Secure implements SecureInterface
return value; return value;
} }
// Init // Init
if (m_cipher == null) if (m_keyStore == null)
initCipher(); initCipher();
// Encrypt // Encrypt
if (m_cipher != null && value != null && value.length() > 0) if (value != null && value.length() > 0)
{ {
try try
{ {
AlgorithmParameters ap = m_cipher.getParameters(); Cipher cipher = Cipher.getInstance(m_keyStore.getAlgorithm());
m_cipher.init(Cipher.DECRYPT_MODE, m_key, ap); AlgorithmParameters ap = cipher.getParameters();
byte[] out = m_cipher.doFinal(data); cipher.init(Cipher.DECRYPT_MODE, m_keyStore.getKey(AD_Client_ID), ap);
byte[] out = cipher.doFinal(data);
String retValue = new String(out, "UTF8"); String retValue = new String(out, "UTF8");
// globalqss - [ 1577737 ] Security Breach - show database password // globalqss - [ 1577737 ] Security Breach - show database password
// log.log (Level.ALL, value + " => " + retValue); // log.log (Level.ALL, value + " => " + retValue);
@ -267,9 +244,10 @@ public class Secure implements SecureInterface
* Encryption. * Encryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value clear value * @param value clear value
* @param ad_client_id
* @return encrypted String * @return encrypted String
*/ */
public Integer encrypt (Integer value) public Integer encrypt (Integer value,int ad_client_id)
{ {
return value; return value;
} // encrypt } // encrypt
@ -280,7 +258,7 @@ public class Secure implements SecureInterface
* @param value encrypted value * @param value encrypted value
* @return decrypted String * @return decrypted String
*/ */
public Integer decrypt (Integer value) public Integer decrypt (Integer value,int ad_client_id)
{ {
return value; return value;
} // decrypt } // decrypt
@ -289,9 +267,10 @@ public class Secure implements SecureInterface
* Encryption. * Encryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value clear value * @param value clear value
* @param ad_client_id
* @return encrypted String * @return encrypted String
*/ */
public BigDecimal encrypt (BigDecimal value) public BigDecimal encrypt (BigDecimal value,int ad_client_id)
{ {
return value; return value;
} // encrypt } // encrypt
@ -302,7 +281,7 @@ public class Secure implements SecureInterface
* @param value encrypted value * @param value encrypted value
* @return decrypted String * @return decrypted String
*/ */
public BigDecimal decrypt (BigDecimal value) public BigDecimal decrypt (BigDecimal value,int ad_client_id)
{ {
return value; return value;
} // decrypt } // decrypt
@ -311,9 +290,10 @@ public class Secure implements SecureInterface
* Encryption. * Encryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value clear value * @param value clear value
* @param ad_client_id
* @return encrypted String * @return encrypted String
*/ */
public Timestamp encrypt (Timestamp value) public Timestamp encrypt (Timestamp value,int ad_client_id)
{ {
return value; return value;
} // encrypt } // encrypt
@ -324,7 +304,7 @@ public class Secure implements SecureInterface
* @param value encrypted value * @param value encrypted value
* @return decrypted String * @return decrypted String
*/ */
public Timestamp decrypt (Timestamp value) public Timestamp decrypt (Timestamp value,int ad_client_id)
{ {
return value; return value;
} // decrypt } // decrypt
@ -412,9 +392,20 @@ public class Secure implements SecureInterface
public String toString () public String toString ()
{ {
StringBuilder sb = new StringBuilder ("Secure["); StringBuilder sb = new StringBuilder ("Secure[");
sb.append(m_cipher) sb.append(m_keyStore.getAlgorithm())
.append ("]"); .append ("]");
return sb.toString (); return sb.toString ();
} // toString } // toString
/**
*
* @return keystore
*/
public IKeyStore getKeyStore(){
IKeyStore keyStore = Core.getKeyStore();
if(keyStore==null)
keyStore = new DefaultKeyStore();
return keyStore;
}
} // Secure } // Secure

View File

@ -106,9 +106,10 @@ public class SecureEngine
* Encryption. * Encryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value clear value * @param value clear value
* @param AD_Client_ID
* @return encrypted String * @return encrypted String
*/ */
public static String encrypt (String value) public static String encrypt (String value,int AD_Client_ID)
{ {
if (value == null || value.length() == 0) if (value == null || value.length() == 0)
return value; return value;
@ -119,19 +120,21 @@ public class SecureEngine
if (inQuotes) if (inQuotes)
value = value.substring(1, value.length()-1); value = value.substring(1, value.length()-1);
// //
String retValue = s_engine.implementation.encrypt(value); String retValue = s_engine.implementation.encrypt(value,AD_Client_ID);
if (inQuotes) if (inQuotes)
return "'" + retValue + "'"; return "'" + retValue + "'";
return retValue; return retValue;
} // encrypt } // encrypt
/** /**
* Decryption. * Decryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value encrypted value * @param value encrypted value
* @param AD_Client_ID
* @return decrypted String * @return decrypted String
*/ */
public static String decrypt (String value) public static String decrypt (String value, int AD_Client_ID)
{ {
if (value == null) if (value == null)
return null; return null;
@ -144,22 +147,23 @@ public class SecureEngine
if (value.startsWith(SecureInterface.CLEARVALUE_START) && value.endsWith(SecureInterface.CLEARVALUE_END)) if (value.startsWith(SecureInterface.CLEARVALUE_START) && value.endsWith(SecureInterface.CLEARVALUE_END))
retValue = value.substring(SecureInterface.CLEARVALUE_START.length(), value.length()-SecureInterface.CLEARVALUE_END.length()); retValue = value.substring(SecureInterface.CLEARVALUE_START.length(), value.length()-SecureInterface.CLEARVALUE_END.length());
else else
retValue = s_engine.implementation.decrypt(value); retValue = s_engine.implementation.decrypt(value,AD_Client_ID);
if (inQuotes) if (inQuotes)
return "'" + retValue + "'"; return "'" + retValue + "'";
return retValue; return retValue;
} // decrypt } // decrypt
/** /**
* Encryption. * Encryption.
* The methods must recognize clear values * The methods must recognize clear values
* @param value clear value * @param value clear value
* @param AD_Client_ID
* @return encrypted String * @return encrypted String
*/ */
public static Object encrypt (Object value) public static Object encrypt (Object value, int AD_Client_ID)
{ {
if (value instanceof String) if (value instanceof String)
return encrypt((String) value); return encrypt((String) value, AD_Client_ID);
return value; return value;
} // encrypt } // encrypt
@ -169,10 +173,10 @@ public class SecureEngine
* @param value encrypted value * @param value encrypted value
* @return decrypted String * @return decrypted String
*/ */
public static Object decrypt (Object value) public static Object decrypt (Object value, int AD_Client_ID)
{ {
if (value instanceof String) if (value instanceof String)
return decrypt((String) value); return decrypt((String) value, AD_Client_ID);
return value; return value;
} // decrypt } // decrypt
@ -204,8 +208,8 @@ public class SecureEngine
System.exit(10); System.exit(10);
} }
// See if it works // See if it works
String testE = implementation.encrypt(TEST); String testE = implementation.encrypt(TEST,0);
String testC = implementation.decrypt(testE); String testC = implementation.decrypt(testE,0);
if (!testC.equals(TEST)) if (!testC.equals(TEST))
throw new IllegalStateException(realClass throw new IllegalStateException(realClass
+ ": " + TEST + ": " + TEST
@ -269,10 +273,10 @@ public class SecureEngine
log.info("Decrypt null =" + test(decrypt(null), null)); log.info("Decrypt null =" + test(decrypt(null), null));
log.info("Decrypt test =" + test(decrypt("test"), "test")); log.info("Decrypt test =" + test(decrypt("test"), "test"));
**/ **/
log.info("Decrypt {test} =" + test(decrypt("af2309f390afed74"), "test")); log.info("Decrypt {test} =" + test(decrypt("af2309f390afed74", 0), "test"));
log.info("Decrypt ~{test}~ =" + test(decrypt(SecureInterface.ENCRYPTEDVALUE_START + "af2309f390afed74" + SecureInterface.ENCRYPTEDVALUE_END), "test")); log.info("Decrypt ~{test}~ =" + test(decrypt(SecureInterface.ENCRYPTEDVALUE_START + "af2309f390afed74" + SecureInterface.ENCRYPTEDVALUE_END, 0), "test"));
log.info("Encrypt test =" + test(encrypt("test"), "af2309f390afed74")); log.info("Encrypt test =" + test(encrypt("test", 0), "af2309f390afed74"));

View File

@ -52,64 +52,71 @@ public interface SecureInterface
/** /**
* Encryption. * Encryption.
* @param value clear value * @param value clear value
* @param AD_Client_ID
* @return encrypted String * @return encrypted String
*/ */
public String encrypt (String value); public String encrypt (String value,int AD_Client_ID);
/** /**
* Decryption. * Decryption.
* @param value encrypted value * @param value encrypted value
* @return decrypted String * @return decrypted String
*/ */
public String decrypt (String value); public String decrypt (String value,int AD_Client_ID);
/** /**
* Encryption. * Encryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value clear value * @param value clear value
* @param AD_Client_ID
* @return encrypted String * @return encrypted String
*/ */
public Integer encrypt (Integer value); public Integer encrypt (Integer value,int AD_Client_ID);
/** /**
* Decryption. * Decryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value encrypted value * @param value encrypted value
* @param AD_Client_ID
* @return decrypted String * @return decrypted String
*/ */
public Integer decrypt (Integer value); public Integer decrypt (Integer value,int AD_Client_ID);
/** /**
* Encryption. * Encryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value clear value * @param value clear value
* @param AD_Client_ID
* @return encrypted String * @return encrypted String
*/ */
public BigDecimal encrypt (BigDecimal value); public BigDecimal encrypt (BigDecimal value,int AD_Client_ID);
/** /**
* Decryption. * Decryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value encrypted value * @param value encrypted value
* @param AD_Client_ID
* @return decrypted String * @return decrypted String
*/ */
public BigDecimal decrypt (BigDecimal value); public BigDecimal decrypt (BigDecimal value,int AD_Client_ID);
/** /**
* Encryption. * Encryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value clear value * @param value clear value
* @param AD_Client_ID
* @return encrypted String * @return encrypted String
*/ */
public Timestamp encrypt (Timestamp value); public Timestamp encrypt (Timestamp value,int AD_Client_ID);
/** /**
* Decryption. * Decryption.
* The methods must recognize clear text values * The methods must recognize clear text values
* @param value encrypted value * @param value encrypted value
* @param AD_Client_ID
* @return decrypted String * @return decrypted String
*/ */
public Timestamp decrypt (Timestamp value); public Timestamp decrypt (Timestamp value,int AD_Client_ID);
/** /**

View File

@ -682,8 +682,6 @@ public class WebUser
{ {
String sql = "SELECT * FROM AD_User " String sql = "SELECT * FROM AD_User "
+ "WHERE COALESCE(LDAPUser, Name)=? " // #1 + "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 + " AND IsActive='Y' " // #4
; ;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
@ -692,14 +690,17 @@ public class WebUser
{ {
pstmt = DB.prepareStatement (sql, null); pstmt = DB.prepareStatement (sql, null);
pstmt.setString (1, m_bpc.getName()); pstmt.setString (1, m_bpc.getName());
pstmt.setString (2, password);
pstmt.setString (3, SecureEngine.encrypt(password));
rs = pstmt.executeQuery (); rs = pstmt.executeQuery ();
if (rs.next ()) if (rs.next ())
{ {
retValue = true; do
if (rs.next()) {
log.warning ("More then one user with Name/Password = " + m_bpc.getName()); MUser user = new MUser(Env.getCtx(), rs, null);
if (user.getPassword() != null && user.getPassword().equals(password)) {
retValue = true;
break;
}
} while (rs.next());
} }
else else
log.fine("No record"); log.fine("No record");

View File

@ -1697,7 +1697,7 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
GridField field = getTargetMField(ColumnName); GridField field = getTargetMField(ColumnName);
// add encryption here if the field is encrypted. // add encryption here if the field is encrypted.
if (field.isEncryptedColumn()) { if (field.isEncryptedColumn()) {
value = SecureEngine.encrypt(value); value = SecureEngine.encrypt(value, Env.getAD_Client_ID(Env.getCtx()));
} }
boolean isProductCategoryField = isProductCategoryField(field.getAD_Column_ID()); boolean isProductCategoryField = isProductCategoryField(field.getAD_Column_ID());