Skip to content

Commit

Permalink
Bring user notion to security plugin
Browse files Browse the repository at this point in the history
Signed-off-by: Darshit Chanpura <[email protected]>
  • Loading branch information
DarshitChanpura committed Dec 31, 2024
1 parent 193e846 commit 13fdb81
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,7 @@
import org.opensearch.OpenSearchSecurityException;
import org.opensearch.SpecialPermission;
import org.opensearch.Version;
import org.opensearch.accesscontrol.resources.EntityType;
import org.opensearch.accesscontrol.resources.Resource;
import org.opensearch.accesscontrol.resources.ResourceService;
import org.opensearch.accesscontrol.resources.ResourceSharing;
import org.opensearch.accesscontrol.resources.ShareWith;
import org.opensearch.accesscontrol.resources.*;
import org.opensearch.action.ActionRequest;
import org.opensearch.action.search.PitService;
import org.opensearch.action.search.SearchScrollAction;
Expand Down Expand Up @@ -1230,6 +1226,7 @@ public Collection<Object> createComponents(
auditLog
);
resourceAccessHandler = new ResourceAccessHandler(threadPool, rsIndexHandler, adminDns);
resourceAccessHandler.initializeRecipientTypes();

rmr = ResourceSharingIndexManagementRepository.create(rsIndexHandler);

Expand Down Expand Up @@ -2255,7 +2252,7 @@ public ResourceSharing shareWith(String resourceId, String systemIndexName, Shar
public ResourceSharing revokeAccess(
String resourceId,
String systemIndexName,
Map<EntityType, Set<String>> entities,
Map<RecipientType, Set<String>> entities,
Set<String> scopes
) {
return this.resourceAccessHandler.revokeAccess(resourceId, systemIndexName, entities, scopes);
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/opensearch/security/resources/Creator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.opensearch.security.resources;

public enum Creator {
USER("user");

private final String name;

Creator(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
17 changes: 17 additions & 0 deletions src/main/java/org/opensearch/security/resources/Recipient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.opensearch.security.resources;

public enum Recipient {
USERS("users"),
ROLES("roles"),
BACKEND_ROLES("backend_roles");

private final String name;

Recipient(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import org.opensearch.accesscontrol.resources.EntityType;
import org.opensearch.accesscontrol.resources.RecipientType;
import org.opensearch.accesscontrol.resources.RecipientTypeRegistry;
import org.opensearch.accesscontrol.resources.Resource;
import org.opensearch.accesscontrol.resources.ResourceSharing;
import org.opensearch.accesscontrol.resources.ShareWith;
Expand Down Expand Up @@ -53,6 +54,19 @@ public ResourceAccessHandler(
this.adminDNs = adminDns;
}

/**
* Initializes the recipient types for users, roles, and backend roles.
* These recipient types are used to identify the types of recipients for resource sharing.
*/
public void initializeRecipientTypes() {
RecipientTypeRegistry.registerRecipientType(Recipient.USERS.getName(), new RecipientType(Recipient.USERS.getName()));
RecipientTypeRegistry.registerRecipientType(Recipient.ROLES.getName(), new RecipientType(Recipient.ROLES.getName()));
RecipientTypeRegistry.registerRecipientType(
Recipient.BACKEND_ROLES.getName(),
new RecipientType(Recipient.BACKEND_ROLES.getName())
);
}

/**
* Returns a set of accessible resources for the current user within the specified resource index.
*
Expand Down Expand Up @@ -82,15 +96,15 @@ public <T extends Resource> Set<T> getAccessibleResourcesForCurrentUser(String r
result.addAll(loadOwnResources(resourceIndex, user.getName(), clazz));

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

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

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

return result;
}
Expand Down Expand Up @@ -127,9 +141,9 @@ public boolean hasPermission(String resourceId, String resourceIndex, String sco

if (isSharedWithEveryone(document)
|| isOwnerOfResource(document, user.getName())
|| isSharedWithEntity(document, EntityType.USERS, Set.of(user.getName()), scope)
|| isSharedWithEntity(document, EntityType.ROLES, userRoles, scope)
|| isSharedWithEntity(document, EntityType.BACKEND_ROLES, userBackendRoles, scope)) {
|| isSharedWithEntity(document, Recipient.USERS, Set.of(user.getName()), scope)
|| isSharedWithEntity(document, Recipient.ROLES, userRoles, scope)
|| isSharedWithEntity(document, Recipient.BACKEND_ROLES, userBackendRoles, scope)) {
LOGGER.info("User {} has {} access to {}", user.getName(), scope, resourceId);
return true;
}
Expand Down Expand Up @@ -169,7 +183,7 @@ public ResourceSharing shareWith(String resourceId, String resourceIndex, ShareW
public ResourceSharing revokeAccess(
String resourceId,
String resourceIndex,
Map<EntityType, Set<String>> revokeAccess,
Map<RecipientType, Set<String>> revokeAccess,
Set<String> scopes
) {
if (areArgumentsInvalid(resourceId, resourceIndex, revokeAccess, scopes)) {
Expand Down Expand Up @@ -247,16 +261,16 @@ private <T extends Resource> Set<T> loadOwnResources(String resourceIndex, Strin
*
* @param resourceIndex The resource index to load resources from.
* @param entities The set of entities to check for shared resources.
* @param entityType The type of entity (e.g., users, roles, backend_roles).
* @param RecipientType The type of entity (e.g., users, roles, backend_roles).
* @return A set of resource IDs shared with the specified entities.
*/
private <T extends Resource> Set<T> loadSharedWithResources(
String resourceIndex,
Set<String> entities,
String entityType,
String RecipientType,
Class<T> clazz
) {
return this.resourceSharingIndexHandler.fetchDocumentsForAllScopes(resourceIndex, entities, entityType, clazz);
return this.resourceSharingIndexHandler.fetchDocumentsForAllScopes(resourceIndex, entities, RecipientType, clazz);
}

/**
Expand All @@ -267,21 +281,21 @@ private <T extends Resource> Set<T> loadSharedWithResources(
* @return True if the resource is owned by the user, false otherwise.
*/
private boolean isOwnerOfResource(ResourceSharing document, String userName) {
return document.getCreatedBy() != null && document.getCreatedBy().getUser().equals(userName);
return document.getCreatedBy() != null && document.getCreatedBy().getCreator().equals(userName);
}

/**
* Checks if the given resource is shared with the specified entities and scope.
*
* @param document The ResourceSharing document to check.
* @param entityType The type of entity (e.g., users, roles, backend_roles).
* @param recipient The recipient entity
* @param entities The set of entities to check for sharing.
* @param scope The permission scope to check.
* @return True if the resource is shared with the entities and scope, false otherwise.
*/
private boolean isSharedWithEntity(ResourceSharing document, EntityType entityType, Set<String> entities, String scope) {
private boolean isSharedWithEntity(ResourceSharing document, Recipient recipient, Set<String> entities, String scope) {
for (String entity : entities) {
if (checkSharing(document, entityType, entity, scope)) {
if (checkSharing(document, recipient, entity, scope)) {
return true;
}
}
Expand All @@ -303,12 +317,12 @@ private boolean isSharedWithEveryone(ResourceSharing document) {
* Checks if the given resource is shared with the specified entity and scope.
*
* @param document The ResourceSharing document to check.
* @param entityType The type of entity (e.g., users, roles, backend_roles).
* @param recipient The recipient entity
* @param identifier The identifier of the entity to check for sharing.
* @param scope The permission scope to check.
* @return True if the resource is shared with the entity and scope, false otherwise.
*/
private boolean checkSharing(ResourceSharing document, EntityType entityType, String identifier, String scope) {
private boolean checkSharing(ResourceSharing document, Recipient recipient, String identifier, String scope) {
if (document.getShareWith() == null) {
return false;
}
Expand All @@ -320,11 +334,12 @@ private boolean checkSharing(ResourceSharing document, EntityType entityType, St
.findFirst()
.map(sharedWithScope -> {
SharedWithScope.ScopeRecipients scopePermissions = sharedWithScope.getSharedWithPerScope();
Map<RecipientType, Set<String>> recipients = scopePermissions.getRecipients();

return switch (entityType) {
case EntityType.USERS -> scopePermissions.getUsers().contains(identifier);
case EntityType.ROLES -> scopePermissions.getRoles().contains(identifier);
case EntityType.BACKEND_ROLES -> scopePermissions.getBackendRoles().contains(identifier);
return switch (recipient) {
case Recipient.USERS, Recipient.ROLES, Recipient.BACKEND_ROLES -> recipients.get(
RecipientTypeRegistry.fromValue(recipient.getName())
).contains(identifier);
};
})
.orElse(false); // Return false if no matching scope is found
Expand Down
Loading

0 comments on commit 13fdb81

Please sign in to comment.