From 3f883e3ad0fe4b06fb102e11240f0c6737c0d38a Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 29 Jul 2025 13:52:29 -0400 Subject: [PATCH 1/5] Add tenancy access info to serialized user in threadcontext Signed-off-by: Craig Perkins --- .../privileges/PrivilegesEvaluator.java | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index af5c3c3124..a725da8bb0 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -117,6 +117,12 @@ public class PrivilegesEvaluator { + private static final String USER_TENANT = "__user__"; + private static final String GLOBAL_TENANT = "global_tenant"; + private static final String READ_ACCESS = "READ"; + private static final String WRITE_ACCESS = "WRITE"; + private static final String NO_ACCESS = "NONE"; + static final WildcardMatcher DNFOF_MATCHER = WildcardMatcher.from( ImmutableList.of( "indices:data/read/*", @@ -278,7 +284,7 @@ public boolean isInitialized() { return configModel != null && dcm != null && actionPrivileges.get() != null; } - private void setUserInfoInThreadContext(User user, Set mappedRoles) { + private void setUserInfoInThreadContext(User user, Set mappedRoles, PrivilegesEvaluationContext context) { if (threadContext.getTransient(OPENDISTRO_SECURITY_USER_INFO_THREAD_CONTEXT) == null) { StringJoiner joiner = new StringJoiner("|"); // Escape any pipe characters in the values before joining @@ -287,9 +293,10 @@ private void setUserInfoInThreadContext(User user, Set mappedRoles) { joiner.add(escapePipe(String.join(",", mappedRoles))); String requestedTenant = user.getRequestedTenant(); - if (!Strings.isNullOrEmpty(requestedTenant)) { - joiner.add(escapePipe(requestedTenant)); - } + joiner.add(requestedTenant); + String tenantAccessToCheck = getTenancyAccess(requestedTenant, this.tenantPrivileges.get().tenantMap(context)); + joiner.add(tenantAccessToCheck); + log.debug(joiner); threadContext.putTransient(OPENDISTRO_SECURITY_USER_INFO_THREAD_CONTEXT, joiner.toString()); } } @@ -298,6 +305,19 @@ public PrivilegesEvaluationContext createContext(User user, String action) { return createContext(user, action, null, null, null); } + private String getTenancyAccess(String requestedTenant, Map tenancyAccessMap) { + final String tenant = Strings.isNullOrEmpty(requestedTenant) ? GLOBAL_TENANT : requestedTenant; + if (tenant.equals(USER_TENANT)) { + return WRITE_ACCESS; + } else { + if (tenancyAccessMap == null || !tenancyAccessMap.containsKey(tenant)) { + return NO_ACCESS; + } else { + return tenancyAccessMap.get(tenant) ? WRITE_ACCESS : READ_ACCESS; + } + } + } + public PrivilegesEvaluationContext createContext( User user, String action0, @@ -387,7 +407,7 @@ public PrivilegesEvaluatorResponse evaluate(PrivilegesEvaluationContext context) context.setMappedRoles(mappedRoles); } - setUserInfoInThreadContext(user, mappedRoles); + setUserInfoInThreadContext(user, mappedRoles, context); final boolean isDebugEnabled = log.isDebugEnabled(); if (isDebugEnabled) { From 91d2af2975dcc266ed57463a2033de31ba7e483d Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 29 Jul 2025 13:58:21 -0400 Subject: [PATCH 2/5] Only use context Signed-off-by: Craig Perkins --- .../security/privileges/PrivilegesEvaluator.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index a725da8bb0..afd35583cc 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -284,15 +284,15 @@ public boolean isInitialized() { return configModel != null && dcm != null && actionPrivileges.get() != null; } - private void setUserInfoInThreadContext(User user, Set mappedRoles, PrivilegesEvaluationContext context) { + private void setUserInfoInThreadContext(PrivilegesEvaluationContext context) { if (threadContext.getTransient(OPENDISTRO_SECURITY_USER_INFO_THREAD_CONTEXT) == null) { StringJoiner joiner = new StringJoiner("|"); // Escape any pipe characters in the values before joining - joiner.add(escapePipe(user.getName())); - joiner.add(escapePipe(String.join(",", user.getRoles()))); - joiner.add(escapePipe(String.join(",", mappedRoles))); + joiner.add(escapePipe(context.getUser().getName())); + joiner.add(escapePipe(String.join(",", context.getUser().getRoles()))); + joiner.add(escapePipe(String.join(",", context.getMappedRoles()))); - String requestedTenant = user.getRequestedTenant(); + String requestedTenant = context.getUser().getRequestedTenant(); joiner.add(requestedTenant); String tenantAccessToCheck = getTenancyAccess(requestedTenant, this.tenantPrivileges.get().tenantMap(context)); joiner.add(tenantAccessToCheck); @@ -407,7 +407,7 @@ public PrivilegesEvaluatorResponse evaluate(PrivilegesEvaluationContext context) context.setMappedRoles(mappedRoles); } - setUserInfoInThreadContext(user, mappedRoles, context); + setUserInfoInThreadContext(context); final boolean isDebugEnabled = log.isDebugEnabled(); if (isDebugEnabled) { From f4a9f8ede0016e7aee3edc794c93bd03f6f8dfbd Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 30 Jul 2025 10:15:26 -0400 Subject: [PATCH 3/5] Use hasTenantPrivileges Signed-off-by: Craig Perkins --- .../security/privileges/PrivilegesEvaluator.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index afd35583cc..e1c1f570e7 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -294,7 +294,7 @@ private void setUserInfoInThreadContext(PrivilegesEvaluationContext context) { String requestedTenant = context.getUser().getRequestedTenant(); joiner.add(requestedTenant); - String tenantAccessToCheck = getTenancyAccess(requestedTenant, this.tenantPrivileges.get().tenantMap(context)); + String tenantAccessToCheck = getTenancyAccess(requestedTenant); joiner.add(tenantAccessToCheck); log.debug(joiner); threadContext.putTransient(OPENDISTRO_SECURITY_USER_INFO_THREAD_CONTEXT, joiner.toString()); @@ -305,16 +305,15 @@ public PrivilegesEvaluationContext createContext(User user, String action) { return createContext(user, action, null, null, null); } - private String getTenancyAccess(String requestedTenant, Map tenancyAccessMap) { + private String getTenancyAccess(PrivilegesEvaluationContext context) { + String requestedTenant = context.getUser().getRequestedTenant(); final String tenant = Strings.isNullOrEmpty(requestedTenant) ? GLOBAL_TENANT : requestedTenant; - if (tenant.equals(USER_TENANT)) { + if (tenantPrivileges.get().hasTenantPrivilege(context, tenant, TenantPrivileges.ActionType.WRITE)) { return WRITE_ACCESS; + } else if (tenantPrivileges.get().hasTenantPrivilege(context, tenant, TenantPrivileges.ActionType.READ)) { + return READ_ACCESS; } else { - if (tenancyAccessMap == null || !tenancyAccessMap.containsKey(tenant)) { - return NO_ACCESS; - } else { - return tenancyAccessMap.get(tenant) ? WRITE_ACCESS : READ_ACCESS; - } + return NO_ACCESS; } } From fc787c9222c50511a17916d0a6589a3753b534be Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 30 Jul 2025 10:18:03 -0400 Subject: [PATCH 4/5] Add to CHANGELOG Signed-off-by: Craig Perkins --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b12f9c7a32..1dca842baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), * Refactor JWT Vender to take a claims builder and rename oboEnabled to enabled ([#5436](https://github.com/opensearch-project/security/pull/5436)) * Remove ASN1 reflection methods ([#5454](https://github.com/opensearch-project/security/pull/5454)) * Remove provider reflection code ([#5457](https://github.com/opensearch-project/security/pull/5457)) +* Add tenancy access info to serialized user in threadcontext ([#5519](https://github.com/opensearch-project/security/pull/5519)) ### Maintenance - Bump `org.eclipse.platform:org.eclipse.core.runtime` from 3.33.0 to 3.33.100 ([#5400](https://github.com/opensearch-project/security/pull/5400)) From 006d83976f64d6783b935635f50a0a2aeb8ad7c1 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 30 Jul 2025 10:32:38 -0400 Subject: [PATCH 5/5] Pass the correct param Signed-off-by: Craig Perkins --- .../org/opensearch/security/privileges/PrivilegesEvaluator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index e1c1f570e7..fb94e0900e 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -294,7 +294,7 @@ private void setUserInfoInThreadContext(PrivilegesEvaluationContext context) { String requestedTenant = context.getUser().getRequestedTenant(); joiner.add(requestedTenant); - String tenantAccessToCheck = getTenancyAccess(requestedTenant); + String tenantAccessToCheck = getTenancyAccess(context); joiner.add(tenantAccessToCheck); log.debug(joiner); threadContext.putTransient(OPENDISTRO_SECURITY_USER_INFO_THREAD_CONTEXT, joiner.toString());