Skip to content
This repository was archived by the owner on Aug 2, 2022. It is now read-only.

Commit 96ef5eb

Browse files
authored
Support for parsing requested tenant from the thread context transient info (#11)
1 parent 71a6b49 commit 96ef5eb

File tree

2 files changed

+123
-11
lines changed
  • src
    • main/java/com/amazon/opendistroforelasticsearch/commons/authuser
    • test/java/com/amazon/opendistroforelasticsearch/commons/authuser

2 files changed

+123
-11
lines changed

src/main/java/com/amazon/opendistroforelasticsearch/commons/authuser/User.java

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import java.util.Arrays;
2323
import java.util.List;
2424
import java.util.Map;
25+
import java.util.Objects;
2526

2627
import org.apache.http.util.EntityUtils;
2728
import org.elasticsearch.client.Response;
29+
import org.elasticsearch.common.Nullable;
2830
import org.elasticsearch.common.Strings;
2931
import org.elasticsearch.common.inject.internal.ToStringBuilder;
3032
import org.elasticsearch.common.io.stream.StreamInput;
@@ -47,24 +49,43 @@ final public class User implements Writeable, ToXContent {
4749
public static final String BACKEND_ROLES_FIELD = "backend_roles";
4850
public static final String ROLES_FIELD = "roles";
4951
public static final String CUSTOM_ATTRIBUTE_NAMES_FIELD = "custom_attribute_names";
52+
public static final String REQUESTED_TENANT_FIELD = "user_requested_tenant";
5053

5154
private final String name;
5255
private final List<String> backendRoles;
5356
private final List<String> roles;
5457
private final List<String> customAttNames;
58+
@Nullable
59+
private final String requestedTenant;
5560

5661
public User() {
5762
name = "";
5863
backendRoles = new ArrayList<>();
5964
roles = new ArrayList<>();
6065
customAttNames = new ArrayList<>();
66+
requestedTenant = null;
6167
}
6268

6369
public User(final String name, final List<String> backendRoles, List<String> roles, List<String> customAttNames) {
6470
this.name = name;
6571
this.backendRoles = backendRoles;
6672
this.roles = roles;
6773
this.customAttNames = customAttNames;
74+
this.requestedTenant = null;
75+
}
76+
77+
public User(
78+
final String name,
79+
final List<String> backendRoles,
80+
final List<String> roles,
81+
final List<String> customAttNames,
82+
@Nullable final String requestedTenant
83+
) {
84+
this.name = name;
85+
this.backendRoles = backendRoles;
86+
this.roles = roles;
87+
this.customAttNames = customAttNames;
88+
this.requestedTenant = requestedTenant;
6889
}
6990

7091
/**
@@ -87,20 +108,23 @@ public User(String json) {
87108
backendRoles = (List<String>) mapValue.get("backend_roles");
88109
roles = (List<String>) mapValue.get("roles");
89110
customAttNames = (List<String>) mapValue.get("custom_attribute_names");
111+
requestedTenant = (String) mapValue.getOrDefault("user_requested_tenant", null);
90112
}
91113

92114
public User(StreamInput in) throws IOException {
93115
name = in.readString();
94116
backendRoles = in.readStringList();
95117
roles = in.readStringList();
96118
customAttNames = in.readStringList();
119+
requestedTenant = in.readOptionalString();
97120
}
98121

99122
public static User parse(XContentParser parser) throws IOException {
100123
String name = "";
101124
List<String> backendRoles = new ArrayList<>();
102125
List<String> roles = new ArrayList<>();
103126
List<String> customAttNames = new ArrayList<>();
127+
String requestedTenant = null;
104128

105129
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser);
106130
while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
@@ -128,11 +152,14 @@ public static User parse(XContentParser parser) throws IOException {
128152
customAttNames.add(parser.text());
129153
}
130154
break;
155+
case REQUESTED_TENANT_FIELD:
156+
requestedTenant = parser.textOrNull();
157+
break;
131158
default:
132159
break;
133160
}
134161
}
135-
return new User(name, backendRoles, roles, customAttNames);
162+
return new User(name, backendRoles, roles, customAttNames, requestedTenant);
136163
}
137164

138165
/**
@@ -153,14 +180,18 @@ public static User parse(final String userString) {
153180
String userName = strs[0].trim();
154181
List<String> backendRoles = new ArrayList<>();
155182
List<String> roles = new ArrayList<>();
183+
String requestedTenant = null;
156184

157185
if ((strs.length > 1) && !Strings.isNullOrEmpty(strs[1])) {
158186
backendRoles.addAll(Arrays.asList(strs[1].split(",")));
159187
}
160188
if ((strs.length > 2) && !Strings.isNullOrEmpty(strs[2])) {
161189
roles.addAll(Arrays.asList(strs[2].split(",")));
162190
}
163-
return new User(userName, backendRoles, roles, Arrays.asList());
191+
if ((strs.length > 3) && !Strings.isNullOrEmpty(strs[3])) {
192+
requestedTenant = strs[3].trim();
193+
}
194+
return new User(userName, backendRoles, roles, Arrays.asList(), requestedTenant);
164195
}
165196

166197
@Override
@@ -170,7 +201,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
170201
.field(NAME_FIELD, name)
171202
.field(BACKEND_ROLES_FIELD, backendRoles)
172203
.field(ROLES_FIELD, roles)
173-
.field(CUSTOM_ATTRIBUTE_NAMES_FIELD, customAttNames);
204+
.field(CUSTOM_ATTRIBUTE_NAMES_FIELD, customAttNames)
205+
.field(REQUESTED_TENANT_FIELD, requestedTenant);
174206
return builder.endObject();
175207
}
176208

@@ -180,6 +212,7 @@ public void writeTo(StreamOutput out) throws IOException {
180212
out.writeStringCollection(backendRoles);
181213
out.writeStringCollection(roles);
182214
out.writeStringCollection(customAttNames);
215+
out.writeOptionalString(requestedTenant);
183216
}
184217

185218
@Override
@@ -189,16 +222,21 @@ public String toString() {
189222
builder.add(BACKEND_ROLES_FIELD, backendRoles);
190223
builder.add(ROLES_FIELD, roles);
191224
builder.add(CUSTOM_ATTRIBUTE_NAMES_FIELD, customAttNames);
225+
builder.add(REQUESTED_TENANT_FIELD, requestedTenant);
192226
return builder.toString();
193227
}
194228

195229
@Override
196230
public boolean equals(Object obj) {
231+
if (!(obj instanceof User)) {
232+
return false;
233+
}
197234
User that = (User) obj;
198235
return this.name.equals(that.name)
199236
&& this.getBackendRoles().equals(that.backendRoles)
200237
&& this.getRoles().equals(that.roles)
201-
&& this.getCustomAttNames().equals(that.customAttNames);
238+
&& this.getCustomAttNames().equals(that.customAttNames)
239+
&& (Objects.equals(this.requestedTenant, that.requestedTenant));
202240
}
203241

204242
public String getName() {
@@ -216,4 +254,9 @@ public List<String> getRoles() {
216254
public List<String> getCustomAttNames() {
217255
return customAttNames;
218256
}
257+
258+
@Nullable
259+
public String getRequestedTenant() {
260+
return requestedTenant;
261+
}
219262
}

src/test/java/com/amazon/opendistroforelasticsearch/commons/authuser/UserTest.java

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static com.amazon.opendistroforelasticsearch.commons.ConfigConstants.OPENDISTRO_SECURITY_USER_AND_ROLES;
1919
import static org.junit.Assert.assertEquals;
2020
import static org.junit.Assert.assertFalse;
21+
import static org.junit.Assert.assertNull;
2122
import static org.junit.Assert.assertTrue;
2223

2324
import java.io.IOException;
@@ -32,30 +33,46 @@
3233

3334
public class UserTest {
3435

35-
User testUser() {
36+
User testNoTenantUser() {
3637
return new User("chip", Arrays.asList("admin", "ops"), Arrays.asList("ops_data"), Arrays.asList("attr1", "attr2"));
3738
}
3839

40+
User testTenantUser() {
41+
return new User("chip", Arrays.asList("admin", "ops"), Arrays.asList("ops_data"), Arrays.asList("attr1", "attr2"), "__user__");
42+
}
43+
3944
@Test
4045
public void testEmptyConst() {
4146
User user = new User();
4247
assertEquals("", user.getName());
4348
assertEquals(0, user.getBackendRoles().size());
4449
assertEquals(0, user.getRoles().size());
4550
assertEquals(0, user.getCustomAttNames().size());
51+
assertEquals(null, user.getRequestedTenant());
52+
}
53+
54+
@Test
55+
public void testParamsConstForNoTenantUser() {
56+
User user = testNoTenantUser();
57+
assertFalse(Strings.isNullOrEmpty(user.getName()));
58+
assertEquals(2, user.getBackendRoles().size());
59+
assertEquals(1, user.getRoles().size());
60+
assertEquals(2, user.getCustomAttNames().size());
61+
assertNull(user.getRequestedTenant());
4662
}
4763

4864
@Test
49-
public void testParamsConst() {
50-
User user = testUser();
65+
public void testParamsConstForTenantUser() {
66+
User user = testTenantUser();
5167
assertFalse(Strings.isNullOrEmpty(user.getName()));
5268
assertEquals(2, user.getBackendRoles().size());
5369
assertEquals(1, user.getRoles().size());
5470
assertEquals(2, user.getCustomAttNames().size());
71+
assertFalse(Strings.isNullOrEmpty(user.getRequestedTenant()));
5572
}
5673

5774
@Test
58-
public void testJsonConst() throws IOException {
75+
public void testNullTenantJsonConst() throws IOException {
5976
String json =
6077
"{\"user\":\"User [name=chip, backend_roles=[admin], requestedTenant=null]\",\"user_name\":\"chip\",\"user_requested_tenant\":null,\"remote_address\":\"127.0.0.1:52196\",\"backend_roles\":[\"admin\"],\"custom_attribute_names\":[],\"roles\":[\"alerting_monitor_full\",\"ops_role\",\"own_index\"],\"tenants\":{\"chip\":true},\"principal\":null,\"peer_certificates\":\"0\",\"sso_logout_url\":null}";
6178

@@ -64,11 +81,36 @@ public void testJsonConst() throws IOException {
6481
assertEquals(1, user.getBackendRoles().size());
6582
assertEquals(3, user.getRoles().size());
6683
assertEquals(0, user.getCustomAttNames().size());
84+
assertNull(user.getRequestedTenant());
85+
}
86+
87+
@Test
88+
public void testNonNullTenantJsonConst() throws IOException {
89+
String json =
90+
"{\"user\":\"User [name=chip, backend_roles=[admin], requestedTenant=__user__]\",\"user_name\":\"chip\",\"user_requested_tenant\":\"__user__\",\"remote_address\":\"127.0.0.1:52196\",\"backend_roles\":[\"admin\"],\"custom_attribute_names\":[],\"roles\":[\"alerting_monitor_full\",\"ops_role\",\"own_index\"],\"tenants\":{\"chip\":true},\"principal\":null,\"peer_certificates\":\"0\",\"sso_logout_url\":null}";
91+
92+
User user = new User(json);
93+
assertEquals("chip", user.getName());
94+
assertEquals(1, user.getBackendRoles().size());
95+
assertEquals(3, user.getRoles().size());
96+
assertEquals(0, user.getCustomAttNames().size());
97+
assertEquals("__user__", user.getRequestedTenant());
98+
}
99+
100+
@Test
101+
public void testStreamConstForNoTenantUser() throws IOException {
102+
User user = testNoTenantUser();
103+
BytesStreamOutput out = new BytesStreamOutput();
104+
user.writeTo(out);
105+
StreamInput in = StreamInput.wrap(out.bytes().toBytesRef().bytes);
106+
User newUser = new User(in);
107+
assertEquals("Round tripping User doesn't work", user.toString(), newUser.toString());
108+
assertEquals("Round tripping User doesn't work", user, newUser);
67109
}
68110

69111
@Test
70-
public void testStreamConst() throws IOException {
71-
User user = testUser();
112+
public void testStreamConstForTenantUser() throws IOException {
113+
User user = testTenantUser();
72114
BytesStreamOutput out = new BytesStreamOutput();
73115
user.writeTo(out);
74116
StreamInput in = StreamInput.wrap(out.bytes().toBytesRef().bytes);
@@ -80,7 +122,7 @@ public void testStreamConst() throws IOException {
80122
@Test
81123
public void testParseUserString() {
82124
ThreadContext tc = new ThreadContext(Settings.EMPTY);
83-
tc.putTransient("user_roles_string", "myuser|bckrole1,bckrol2|role1,role2");
125+
tc.putTransient("user_roles_string", "myuser|bckrole1,bckrol2|role1,role2|myTenant");
84126
String str = tc.getTransient("user_roles_string");
85127
User user = User.parse(str);
86128

@@ -89,6 +131,7 @@ public void testParseUserString() {
89131
assertEquals(2, user.getRoles().size());
90132
assertTrue(user.getRoles().contains("role1"));
91133
assertTrue(user.getRoles().contains("role2"));
134+
assertEquals("myTenant", user.getRequestedTenant());
92135
}
93136

94137
@Test
@@ -111,6 +154,19 @@ public void testParseUserStringName() {
111154
assertEquals(0, user.getRoles().size());
112155
}
113156

157+
@Test
158+
public void testParseUserStringNameWithTenant() {
159+
ThreadContext tc = new ThreadContext(Settings.EMPTY);
160+
tc.putTransient(OPENDISTRO_SECURITY_USER_AND_ROLES, "myuser|||myTenant");
161+
String str = tc.getTransient(OPENDISTRO_SECURITY_USER_AND_ROLES);
162+
User user = User.parse(str);
163+
164+
assertEquals("myuser", user.getName());
165+
assertEquals(0, user.getBackendRoles().size());
166+
assertEquals(0, user.getRoles().size());
167+
assertEquals("myTenant", user.getRequestedTenant());
168+
}
169+
114170
@Test
115171
public void testParseUserStringNobackendRoles() {
116172
ThreadContext tc = new ThreadContext(Settings.EMPTY);
@@ -135,6 +191,19 @@ public void testParseUserStringNoRoles() {
135191
assertEquals(0, user.getRoles().size());
136192
}
137193

194+
@Test
195+
public void testParseUserStringNoRolesWithTenant() {
196+
ThreadContext tc = new ThreadContext(Settings.EMPTY);
197+
tc.putTransient(OPENDISTRO_SECURITY_USER_AND_ROLES, "myuser|brole1,brole2||myTenant");
198+
String str = tc.getTransient(OPENDISTRO_SECURITY_USER_AND_ROLES);
199+
User user = User.parse(str);
200+
201+
assertEquals("myuser", user.getName());
202+
assertEquals(2, user.getBackendRoles().size());
203+
assertEquals(0, user.getRoles().size());
204+
assertEquals("myTenant", user.getRequestedTenant());
205+
}
206+
138207
@Test
139208
public void testParseUserStringMalformed() {
140209
ThreadContext tc = new ThreadContext(Settings.EMPTY);

0 commit comments

Comments
 (0)