Skip to content

Commit

Permalink
Updates methods to return actual resources instead of resource ids
Browse files Browse the repository at this point in the history
Signed-off-by: Darshit Chanpura <[email protected]>
  • Loading branch information
DarshitChanpura committed Dec 12, 2024
1 parent 8e3d41c commit cabbcd6
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2208,8 +2208,8 @@ private void tryAddSecurityProvider() {
}

@Override
public Set<String> getAccessibleResourcesForCurrentUser(String systemIndexName) {
return this.resourceAccessHandler.getAccessibleResourcesForCurrentUser(systemIndexName);
public <T> Set<T> getAccessibleResourcesForCurrentUser(String systemIndexName, Class<T> clazz) {
return this.resourceAccessHandler.getAccessibleResourcesForCurrentUser(systemIndexName, clazz);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public ResourceAccessHandler(
* @param resourceIndex The resource index to check for accessible resources.
* @return A set of accessible resource IDs.
*/
public Set<String> getAccessibleResourcesForCurrentUser(String resourceIndex) {
public <T> Set<T> getAccessibleResourcesForCurrentUser(String resourceIndex, Class<T> clazz) {
final User user = threadContext.getPersistent(ConfigConstants.OPENDISTRO_SECURITY_USER);
if (user == null) {
LOGGER.info("Unable to fetch user details ");
Expand All @@ -69,24 +69,24 @@ public Set<String> getAccessibleResourcesForCurrentUser(String resourceIndex) {

// check if user is admin, if yes all resources should be accessible
if (adminDNs.isAdmin(user)) {
return loadAllResources(resourceIndex);
return loadAllResources(resourceIndex, clazz);
}

Set<String> result = new HashSet<>();
Set<T> result = new HashSet<>();

// 0. Own resources
result.addAll(loadOwnResources(resourceIndex, user.getName()));
result.addAll(loadOwnResources(resourceIndex, user.getName(), clazz));

// 1. By username
result.addAll(loadSharedWithResources(resourceIndex, Set.of(user.getName()), EntityType.USERS.toString()));
result.addAll(loadSharedWithResources(resourceIndex, Set.of(user.getName()), EntityType.USERS.toString(), clazz));

// 2. By roles
Set<String> roles = user.getSecurityRoles();
result.addAll(loadSharedWithResources(resourceIndex, roles, EntityType.ROLES.toString()));
result.addAll(loadSharedWithResources(resourceIndex, roles, EntityType.ROLES.toString(), clazz));

// 3. By backend_roles
Set<String> backendRoles = user.getRoles();
result.addAll(loadSharedWithResources(resourceIndex, backendRoles, EntityType.BACKEND_ROLES.toString()));
result.addAll(loadSharedWithResources(resourceIndex, backendRoles, EntityType.BACKEND_ROLES.toString(), clazz));

return result;
}
Expand Down Expand Up @@ -210,8 +210,8 @@ public boolean deleteAllResourceSharingRecordsForCurrentUser() {
* @param resourceIndex The resource index to load resources from.
* @return A set of resource IDs.
*/
private Set<String> loadAllResources(String resourceIndex) {
return this.resourceSharingIndexHandler.fetchAllDocuments(resourceIndex);
private <T> Set<T> loadAllResources(String resourceIndex, Class<T> clazz) {
return this.resourceSharingIndexHandler.fetchAllDocuments(resourceIndex, clazz);
}

/**
Expand All @@ -221,8 +221,8 @@ private Set<String> loadAllResources(String resourceIndex) {
* @param userName The username of the owner.
* @return A set of resource IDs owned by the user.
*/
private Set<String> loadOwnResources(String resourceIndex, String userName) {
return this.resourceSharingIndexHandler.fetchDocumentsByField(resourceIndex, "created_by.user", userName);
private <T> Set<T> loadOwnResources(String resourceIndex, String userName, Class<T> clazz) {
return this.resourceSharingIndexHandler.fetchDocumentsByField(resourceIndex, "created_by.user", userName, clazz);
}

/**
Expand All @@ -233,8 +233,8 @@ private Set<String> loadOwnResources(String resourceIndex, String userName) {
* @param entityType The type of entity (e.g., users, roles, backend_roles).
* @return A set of resource IDs shared with the specified entities.
*/
private Set<String> loadSharedWithResources(String resourceIndex, Set<String> entities, String entityType) {
return this.resourceSharingIndexHandler.fetchDocumentsForAllScopes(resourceIndex, entities, entityType);
private <T> Set<T> loadSharedWithResources(String resourceIndex, Set<String> entities, String entityType, Class<T> clazz) {
return this.resourceSharingIndexHandler.fetchDocumentsForAllScopes(resourceIndex, entities, entityType, clazz);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
import org.opensearch.accesscontrol.resources.ShareWith;
import org.opensearch.action.admin.indices.create.CreateIndexRequest;
import org.opensearch.action.admin.indices.create.CreateIndexResponse;
import org.opensearch.action.get.MultiGetItemResponse;
import org.opensearch.action.get.MultiGetRequest;
import org.opensearch.action.get.MultiGetResponse;
import org.opensearch.action.index.IndexRequest;
import org.opensearch.action.index.IndexResponse;
import org.opensearch.action.search.ClearScrollRequest;
Expand Down Expand Up @@ -214,7 +217,7 @@ public ResourceSharing indexResourceSharing(String resourceId, String resourceIn
* <li>Returns an empty list instead of throwing exceptions</li>
* </ul>
*/
public Set<String> fetchAllDocuments(String pluginIndex) {
public <T> Set<T> fetchAllDocuments(String pluginIndex, Class<T> clazz) {
LOGGER.debug("Fetching all documents from {} where source_idx = {}", resourceSharingIndex, pluginIndex);

try {
Expand Down Expand Up @@ -242,7 +245,7 @@ public Set<String> fetchAllDocuments(String pluginIndex) {

LOGGER.debug("Found {} documents in {} for source_idx: {}", resourceIds.size(), resourceSharingIndex, pluginIndex);

return resourceIds;
return getResourcesFromIds(resourceIds, pluginIndex, clazz);

} catch (Exception e) {
LOGGER.error("Failed to fetch documents from {} for source_idx: {}", resourceSharingIndex, pluginIndex, e);
Expand Down Expand Up @@ -316,9 +319,9 @@ public Set<String> fetchAllDocuments(String pluginIndex) {
* </ul>
*/

public Set<String> fetchDocumentsForAllScopes(String pluginIndex, Set<String> entities, String entityType) {
public <T> Set<T> fetchDocumentsForAllScopes(String pluginIndex, Set<String> entities, String entityType, Class<T> clazz) {
// "*" must match all scopes
return fetchDocumentsForAGivenScope(pluginIndex, entities, entityType, "*");
return fetchDocumentsForAGivenScope(pluginIndex, entities, entityType, "*", clazz);
}

/**
Expand Down Expand Up @@ -387,7 +390,13 @@ public Set<String> fetchDocumentsForAllScopes(String pluginIndex, Set<String> en
* <li>Properly cleans up scroll context after use</li>
* </ul>
*/
public Set<String> fetchDocumentsForAGivenScope(String pluginIndex, Set<String> entities, String entityType, String scope) {
public <T> Set<T> fetchDocumentsForAGivenScope(
String pluginIndex,
Set<String> entities,
String entityType,
String scope,
Class<T> clazz
) {
LOGGER.debug(
"Fetching documents from index: {}, where share_with.{}.{} contains any of {}",
pluginIndex,
Expand Down Expand Up @@ -426,11 +435,11 @@ public Set<String> fetchDocumentsForAGivenScope(String pluginIndex, Set<String>

LOGGER.debug("Found {} documents matching the criteria in {}", resourceIds.size(), resourceSharingIndex);

return resourceIds;
return getResourcesFromIds(resourceIds, pluginIndex, clazz);

} catch (Exception e) {
LOGGER.error(
"Failed to fetch documents from {} for criteria - systemIndex: {}, scope: {}, entityType: {}, entities: {}",
"Failed to fetch documents from {} for criteria - pluginIndex: {}, scope: {}, entityType: {}, entities: {}",
resourceSharingIndex,
pluginIndex,
scope,
Expand Down Expand Up @@ -472,7 +481,7 @@ public Set<String> fetchDocumentsForAGivenScope(String pluginIndex, Set<String>
* }
* </pre>
*
* @param systemIndex The source index to match against the source_idx field
* @param pluginIndex The source index to match against the source_idx field
* @param field The field name to search in. Must be a valid field in the index mapping
* @param value The value to match for the specified field. Performs exact term matching
* @return Set<String> List of resource IDs that match the criteria. Returns an empty list
Expand All @@ -495,12 +504,12 @@ public Set<String> fetchDocumentsForAGivenScope(String pluginIndex, Set<String>
* Set<String> resources = fetchDocumentsByField("myIndex", "status", "active");
* </pre>
*/
public Set<String> fetchDocumentsByField(String systemIndex, String field, String value) {
if (StringUtils.isBlank(systemIndex) || StringUtils.isBlank(field) || StringUtils.isBlank(value)) {
throw new IllegalArgumentException("systemIndex, field, and value must not be null or empty");
public <T> Set<T> fetchDocumentsByField(String pluginIndex, String field, String value, Class<T> clazz) {
if (StringUtils.isBlank(pluginIndex) || StringUtils.isBlank(field) || StringUtils.isBlank(value)) {
throw new IllegalArgumentException("pluginIndex, field, and value must not be null or empty");
}

LOGGER.debug("Fetching documents from index: {}, where {} = {}", systemIndex, field, value);
LOGGER.debug("Fetching documents from index: {}, where {} = {}", pluginIndex, field, value);

Set<String> resourceIds = new HashSet<>();
final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
Expand All @@ -510,14 +519,14 @@ public Set<String> fetchDocumentsByField(String systemIndex, String field, Strin
searchRequest.scroll(scroll);

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("source_idx.keyword", systemIndex))
.must(QueryBuilders.termQuery("source_idx.keyword", pluginIndex))
.must(QueryBuilders.termQuery(field + ".keyword", value));

executeSearchRequest(resourceIds, scroll, searchRequest, boolQuery);

LOGGER.info("Found {} documents in {} where {} = {}", resourceIds.size(), resourceSharingIndex, field, value);

return resourceIds;
return getResourcesFromIds(resourceIds, pluginIndex, clazz);
} catch (Exception e) {
LOGGER.error("Failed to fetch documents from {} where {} = {}", resourceSharingIndex, field, value, e);
throw new RuntimeException("Failed to fetch documents: " + e.getMessage(), e);
Expand Down Expand Up @@ -557,7 +566,7 @@ public Set<String> fetchDocumentsByField(String systemIndex, String field, Strin
* @return ResourceSharing object if a matching document is found, null if no document
* matches the criteria
*
* @throws IllegalArgumentException if systemIndexName or resourceId is null or empty
* @throws IllegalArgumentException if pluginIndexName or resourceId is null or empty
* @throws RuntimeException if the search operation fails or parsing errors occur,
* wrapping the underlying exception
*
Expand All @@ -581,7 +590,7 @@ public Set<String> fetchDocumentsByField(String systemIndex, String field, Strin

public ResourceSharing fetchDocumentById(String pluginIndex, String resourceId) {
if (StringUtils.isBlank(pluginIndex) || StringUtils.isBlank(resourceId)) {
throw new IllegalArgumentException("systemIndexName and resourceId must not be null or empty");
throw new IllegalArgumentException("pluginIndexName and resourceId must not be null or empty");
}

LOGGER.debug("Fetching document from index: {}, with resourceId: {}", pluginIndex, resourceId);
Expand Down Expand Up @@ -901,7 +910,7 @@ private boolean updateByQueryResourceSharing(String sourceIdx, String resourceId
* Map<EntityType, Set<String>> revokeAccess = new HashMap<>();
* revokeAccess.put(EntityType.USER, Set.of("user1", "user2"));
* revokeAccess.put(EntityType.ROLE, Set.of("role1"));
* ResourceSharing updated = revokeAccess("resourceId", "systemIndex", revokeAccess);
* ResourceSharing updated = revokeAccess("resourceId", "pluginIndex", revokeAccess);
* </pre>
*/
public ResourceSharing revokeAccess(
Expand Down Expand Up @@ -1131,4 +1140,35 @@ public boolean deleteAllRecordsForUser(String name) {
}
}

/**
* Fetches all documents from the specified resource index and deserializes them into the specified class.
*
* @param resourceIndex The resource index to fetch documents from.
* @param clazz The class to deserialize the documents into.
* @return A set of deserialized documents.
*/
private <T> Set<T> getResourcesFromIds(Set<String> resourceIds, String resourceIndex, Class<T> clazz) {

Set<T> result = new HashSet<>();
try {
MultiGetRequest request = new MultiGetRequest();
for (String id : resourceIds) {
request.add(new MultiGetRequest.Item(resourceIndex, id));
}

MultiGetResponse response = client.multiGet(request).actionGet();

for (MultiGetItemResponse itemResponse : response.getResponses()) {
if (!itemResponse.isFailed() && itemResponse.getResponse().isExists()) {
String sourceAsString = itemResponse.getResponse().getSourceAsString();
T resource = DefaultObjectMapper.readValue(sourceAsString, clazz);
result.add(resource);
}
}
} catch (Exception e) {
LOGGER.error("Failed to fetch resources with ids {} from index {}", resourceIds, resourceIndex, e);
}

return result;
}
}

0 comments on commit cabbcd6

Please sign in to comment.