Skip to content

Commit

Permalink
Add getReadableIds and use in filterReadAccess #277
Browse files Browse the repository at this point in the history
  • Loading branch information
patrick-austin committed Feb 11, 2022
1 parent f86b255 commit 3770bbf
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 30 deletions.
50 changes: 20 additions & 30 deletions src/main/java/org/icatproject/core/manager/EntityBeanManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ public enum PersistMode {
private boolean luceneActive;

private int maxEntities;
private int maxIdsInQuery;

private long exportCacheSize;
private Set<String> rootUserNames;
Expand Down Expand Up @@ -786,23 +787,23 @@ private void filterReadAccess(List<ScoredEntityBaseBean> results, List<ScoredEnt
throws IcatException {

logger.debug("Got " + allResults.size() + " results from Lucene");
List<Long> allIds = new ArrayList<>();
allResults.forEach(r -> allIds.add(r.getEntityBaseBeanId()));
List<Long> allowedIds = gateKeeper.getReadableIds(userId, allIds, klass, manager);
for (ScoredEntityBaseBean sr : allResults) {
long entityId = sr.getEntityBaseBeanId();
EntityBaseBean beanManaged = manager.find(klass, entityId);
if (beanManaged != null) {
try {
gateKeeper.performAuthorisation(userId, beanManaged, AccessType.READ, manager);
results.add(new ScoredEntityBaseBean(entityId, sr.getScore()));
if (results.size() > maxEntities) {
throw new IcatException(IcatExceptionType.VALIDATION,
"attempt to return more than " + maxEntities + " entities");
}
if (results.size() == maxCount) {
break;
}
} catch (IcatException e) {
// Nothing to do
try {
if (allowedIds.contains(sr.getEntityBaseBeanId())) {
results.add(sr);
}
if (results.size() > maxEntities) {
throw new IcatException(IcatExceptionType.VALIDATION,
"attempt to return more than " + maxEntities + " entities");
}
if (results.size() == maxCount) {
break;
}
} catch (IcatException e) {
// Nothing to do
}
}
}
Expand Down Expand Up @@ -1154,6 +1155,7 @@ void init() {
notificationRequests = propertyHandler.getNotificationRequests();
luceneActive = lucene.isActive();
maxEntities = propertyHandler.getMaxEntities();
maxIdsInQuery = propertyHandler.getMaxIdsInQuery();
exportCacheSize = propertyHandler.getImportCacheSize();
rootUserNames = propertyHandler.getRootUserNames();
key = propertyHandler.getKey();
Expand Down Expand Up @@ -1398,11 +1400,7 @@ public List<ScoredEntityBaseBean> luceneDatafiles(String userName, String user,
LuceneSearchResult last = null;
Long uid = null;
List<ScoredEntityBaseBean> allResults = Collections.emptyList();
/*
* As results may be rejected and maxCount may be 1 ensure that we
* don't make a huge number of calls to Lucene
*/
int blockSize = Math.max(1000, maxCount);
int blockSize = maxIdsInQuery;

do {
if (last == null) {
Expand Down Expand Up @@ -1441,11 +1439,7 @@ public List<ScoredEntityBaseBean> luceneDatasets(String userName, String user, S
LuceneSearchResult last = null;
Long uid = null;
List<ScoredEntityBaseBean> allResults = Collections.emptyList();
/*
* As results may be rejected and maxCount may be 1 ensure that we
* don't make a huge number of calls to Lucene
*/
int blockSize = Math.max(1000, maxCount);
int blockSize = maxIdsInQuery;

do {
if (last == null) {
Expand Down Expand Up @@ -1492,11 +1486,7 @@ public List<ScoredEntityBaseBean> luceneInvestigations(String userName, String u
LuceneSearchResult last = null;
Long uid = null;
List<ScoredEntityBaseBean> allResults = Collections.emptyList();
/*
* As results may be rejected and maxCount may be 1 ensure that we
* don't make a huge number of calls to Lucene
*/
int blockSize = Math.max(1000, maxCount);
int blockSize = maxIdsInQuery;

do {
if (last == null) {
Expand Down
78 changes: 78 additions & 0 deletions src/main/java/org/icatproject/core/manager/GateKeeper.java
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,84 @@ public List<EntityBaseBean> getReadable(String userId, List<EntityBaseBean> bean
return results;
}

public List<Long> getReadableIds(String userId, List<Long> ids,
Class<? extends EntityBaseBean> objectClass, EntityManager manager) {
if (ids.size() == 0) {
return ids;
}

String simpleName = objectClass.getSimpleName();
if (rootUserNames.contains(userId)) {
logger.info("\"Root\" user " + userId + " is allowed READ to " + simpleName);
return ids;
}

TypedQuery<String> query = manager.createNamedQuery(Rule.INCLUDE_QUERY, String.class)
.setParameter("member", userId).setParameter("bean", simpleName);

List<String> restrictions = query.getResultList();
logger.debug("Got " + restrictions.size() + " authz queries for READ by " + userId + " to a "
+ objectClass.getSimpleName());

for (String restriction : restrictions) {
logger.debug("Query: " + restriction);
if (restriction == null) {
logger.info("Null restriction => READ permitted to " + simpleName);
return ids;
}
}

/*
* IDs are processed in batches to avoid Oracle error: ORA-01795:
* maximum number of expressions in a list is 1000
*/

List<String> idLists = new ArrayList<>();
StringBuilder sb = null;

int i = 0;
for (Long id : ids) {
if (i == 0) {
sb = new StringBuilder();
sb.append(id);
i = 1;
} else {
sb.append("," + id);
i++;
}
if (i == maxIdsInQuery) {
i = 0;
idLists.add(sb.toString());
sb = null;
}
}
if (sb != null) {
idLists.add(sb.toString());
}

logger.debug("Check readability of " + ids.size() + " beans has been divided into " + idLists.size()
+ " queries.");

Set<Long> readableIds = new HashSet<>();
for (String idList : idLists) {
for (String qString : restrictions) {
TypedQuery<Long> q = manager.createQuery(qString.replace(":pkids", idList), Long.class);
if (qString.contains(":user")) {
q.setParameter("user", userId);
}
readableIds.addAll(q.getResultList());
}
}

List<Long> results = new ArrayList<>();
for (Long id : ids) {
if (readableIds.contains(id)) {
results.add(id);
}
}
return results;
}

public Set<String> getRootUserNames() {
return rootUserNames;
}
Expand Down

0 comments on commit 3770bbf

Please sign in to comment.