Skip to content

Commit 9bb579f

Browse files
authored
Add tenancy access info to serialized user in threadcontext (#857)
1 parent 09f4cd6 commit 9bb579f

File tree

2 files changed

+98
-4
lines changed

2 files changed

+98
-4
lines changed

src/main/java/org/opensearch/commons/authuser/User.java

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

1919
import org.apache.hc.core5.http.ParseException;
2020
import org.apache.hc.core5.http.io.entity.EntityUtils;
21+
import org.opensearch.Version;
2122
import org.opensearch.client.Response;
2223
import org.opensearch.common.Nullable;
2324
import org.opensearch.common.inject.internal.ToStringBuilder;
@@ -45,20 +46,24 @@ final public class User implements Writeable, ToXContent {
4546
public static final String ROLES_FIELD = "roles";
4647
public static final String CUSTOM_ATTRIBUTE_NAMES_FIELD = "custom_attribute_names";
4748
public static final String REQUESTED_TENANT_FIELD = "user_requested_tenant";
49+
public static final String REQUESTED_TENANT_ACCESS = "user_requested_tenant_access";
4850

4951
private final String name;
5052
private final List<String> backendRoles;
5153
private final List<String> roles;
5254
private final List<String> customAttNames;
5355
@Nullable
5456
private final String requestedTenant;
57+
@Nullable
58+
private final String requestedTenantAccess;
5559

5660
public User() {
5761
name = "";
5862
backendRoles = new ArrayList<>();
5963
roles = new ArrayList<>();
6064
customAttNames = new ArrayList<>();
6165
requestedTenant = null;
66+
requestedTenantAccess = null;
6267
}
6368

6469
public User(final String name, final List<String> backendRoles, List<String> roles, List<String> customAttNames) {
@@ -67,6 +72,7 @@ public User(final String name, final List<String> backendRoles, List<String> rol
6772
this.roles = roles;
6873
this.customAttNames = customAttNames;
6974
this.requestedTenant = null;
75+
this.requestedTenantAccess = null;
7076
}
7177

7278
public User(
@@ -81,6 +87,23 @@ public User(
8187
this.roles = roles;
8288
this.customAttNames = customAttNames;
8389
this.requestedTenant = requestedTenant;
90+
this.requestedTenantAccess = null;
91+
}
92+
93+
public User(
94+
final String name,
95+
final List<String> backendRoles,
96+
final List<String> roles,
97+
final List<String> customAttNames,
98+
@Nullable final String requestedTenant,
99+
@Nullable final String requestedTenantAccess
100+
) {
101+
this.name = name;
102+
this.backendRoles = backendRoles;
103+
this.roles = roles;
104+
this.customAttNames = customAttNames;
105+
this.requestedTenant = requestedTenant;
106+
this.requestedTenantAccess = requestedTenantAccess;
84107
}
85108

86109
/**
@@ -104,6 +127,7 @@ public User(String json) {
104127
roles = (List<String>) mapValue.get("roles");
105128
customAttNames = (List<String>) mapValue.get("custom_attribute_names");
106129
requestedTenant = (String) mapValue.getOrDefault("user_requested_tenant", null);
130+
requestedTenantAccess = (String) mapValue.getOrDefault("user_requested_tenant_access", null);
107131
}
108132

109133
public User(StreamInput in) throws IOException {
@@ -112,6 +136,11 @@ public User(StreamInput in) throws IOException {
112136
roles = in.readStringList();
113137
customAttNames = in.readStringList();
114138
requestedTenant = in.readOptionalString();
139+
if (in.getVersion().onOrAfter(Version.V_3_2_0)) {
140+
requestedTenantAccess = in.readOptionalString();
141+
} else {
142+
requestedTenantAccess = null;
143+
}
115144
}
116145

117146
public static User parse(XContentParser parser) throws IOException {
@@ -120,6 +149,7 @@ public static User parse(XContentParser parser) throws IOException {
120149
List<String> roles = new ArrayList<>();
121150
List<String> customAttNames = new ArrayList<>();
122151
String requestedTenant = null;
152+
String requestedTenantAccess = null;
123153

124154
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser);
125155
while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
@@ -150,11 +180,14 @@ public static User parse(XContentParser parser) throws IOException {
150180
case REQUESTED_TENANT_FIELD:
151181
requestedTenant = parser.textOrNull();
152182
break;
183+
case REQUESTED_TENANT_ACCESS:
184+
requestedTenantAccess = parser.textOrNull();
185+
break;
153186
default:
154187
break;
155188
}
156189
}
157-
return new User(name, backendRoles, roles, customAttNames, requestedTenant);
190+
return new User(name, backendRoles, roles, customAttNames, requestedTenant, requestedTenantAccess);
158191
}
159192

160193
/**
@@ -178,6 +211,7 @@ public static User parse(final String userString) {
178211
List<String> backendRoles = new ArrayList<>();
179212
List<String> roles = new ArrayList<>();
180213
String requestedTenant = null;
214+
String requestedTenantAccess = null;
181215

182216
if ((strs.length > 1) && !Strings.isNullOrEmpty(strs[1])) {
183217
backendRoles.addAll(Arrays.stream(strs[1].split(",")).map(Utils::unescapePipe).toList());
@@ -188,7 +222,10 @@ public static User parse(final String userString) {
188222
if ((strs.length > 3) && !Strings.isNullOrEmpty(strs[3])) {
189223
requestedTenant = unescapePipe(strs[3].trim());
190224
}
191-
return new User(userName, backendRoles, roles, Arrays.asList(), requestedTenant);
225+
if ((strs.length > 4) && !Strings.isNullOrEmpty(strs[4])) {
226+
requestedTenantAccess = strs[4].trim();
227+
}
228+
return new User(userName, backendRoles, roles, Arrays.asList(), requestedTenant, requestedTenantAccess);
192229
}
193230

194231
@Override
@@ -199,7 +236,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
199236
.field(BACKEND_ROLES_FIELD, backendRoles)
200237
.field(ROLES_FIELD, roles)
201238
.field(CUSTOM_ATTRIBUTE_NAMES_FIELD, customAttNames)
202-
.field(REQUESTED_TENANT_FIELD, requestedTenant);
239+
.field(REQUESTED_TENANT_FIELD, requestedTenant)
240+
.field(REQUESTED_TENANT_ACCESS, requestedTenantAccess);
203241
return builder.endObject();
204242
}
205243

@@ -210,6 +248,9 @@ public void writeTo(StreamOutput out) throws IOException {
210248
out.writeStringCollection(roles);
211249
out.writeStringCollection(customAttNames);
212250
out.writeOptionalString(requestedTenant);
251+
if (out.getVersion().onOrAfter(Version.V_3_2_0)) {
252+
out.writeOptionalString(requestedTenantAccess);
253+
}
213254
}
214255

215256
@Override
@@ -220,6 +261,7 @@ public String toString() {
220261
builder.add(ROLES_FIELD, roles);
221262
builder.add(CUSTOM_ATTRIBUTE_NAMES_FIELD, customAttNames);
222263
builder.add(REQUESTED_TENANT_FIELD, requestedTenant);
264+
builder.add(REQUESTED_TENANT_ACCESS, requestedTenantAccess);
223265
return builder.toString();
224266
}
225267

@@ -233,7 +275,8 @@ public boolean equals(Object obj) {
233275
&& this.getBackendRoles().equals(that.backendRoles)
234276
&& this.getRoles().equals(that.roles)
235277
&& this.getCustomAttNames().equals(that.customAttNames)
236-
&& (Objects.equals(this.requestedTenant, that.requestedTenant));
278+
&& (Objects.equals(this.requestedTenant, that.requestedTenant))
279+
&& (Objects.equals(this.requestedTenantAccess, that.requestedTenantAccess));
237280
}
238281

239282
public String getName() {
@@ -257,6 +300,11 @@ public String getRequestedTenant() {
257300
return requestedTenant;
258301
}
259302

303+
@Nullable
304+
public String getRequestedTenantAccess() {
305+
return requestedTenantAccess;
306+
}
307+
260308
public boolean isAdminDn(Settings settings) {
261309
if (settings == null) {
262310
return false;

src/test/java/org/opensearch/commons/authuser/UserTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ User testNoTenantUser() {
3030
}
3131

3232
User testTenantUser() {
33+
return new User(
34+
"chip",
35+
Arrays.asList("admin", "ops"),
36+
Arrays.asList("ops_data"),
37+
Arrays.asList("attr1", "attr2"),
38+
"__user__",
39+
"WRITE"
40+
);
41+
}
42+
43+
User testTenantUserWithNoAccessInfo() {
3344
return new User("chip", Arrays.asList("admin", "ops"), Arrays.asList("ops_data"), Arrays.asList("attr1", "attr2"), "__user__");
3445
}
3546

@@ -53,6 +64,16 @@ public void testParamsConstForNoTenantUser() {
5364
assertNull(user.getRequestedTenant());
5465
}
5566

67+
@Test
68+
public void testParamsConstForTenantUserWithNoAccessInfo() {
69+
User user = testTenantUserWithNoAccessInfo();
70+
assertFalse(Strings.isNullOrEmpty(user.getName()));
71+
assertEquals(2, user.getBackendRoles().size());
72+
assertEquals(1, user.getRoles().size());
73+
assertEquals(2, user.getCustomAttNames().size());
74+
assertFalse(Strings.isNullOrEmpty(user.getRequestedTenant()));
75+
}
76+
5677
@Test
5778
public void testParamsConstForTenantUser() {
5879
User user = testTenantUser();
@@ -111,6 +132,17 @@ public void testStreamConstForTenantUser() throws IOException {
111132
assertEquals(user, newUser, "Round tripping User doesn't work");
112133
}
113134

135+
@Test
136+
public void testStreamConstForTenantUserWithNoAccessInfo() throws IOException {
137+
User user = testTenantUserWithNoAccessInfo();
138+
BytesStreamOutput out = new BytesStreamOutput();
139+
user.writeTo(out);
140+
StreamInput in = StreamInput.wrap(out.bytes().toBytesRef().bytes);
141+
User newUser = new User(in);
142+
assertEquals(user.toString(), newUser.toString(), "Round tripping User doesn't work");
143+
assertEquals(user, newUser, "Round tripping User doesn't work");
144+
}
145+
114146
@Test
115147
public void testParseUserString() {
116148
ThreadContext tc = new ThreadContext(Settings.EMPTY);
@@ -126,6 +158,20 @@ public void testParseUserString() {
126158
assertEquals("myTenant", user.getRequestedTenant());
127159
}
128160

161+
@Test
162+
public void testParseUserStringNameWithTenantAndAccess() {
163+
ThreadContext tc = new ThreadContext(Settings.EMPTY);
164+
tc.putTransient(OPENSEARCH_SECURITY_USER_INFO_THREAD_CONTEXT, "myuser|||myTenant|NO");
165+
String str = tc.getTransient(OPENSEARCH_SECURITY_USER_INFO_THREAD_CONTEXT);
166+
User user = User.parse(str);
167+
168+
assertEquals("myuser", user.getName());
169+
assertEquals(0, user.getBackendRoles().size());
170+
assertEquals(0, user.getRoles().size());
171+
assertEquals("myTenant", user.getRequestedTenant());
172+
assertEquals("NO", user.getRequestedTenantAccess());
173+
}
174+
129175
@Test
130176
public void testParseUserStringEmpty() {
131177
ThreadContext tc = new ThreadContext(Settings.EMPTY);

0 commit comments

Comments
 (0)