Skip to content

Commit 20b53f3

Browse files
authored
Merge branch 'main' into search_relevance_role_updates
2 parents 1333ed9 + ac718cc commit 20b53f3

File tree

13 files changed

+234
-28
lines changed

13 files changed

+234
-28
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1414
* Added new option skip_users to client cert authenticator (clientcert_auth_domain.http_authenticator.config.skip_users in config.yml)([#4378](https://github.com/opensearch-project/security/pull/5525))
1515
* [Resource Sharing] Fixes accessible resource ids search by marking created_by.user field as keyword search instead of text ([#5574](https://github.com/opensearch-project/security/pull/5574))
1616
* [Resource Sharing] Reverts @Inject pattern usage for ResourceSharingExtension to client accessor pattern. ([#5576](https://github.com/opensearch-project/security/pull/5576))
17+
* Inject user custom attributes when injecting user and role information to the thread context ([#5560](https://github.com/opensearch-project/security/pull/5560))
1718

1819
### Refactoring
1920

@@ -30,6 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
3031
- Bump `org.springframework.kafka:spring-kafka-test` from 4.0.0-M3 to 4.0.0-M4 ([#5583](https://github.com/opensearch-project/security/pull/5583))
3132
- Bump `net.bytebuddy:byte-buddy` from 1.17.6 to 1.17.7 ([#5586](https://github.com/opensearch-project/security/pull/5586))
3233
- Bump `io.dropwizard.metrics:metrics-core` from 4.2.33 to 4.2.34 ([#5589](https://github.com/opensearch-project/security/pull/5589))
34+
- Bump `com.nimbusds:nimbus-jose-jwt:9.48` from 9.48 to 10.4.2 ([#5595](https://github.com/opensearch-project/security/pull/5595))
3335

3436
### Documentation
3537

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ dependencies {
664664
implementation "org.bouncycastle:bcpkix-fips:${versions.bouncycastle_pkix}"
665665
implementation "org.bouncycastle:bcutil-fips:${versions.bouncycastle_util}"
666666
implementation 'org.ldaptive:ldaptive:1.2.3'
667-
implementation 'com.nimbusds:nimbus-jose-jwt:9.48'
667+
implementation 'com.nimbusds:nimbus-jose-jwt:10.4.2'
668668
implementation 'com.rfksystems:blake2b:2.0.0'
669669
implementation "com.password4j:password4j:${versions.password4j}"
670670
implementation "com.github.seancfoley:ipaddress:5.5.1"

src/integrationTest/java/org/opensearch/security/privileges/dlsfls/DocumentPrivilegesTest.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import static org.junit.Assert.assertEquals;
7070
import static org.junit.Assert.assertFalse;
7171
import static org.junit.Assert.assertNotEquals;
72+
import static org.junit.Assert.assertNotNull;
7273
import static org.junit.Assert.assertTrue;
7374
import static org.junit.Assert.fail;
7475

@@ -94,7 +95,6 @@
9495
DocumentPrivilegesTest.DataStreams_getRestriction.class,
9596
DocumentPrivilegesTest.DlsQuery.class })
9697
public class DocumentPrivilegesTest {
97-
9898
static NamedXContentRegistry xContentRegistry = new NamedXContentRegistry(
9999
ImmutableList.of(
100100
new NamedXContentRegistry.Entry(
@@ -364,23 +364,25 @@ public void queryPatternTemplate() throws Exception {
364364
new TestSecurityConfig.Role("non_dls_role").indexPermissions("*").on("index_a*")
365365
);
366366

367-
DocumentPrivileges subject = createSubject(roleConfig);
367+
Exception exception = null;
368+
DlsRestriction dlsRestriction = null;
369+
DocumentPrivileges subject = null;
368370

369-
DlsRestriction dlsRestriction = subject.getRestriction(context, index.getName());
371+
try {
372+
subject = createSubject(roleConfig);
373+
dlsRestriction = subject.getRestriction(context, index.getName());
374+
} catch (PrivilegesEvaluationException ex) {
375+
exception = ex;
376+
}
370377

371378
if (index == index_b1) {
372379
// This test case never grants privileges to index_b1
373380
assertThat(dlsRestriction, isFullyRestricted());
374381
} else if (userSpec.attributes.isEmpty()) {
375-
// If a role uses undefined user attributes for DLS queries, the attribute templates
376-
// remain unchanged in the resulting query. This is a property of the current attribute handling code.
377-
// It would be probably better if an error would be raised in that case.
382+
// If a role uses undefined user attributes for DLS queries, an exception should be raised
378383
if (index == index_a1) {
379384
if (userSpec.roles.contains("dls_role_1") && userSpec.roles.contains("dls_role_2")) {
380-
assertThat(
381-
dlsRestriction,
382-
isRestricted(termQuery("dept", "${attr.attr_a}1"), termQuery("dept", "${attr.attr_a}2"))
383-
);
385+
assertNotNull(exception);
384386
}
385387
}
386388
} else if (userSpec.roles.contains("non_dls_role") && dfmEmptyOverridesAll) {
@@ -417,7 +419,7 @@ public void queryPatternTemplate() throws Exception {
417419
}
418420

419421
boolean isUnrestricted = subject.isUnrestricted(context, index.getName());
420-
if (dlsRestriction.isUnrestricted()) {
422+
if (dlsRestriction != null && dlsRestriction.isUnrestricted()) {
421423
assertTrue("isUnrestricted() should return true according to " + dlsRestriction, isUnrestricted);
422424
} else {
423425
assertFalse("isUnrestricted() should return false according to " + dlsRestriction, isUnrestricted);

src/main/java/org/opensearch/security/auth/RolesInjector.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package org.opensearch.security.auth;
1717

18+
import java.util.Map;
1819
import java.util.Set;
1920

2021
import com.google.common.collect.ImmutableSet;
@@ -70,7 +71,11 @@ public Set<String> injectUserAndRoles(final ThreadPool threadPool) {
7071
return null;
7172
}
7273
Set<String> roles = ImmutableSet.copyOf(strs[1].split(","));
73-
User user = new User(strs[0]).withSecurityRoles(roles);
74+
75+
Map<String, String> customAttributes = threadPool.getThreadContext()
76+
.getTransient(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_USER_CUSTOM_ATTRIBUTES);
77+
78+
User user = new User(strs[0]).withSecurityRoles(roles).withAttributes(customAttributes);
7479

7580
addUser(user, threadPool);
7681
return roles;

src/main/java/org/opensearch/security/privileges/IndexPattern.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ public void add(List<String> source) {
220220

221221
if (indexPattern.startsWith("<") && indexPattern.endsWith(">")) {
222222
this.dateMathExpressions.add(indexPattern);
223-
} else if (!containsPlaceholder(indexPattern)) {
223+
} else if (!UserAttributes.needsAttributeSubstitution(indexPattern)) {
224224
this.constantPatterns.add(WildcardMatcher.from(indexPattern));
225225
} else {
226226
this.patternTemplates.add(indexPattern);
@@ -241,10 +241,6 @@ public IndexPattern build() {
241241
}
242242
}
243243

244-
static boolean containsPlaceholder(String indexPattern) {
245-
return indexPattern.indexOf("${") != -1;
246-
}
247-
248244
public static IndexPattern from(List<String> source) {
249245
Builder builder = new Builder();
250246
builder.add(source);

src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
package org.opensearch.security.privileges;
2828

29-
import java.io.Serializable;
3029
import java.util.ArrayList;
3130
import java.util.Arrays;
3231
import java.util.Collections;
@@ -307,7 +306,7 @@ private void setUserInfoInThreadContext(PrivilegesEvaluationContext context) {
307306
log.debug(joiner);
308307

309308
if (this.isUserAttributeSerializationEnabled()) {
310-
joiner.add(Base64Helper.serializeObject((Serializable) context.getUser().getCustomAttributesMap()));
309+
joiner.add(Base64Helper.serializeObject(new HashMap<>(context.getUser().getCustomAttributesMap())));
311310
}
312311

313312
threadContext.putTransient(OPENDISTRO_SECURITY_USER_INFO_THREAD_CONTEXT, joiner.toString());

src/main/java/org/opensearch/security/privileges/TenantPrivileges.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public TenantPrivileges(
104104
for (RoleV7.Tenant tenantPermissions : role.getTenant_permissions()) {
105105
List<ActionType> actionTypes = resolveActionType(tenantPermissions.getAllowed_actions(), actionGroups);
106106
for (String tenantPattern : tenantPermissions.getTenant_patterns()) {
107-
if (isDynamic(tenantPattern)) {
107+
if (UserAttributes.needsAttributeSubstitution(tenantPattern)) {
108108
// If a tenant pattern contains a user attribute (like ${user.name}), we can only
109109
// do the tenant pattern matching during the actual tenant privilege evaluation, when the user is known.
110110
// Thus, we just keep these patterns here unprocessed
@@ -252,10 +252,6 @@ static List<ActionType> resolveActionType(Collection<String> allowedActions, Fla
252252
}
253253
}
254254

255-
static boolean isDynamic(String tenantPattern) {
256-
return tenantPattern.contains("${");
257-
}
258-
259255
private static ImmutableMap<ActionType, ImmutableCompactSubSet<String>> build(
260256
Map<ActionType, DeduplicatingCompactSubSetBuilder.SubSetBuilder<String>> source,
261257
DeduplicatingCompactSubSetBuilder.Completed<String> completedRoleSetBuilder

src/main/java/org/opensearch/security/privileges/UserAttributes.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
* This code was moved over from ConfigModelV7.
2626
*/
2727
public class UserAttributes {
28+
public static boolean needsAttributeSubstitution(String patternString) {
29+
return patternString.contains("${");
30+
}
31+
2832
public static String replaceProperties(String orig, PrivilegesEvaluationContext context) {
2933
User user = context.getUser();
3034

src/main/java/org/opensearch/security/privileges/dlsfls/DocumentPrivileges.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import org.apache.logging.log4j.util.Strings;
2020

21+
import org.opensearch.OpenSearchSecurityException;
2122
import org.opensearch.cluster.metadata.IndexAbstraction;
2223
import org.opensearch.common.settings.Settings;
2324
import org.opensearch.common.xcontent.json.JsonXContent;
@@ -44,7 +45,6 @@
4445
* Instances of this class are managed by DlsFlsProcessedConfig.
4546
*/
4647
public class DocumentPrivileges extends AbstractRuleBasedPrivileges<DocumentPrivileges.DlsQuery, DlsRestriction> {
47-
4848
private final NamedXContentRegistry xContentRegistry;
4949

5050
public DocumentPrivileges(
@@ -134,7 +134,7 @@ protected QueryBuilder parseQuery(String queryString, NamedXContentRegistry xCon
134134

135135
static DlsQuery create(String queryString, NamedXContentRegistry xContentRegistry)
136136
throws PrivilegesConfigurationValidationException {
137-
if (queryString.contains("${")) {
137+
if (UserAttributes.needsAttributeSubstitution(queryString)) {
138138
return new DlsQuery.Dynamic(queryString, xContentRegistry);
139139
} else {
140140
return new DlsQuery.Constant(queryString, xContentRegistry);
@@ -174,6 +174,12 @@ static class Dynamic extends DlsQuery {
174174
@Override
175175
RenderedDlsQuery evaluate(PrivilegesEvaluationContext context) throws PrivilegesEvaluationException {
176176
String effectiveQueryString = UserAttributes.replaceProperties(this.queryString, context);
177+
if (UserAttributes.needsAttributeSubstitution(effectiveQueryString)) {
178+
throw new PrivilegesEvaluationException(
179+
"Invalid DLS query: " + effectiveQueryString,
180+
new OpenSearchSecurityException("User attribute substitution failed")
181+
);
182+
}
177183
try {
178184
return new RenderedDlsQuery(parseQuery(effectiveQueryString, xContentRegistry), effectiveQueryString);
179185
} catch (Exception e) {

src/main/java/org/opensearch/security/support/ConfigConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ public class ConfigConstants {
131131

132132
public static final String OPENDISTRO_SECURITY_INJECTED_USER = "injected_user";
133133
public static final String OPENDISTRO_SECURITY_INJECTED_USER_HEADER = "injected_user_header";
134+
public static final String OPENDISTRO_SECURITY_INJECTED_USER_CUSTOM_ATTRIBUTES = "injected_user_custom_attributes";
134135

135136
public static final String OPENDISTRO_SECURITY_XFF_DONE = OPENDISTRO_SECURITY_CONFIG_PREFIX + "xff_done";
136137

0 commit comments

Comments
 (0)