From 13262cd60ac37f91d83f96b8dba79a2984dcb107 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 12 Aug 2024 14:49:13 -0400 Subject: [PATCH] Expand RoleV7 to include Resources Signed-off-by: Stephen Crawford --- .../security/securityconf/ConfigModelV7.java | 130 ++++++++++++++++++ .../security/securityconf/impl/v7/RoleV7.java | 62 +++++++++ 2 files changed, 192 insertions(+) diff --git a/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java b/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java index 84902bba3e..fd7e982526 100644 --- a/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java +++ b/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java @@ -63,6 +63,7 @@ import org.opensearch.security.securityconf.impl.v7.RoleMappingsV7; import org.opensearch.security.securityconf.impl.v7.RoleV7; import org.opensearch.security.securityconf.impl.v7.RoleV7.Index; +import org.opensearch.security.securityconf.impl.v7.RoleV7.Resource; import org.opensearch.security.securityconf.impl.v7.TenantV7; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.WildcardMatcher; @@ -179,6 +180,16 @@ public SecurityRole call() throws Exception { } + for (final Resource permittedResourceAliases : securityRole.getValue().getResource_permissions()) { + + for (String resourcePattern : permittedResourceAliases.getResource_patterns()) { + ResourcePattern _resourcePattern = new ResourcePattern(resourcePattern); + _resourcePattern.addPerm(actionGroups.resolve(permittedResourceAliases.getAllowed_actions())); + + _securityRole.addResourcePattern(_resourcePattern); + } + } + return _securityRole.build(); } }); @@ -912,6 +923,125 @@ public Set getPerms() { }*/ + public static class ResourcePattern { + private final String resourcePattern; + private final Set perms = new HashSet<>(); + + public ResourcePattern(String resourcePattern) { + super(); + this.resourcePattern = Objects.requireNonNull(resourcePattern); + } + + public ResourcePattern addPerm(Set perms) { + if (perms != null) { + this.perms.addAll(perms); + } + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((resourcePattern == null) ? 0 : resourcePattern.hashCode()); + result = prime * result + ((perms == null) ? 0 : perms.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + ResourcePattern other = (ResourcePattern) obj; + if (resourcePattern == null) { + if (other.resourcePattern != null) return false; + } else if (!resourcePattern.equals(other.resourcePattern)) return false; + if (perms == null) { + if (other.perms != null) return false; + } else if (!perms.equals(other.perms)) return false; + return true; + } + + @Override + public String toString() { + return System.lineSeparator() + + " resourcePattern=" + + resourcePattern + + System.lineSeparator() + + " perms=" + + perms; + } + + public String getUnresolvedResourcePattern(User user) { + return UserAttributes.replaceProperties(resourcePattern, user); + } + + /** Finds the resources accessible to the user and resolves them to concrete names */ + public Set concreteResourceNames(final User user, final ResourceNameExpressionResolver resolver, final ClusterService cs) { + return getResolvedResourcePattern(user, resolver, cs, false); + } + + /** Finds the resources accessible to the user and attempts to resolve them to names, also includes any unresolved names */ + public Set attemptResolveIndexNames(final User user, final ResourceNameExpressionResolver resolver, final ClusterService cs) { + return getResolvedResourcePattern(user, resolver, cs, true); + } + + + public Set getResolvedResourcePattern( + final User user, + final ResourceNameExpressionResolver resolver, + final ClusterService cs, + final boolean appendUnresolved + ) { + final String unresolved = getUnresolvedResourcePattern(user); + final ImmutableSet.Builder resolvedResources = new ImmutableSet.Builder<>(); + + final WildcardMatcher matcher = WildcardMatcher.from(unresolved); + boolean includeDataStreams = true; + if (!(matcher instanceof WildcardMatcher.Exact)) { + final String[] aliasesAndDataStreamsForPermittedPattern = cs.state() + .getMetadata() + .getResourcesLookup() + .entrySet() + .stream() + .filter(e -> (e.getValue().getType() == ALIAS) || (e.getValue().getType() == DATA_STREAM)) + .filter(e -> matcher.test(e.getKey())) + .map(e -> e.getKey()) + .toArray(String[]::new); + if (aliasesAndDataStreamsForPermittedPattern.length > 0) { + final String[] resolvedAliasesAndDataStreamResources = resolver.concreteResourceNames( + cs.state(), + ResourceOptions.lenientExpandOpen(), + includeDataStreams, + aliasesAndDataStreamsForPermittedPattern + ); + resolvedResources.addAll(Arrays.asList(resolvedAliasesAndDataStreamResources)); + } + } + + if (Strings.isNotBlank(unresolved)) { + final String[] resolvedResourcesFromPattern = resolver.concreteResourceNames( + cs.state(), + ResourceOptions.lenientExpandOpen(), + includeDataStreams, + unresolved + ); + resolvedResources.addAll(Arrays.asList(resolvedResourcesFromPattern)); + } + + if (appendUnresolved || resolvedResources.build().isEmpty()) { + resolvedResources.add(unresolved); + } + return resolvedResources.build(); + } + + public WildcardMatcher getPerms() { + return WildcardMatcher.from(perms); + } + + } + public static class Tenant { private final String tenant; private final boolean readWrite; diff --git a/src/main/java/org/opensearch/security/securityconf/impl/v7/RoleV7.java b/src/main/java/org/opensearch/security/securityconf/impl/v7/RoleV7.java index 229cae0e6f..73396f500b 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/v7/RoleV7.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/v7/RoleV7.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map.Entry; @@ -51,6 +52,7 @@ public class RoleV7 implements Hideable, StaticDefinable { private List cluster_permissions = Collections.emptyList(); private List index_permissions = Collections.emptyList(); private List tenant_permissions = Collections.emptyList(); + private List resource_permissions = Collections.emptyList(); public RoleV7() { @@ -63,6 +65,7 @@ public RoleV7(RoleV6 roleV6) { this.cluster_permissions = roleV6.getCluster(); index_permissions = new ArrayList<>(); tenant_permissions = new ArrayList<>(); + resource_permissions = new ArrayList<>(); for (Entry v6i : roleV6.getIndices().entrySet()) { index_permissions.add(new Index(v6i.getKey(), v6i.getValue())); @@ -225,6 +228,57 @@ public String toString() { } + public static class Resource { + + private String uniqueId; + private List resource_patterns; + private Date lastModifiedAt; + private List allowed_actions = Collections.emptyList(); + + public Resource(String resourceName, List resourcePattern) { + super(); + uniqueId = resourceName; + lastModifiedAt = new Date(); + Set tmpActions = new HashSet<>(); + resource_patterns = resourcePattern; + allowed_actions = new ArrayList<>(tmpActions); + } + + public Resource() { + super(); + } + + public List getAllowed_actions() { + return allowed_actions; + } + + public void setAllowed_actions(List allowed_actions) { + lastModifiedAt = new Date(); + this.allowed_actions = allowed_actions; + } + + public List getResource_patterns() { + return resource_patterns; + } + + public void setResource_patterns(List resource_patterns) { + this.resource_patterns = resource_patterns; + } + + @Override + public String toString() { + return "Resource [uniqueId=" + + uniqueId + + ", lastModifiedAt=" + + lastModifiedAt + + ", resource_patterns=" + + resource_patterns + + ", allowed_actions=" + + allowed_actions + + "]"; + } + } + public boolean isHidden() { return hidden; } @@ -265,6 +319,14 @@ public void setTenant_permissions(List tenant_permissions) { this.tenant_permissions = tenant_permissions; } + public List getResource_permissions() { + return resource_permissions; + } + + public void setResource_permissions(List resource_permissions) { + this.resource_permissions = resource_permissions; + } + public boolean isReserved() { return reserved; }