IDEMPIERE-4268 Web Services : Read miss cross-tenant check (#468)
Extracting from @hengsin pull request 465 Fixes cross tenant readings in MUser MUserDefWin and MWorkflow
This commit is contained in:
parent
03b4a1e878
commit
2ab2211f81
|
@ -383,6 +383,8 @@ public class MUser extends X_AD_User implements ImmutablePOSupport
|
||||||
private MRole[] m_roles = null;
|
private MRole[] m_roles = null;
|
||||||
/** Roles of User with Org */
|
/** Roles of User with Org */
|
||||||
private int m_rolesAD_Org_ID = -1;
|
private int m_rolesAD_Org_ID = -1;
|
||||||
|
/** AD_Client_ID for m_roles above */
|
||||||
|
private int m_rolesAD_Client_ID = -1;
|
||||||
/** Is Administrator */
|
/** Is Administrator */
|
||||||
private Boolean m_isAdministrator = null;
|
private Boolean m_isAdministrator = null;
|
||||||
/** User Access Rights */
|
/** User Access Rights */
|
||||||
|
@ -787,7 +789,7 @@ public class MUser extends X_AD_User implements ImmutablePOSupport
|
||||||
*/
|
*/
|
||||||
public MRole[] getRoles (int AD_Org_ID)
|
public MRole[] getRoles (int AD_Org_ID)
|
||||||
{
|
{
|
||||||
if (m_roles != null && m_rolesAD_Org_ID == AD_Org_ID)
|
if (m_roles != null && m_rolesAD_Org_ID == AD_Org_ID && m_rolesAD_Client_ID == Env.getAD_Client_ID(Env.getCtx()))
|
||||||
return m_roles;
|
return m_roles;
|
||||||
|
|
||||||
ArrayList<MRole> list = new ArrayList<MRole>();
|
ArrayList<MRole> list = new ArrayList<MRole>();
|
||||||
|
@ -796,7 +798,7 @@ public class MUser extends X_AD_User implements ImmutablePOSupport
|
||||||
// are found but also roles which delegate org access to the user level where
|
// are found but also roles which delegate org access to the user level where
|
||||||
// this user has access to the org in question
|
// this user has access to the org in question
|
||||||
String sql = "SELECT * FROM AD_Role r "
|
String sql = "SELECT * FROM AD_Role r "
|
||||||
+ "WHERE r.IsActive='Y'"
|
+ "WHERE r.IsActive='Y' AND r.AD_Client_ID IN (0, ?) "
|
||||||
+ " AND EXISTS (SELECT * FROM AD_User_Roles ur"
|
+ " AND EXISTS (SELECT * FROM AD_User_Roles ur"
|
||||||
+ " WHERE r.AD_Role_ID=ur.AD_Role_ID AND ur.IsActive='Y' AND ur.AD_User_ID=?) "
|
+ " WHERE r.AD_Role_ID=ur.AD_Role_ID AND ur.IsActive='Y' AND ur.AD_User_ID=?) "
|
||||||
+ " AND ( ( r.isaccessallorgs = 'Y' ) OR "
|
+ " AND ( ( r.isaccessallorgs = 'Y' ) OR "
|
||||||
|
@ -817,18 +819,14 @@ public class MUser extends X_AD_User implements ImmutablePOSupport
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pstmt = DB.prepareStatement (sql, get_TrxName());
|
pstmt = DB.prepareStatement (sql, get_TrxName());
|
||||||
pstmt.setInt (1, getAD_User_ID());
|
pstmt.setInt (1, Env.getAD_Client_ID(Env.getCtx()));
|
||||||
pstmt.setInt (2, AD_Org_ID);
|
pstmt.setInt (2, getAD_User_ID());
|
||||||
pstmt.setInt (3, getAD_User_ID());
|
pstmt.setInt (3, AD_Org_ID);
|
||||||
pstmt.setInt (4, AD_Org_ID);
|
pstmt.setInt (4, getAD_User_ID());
|
||||||
|
pstmt.setInt (5, AD_Org_ID);
|
||||||
rs = pstmt.executeQuery ();
|
rs = pstmt.executeQuery ();
|
||||||
try {
|
while (rs.next ())
|
||||||
PO.setCrossTenantSafe();
|
list.add (new MRole(Env.getCtx(), rs, get_TrxName()));
|
||||||
while (rs.next ())
|
|
||||||
list.add (new MRole(Env.getCtx(), rs, get_TrxName()));
|
|
||||||
} finally {
|
|
||||||
PO.clearCrossTenantSafe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -844,6 +842,7 @@ public class MUser extends X_AD_User implements ImmutablePOSupport
|
||||||
list.stream().forEach(e -> e.markImmutable());
|
list.stream().forEach(e -> e.markImmutable());
|
||||||
|
|
||||||
m_rolesAD_Org_ID = AD_Org_ID;
|
m_rolesAD_Org_ID = AD_Org_ID;
|
||||||
|
m_rolesAD_Client_ID = Env.getAD_Client_ID(Env.getCtx());
|
||||||
m_roles = new MRole[list.size()];
|
m_roles = new MRole[list.size()];
|
||||||
list.toArray (m_roles);
|
list.toArray (m_roles);
|
||||||
return m_roles;
|
return m_roles;
|
||||||
|
|
|
@ -16,7 +16,9 @@ package org.compiere.model;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
@ -35,8 +37,7 @@ public class MUserDefWin extends X_AD_UserDef_Win implements ImmutablePOSupport
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = -7542708120229671875L;
|
private static final long serialVersionUID = -7542708120229671875L;
|
||||||
private volatile static List<MUserDefWin> m_fullList = null;
|
private static final Map<Integer, List<MUserDefWin>> m_fullMap = new HashMap<Integer, List<MUserDefWin>>();
|
||||||
private static final Object m_fullListLock = new Object();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard constructor.
|
* Standard constructor.
|
||||||
|
@ -104,26 +105,25 @@ public class MUserDefWin extends X_AD_UserDef_Win implements ImmutablePOSupport
|
||||||
*/
|
*/
|
||||||
private static MUserDefWin[] getAll (Properties ctx, int window_ID )
|
private static MUserDefWin[] getAll (Properties ctx, int window_ID )
|
||||||
{
|
{
|
||||||
synchronized (m_fullListLock) {
|
List<MUserDefWin> fullList = null;
|
||||||
if (m_fullList == null) {
|
synchronized (m_fullMap) {
|
||||||
try {
|
fullList = m_fullMap.get(Env.getAD_Client_ID(ctx));
|
||||||
PO.setCrossTenantSafe();
|
if (fullList == null) {
|
||||||
m_fullList = new Query(ctx, MUserDefWin.Table_Name, null, null)
|
fullList = new Query(ctx, MUserDefWin.Table_Name, null, null)
|
||||||
.setOnlyActiveRecords(true)
|
.setOnlyActiveRecords(true)
|
||||||
.list();
|
.setClient_ID()
|
||||||
} finally {
|
.list();
|
||||||
PO.clearCrossTenantSafe();
|
m_fullMap.put(Env.getAD_Client_ID(ctx), fullList);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_fullList.size() == 0) {
|
if (fullList.size() == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MUserDefWin> list = new ArrayList<MUserDefWin>();
|
List<MUserDefWin> list = new ArrayList<MUserDefWin>();
|
||||||
|
|
||||||
for (MUserDefWin udw : m_fullList) {
|
for (MUserDefWin udw : fullList) {
|
||||||
if (udw.getAD_Window_ID() == window_ID
|
if (udw.getAD_Window_ID() == window_ID
|
||||||
&& udw.getAD_Client_ID() == Env.getAD_Client_ID(ctx)
|
&& udw.getAD_Client_ID() == Env.getAD_Client_ID(ctx)
|
||||||
&& (udw.getAD_Language() == null || udw.getAD_Language().equals(Env.getAD_Language(ctx)))
|
&& (udw.getAD_Language() == null || udw.getAD_Language().equals(Env.getAD_Language(ctx)))
|
||||||
|
@ -240,13 +240,17 @@ public class MUserDefWin extends X_AD_UserDef_Win implements ImmutablePOSupport
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean beforeSave(boolean newRecord) {
|
protected boolean beforeSave(boolean newRecord) {
|
||||||
m_fullList = null;
|
synchronized (m_fullMap) {
|
||||||
|
m_fullMap.remove(getAD_Client_ID());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean beforeDelete() {
|
protected boolean beforeDelete() {
|
||||||
m_fullList = null;
|
synchronized (m_fullMap) {
|
||||||
|
m_fullMap.remove(getAD_Client_ID());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,9 @@ import java.sql.Timestamp;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -125,46 +127,43 @@ public class MWorkflow extends X_AD_Workflow implements ImmutablePOSupport
|
||||||
, String trxName //Bug 1568766 Trx should be kept all along the road
|
, String trxName //Bug 1568766 Trx should be kept all along the road
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
String key = "C" + AD_Client_ID + "T" + AD_Table_ID;
|
|
||||||
// Reload
|
// Reload
|
||||||
if (s_cacheDocValue.isReset())
|
Map<Integer, MWorkflow[]> cachedMap = s_cacheDocValue.get(AD_Client_ID);
|
||||||
|
if (cachedMap == null)
|
||||||
{
|
{
|
||||||
final String whereClause = "WorkflowType=? AND IsValid=?";
|
final String whereClause = "WorkflowType=? AND IsValid=? AND AD_Client_ID=?";
|
||||||
List<MWorkflow> workflows;
|
List<MWorkflow> workflows;
|
||||||
try {
|
workflows = new Query(ctx, Table_Name, whereClause, trxName)
|
||||||
PO.setCrossTenantSafe();
|
.setParameters(new Object[]{WORKFLOWTYPE_DocumentValue, true, Env.getAD_Client_ID(ctx)})
|
||||||
workflows = new Query(ctx, Table_Name, whereClause, trxName)
|
.setOnlyActiveRecords(true)
|
||||||
.setParameters(new Object[]{WORKFLOWTYPE_DocumentValue, true})
|
.setOrderBy("AD_Table_ID")
|
||||||
.setOnlyActiveRecords(true)
|
.list();
|
||||||
.setOrderBy("AD_Client_ID, AD_Table_ID")
|
cachedMap = new HashMap<Integer, MWorkflow[]>();
|
||||||
.list();
|
s_cacheDocValue.put(AD_Client_ID, cachedMap);
|
||||||
} finally {
|
|
||||||
PO.clearCrossTenantSafe();
|
|
||||||
}
|
|
||||||
ArrayList<MWorkflow> list = new ArrayList<MWorkflow>();
|
ArrayList<MWorkflow> list = new ArrayList<MWorkflow>();
|
||||||
String oldKey = "";
|
int previousTableId = -1;
|
||||||
String newKey = null;
|
int currentTableId = -1;
|
||||||
for (MWorkflow wf : workflows)
|
for (MWorkflow wf : workflows)
|
||||||
{
|
{
|
||||||
newKey = "C" + wf.getAD_Client_ID() + "T" + wf.getAD_Table_ID();
|
currentTableId = wf.getAD_Table_ID();
|
||||||
if (!newKey.equals(oldKey) && list.size() > 0)
|
if (currentTableId != previousTableId && list.size() > 0)
|
||||||
{
|
{
|
||||||
s_cacheDocValue.put (oldKey, list.stream().map(e -> {return new MWorkflow(Env.getCtx(), e);}).toArray(MWorkflow[]::new));
|
cachedMap.put (previousTableId, list.stream().map(e -> {return new MWorkflow(Env.getCtx(), e);}).toArray(MWorkflow[]::new));
|
||||||
list = new ArrayList<MWorkflow>();
|
list = new ArrayList<MWorkflow>();
|
||||||
}
|
}
|
||||||
oldKey = newKey;
|
previousTableId = currentTableId;
|
||||||
list.add(wf);
|
list.add(wf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last one
|
// Last one
|
||||||
if (list.size() > 0)
|
if (list.size() > 0)
|
||||||
{
|
{
|
||||||
s_cacheDocValue.put (oldKey, list.stream().map(e -> {return new MWorkflow(Env.getCtx(), e);}).toArray(MWorkflow[]::new));
|
cachedMap.put (previousTableId, list.stream().map(e -> {return new MWorkflow(Env.getCtx(), e);}).toArray(MWorkflow[]::new));
|
||||||
}
|
}
|
||||||
if (s_log.isLoggable(Level.CONFIG)) s_log.config("#" + s_cacheDocValue.size());
|
if (s_log.isLoggable(Level.CONFIG)) s_log.config("#" + cachedMap.size());
|
||||||
}
|
}
|
||||||
// Look for Entry
|
// Look for Entry
|
||||||
MWorkflow[] retValue = (MWorkflow[])s_cacheDocValue.get(key);
|
MWorkflow[] retValue = (MWorkflow[])cachedMap.get(AD_Table_ID);
|
||||||
//hengsin: this is not threadsafe
|
//hengsin: this is not threadsafe
|
||||||
/*
|
/*
|
||||||
//set trxName to all workflow instance
|
//set trxName to all workflow instance
|
||||||
|
@ -180,9 +179,19 @@ public class MWorkflow extends X_AD_Workflow implements ImmutablePOSupport
|
||||||
|
|
||||||
|
|
||||||
/** Single Cache */
|
/** Single Cache */
|
||||||
private static ImmutablePOCache<String,MWorkflow> s_cache = new ImmutablePOCache<String,MWorkflow>(Table_Name, Table_Name+"|Language_Workflow", 20);
|
private static ImmutablePOCache<String,MWorkflow> s_cache = new ImmutablePOCache<String,MWorkflow>(Table_Name, Table_Name, 20);
|
||||||
/** Document Value Cache */
|
/** Document Value Cache */
|
||||||
private static CCache<String,MWorkflow[]> s_cacheDocValue = new CCache<String,MWorkflow[]> (Table_Name, Table_Name+"|AD_Client_Table", 5);
|
private static final CCache<Integer,Map<Integer, MWorkflow[]>> s_cacheDocValue = new CCache<> (Table_Name, Table_Name+"|DocumentValue", 5) {
|
||||||
|
/**
|
||||||
|
* generated serial id
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 2548097748351277269L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int reset(int recordId) {
|
||||||
|
return reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
/** Static Logger */
|
/** Static Logger */
|
||||||
private static CLogger s_log = CLogger.getCLogger (MWorkflow.class);
|
private static CLogger s_log = CLogger.getCLogger (MWorkflow.class);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue