17
17
import org .elasticsearch .core .Tuple ;
18
18
import org .elasticsearch .test .ESTestCase ;
19
19
import org .elasticsearch .xpack .core .security .SecurityContext ;
20
+ import org .elasticsearch .xpack .core .security .action .user .GetUserPrivilegesAction ;
21
+ import org .elasticsearch .xpack .core .security .action .user .GetUserPrivilegesRequest ;
22
+ import org .elasticsearch .xpack .core .security .action .user .GetUserPrivilegesResponse ;
20
23
import org .elasticsearch .xpack .core .security .action .user .HasPrivilegesAction ;
21
24
import org .elasticsearch .xpack .core .security .action .user .HasPrivilegesRequest ;
22
25
import org .elasticsearch .xpack .core .security .action .user .HasPrivilegesResponse ;
23
26
import org .elasticsearch .xpack .core .security .authc .Authentication ;
24
27
import org .elasticsearch .xpack .core .security .authc .AuthenticationTestHelper ;
28
+ import org .elasticsearch .xpack .core .security .authz .RoleDescriptor ;
25
29
import org .elasticsearch .xpack .core .security .authz .permission .ResourcePrivileges ;
26
30
import org .elasticsearch .xpack .core .security .user .User ;
27
31
import org .junit .Before ;
28
- import org .mockito .Mockito ;
29
32
33
+ import java .util .Arrays ;
30
34
import java .util .Collection ;
31
35
import java .util .HashMap ;
32
36
import java .util .Map ;
@@ -50,11 +54,14 @@ public class UserPrivilegeResolverTests extends ESTestCase {
50
54
private SecurityContext securityContext ;
51
55
private UserPrivilegeResolver resolver ;
52
56
57
+ private String app ;
58
+
53
59
@ Before
54
60
@ SuppressWarnings ("unchecked" )
55
61
public void setupTest () {
56
62
client = mock (Client .class );
57
63
securityContext = new SecurityContext (Settings .EMPTY , new ThreadContext (Settings .EMPTY ));
64
+ app = randomAlphaOfLengthBetween (3 , 8 );
58
65
final ApplicationActionsResolver actionsResolver = mock (ApplicationActionsResolver .class );
59
66
doAnswer (inv -> {
60
67
final Object [] args = inv .getArguments ();
@@ -63,12 +70,41 @@ public void setupTest() {
63
70
listener .onResponse (Set .of ("role:cluster:view" , "role:cluster:admin" , "role:cluster:operator" , "role:cluster:monitor" ));
64
71
return null ;
65
72
}).when (actionsResolver ).getActions (anyString (), any (ActionListener .class ));
73
+ doAnswer (inv -> {
74
+ final Object [] args = inv .getArguments ();
75
+ assertThat (args , arrayWithSize (3 ));
76
+ ActionListener <GetUserPrivilegesResponse > listener = (ActionListener <GetUserPrivilegesResponse >) args [args .length - 1 ];
77
+ RoleDescriptor .ApplicationResourcePrivileges appPriv1 = RoleDescriptor .ApplicationResourcePrivileges .builder ()
78
+ .application (app )
79
+ .resources ("resource1" )
80
+ .privileges ("role:extra1" )
81
+ .build ();
82
+ RoleDescriptor .ApplicationResourcePrivileges appPriv2 = RoleDescriptor .ApplicationResourcePrivileges .builder ()
83
+ .application (app )
84
+ .resources ("resource1" )
85
+ .privileges ("role:extra2" , "role:extra3" )
86
+ .build ();
87
+ RoleDescriptor .ApplicationResourcePrivileges discardedAppPriv = RoleDescriptor .ApplicationResourcePrivileges .builder ()
88
+ .application (randomAlphaOfLengthBetween (3 , 8 ))
89
+ .resources ("resource1" )
90
+ .privileges ("role:discarded" )
91
+ .build ();
92
+ GetUserPrivilegesResponse response = new GetUserPrivilegesResponse (
93
+ Set .of (),
94
+ Set .of (),
95
+ Set .of (),
96
+ Set .of (appPriv1 , appPriv2 , discardedAppPriv ),
97
+ Set .of (),
98
+ Set .of ()
99
+ );
100
+ listener .onResponse (response );
101
+ return null ;
102
+ }).when (client ).execute (same (GetUserPrivilegesAction .INSTANCE ), any (GetUserPrivilegesRequest .class ), any (ActionListener .class ));
66
103
resolver = new UserPrivilegeResolver (client , securityContext , actionsResolver );
67
104
}
68
105
69
106
public void testResolveZeroAccess () throws Exception {
70
107
final String username = randomAlphaOfLengthBetween (4 , 12 );
71
- final String app = randomAlphaOfLengthBetween (3 , 8 );
72
108
setupUser (username , () -> {
73
109
setupHasPrivileges (username , app );
74
110
final PlainActionFuture <UserPrivilegeResolver .UserPrivileges > future = new PlainActionFuture <>();
@@ -93,7 +129,6 @@ public void testResolveZeroAccess() throws Exception {
93
129
94
130
public void testResolveSsoWithNoRoleAccess () throws Exception {
95
131
final String username = randomAlphaOfLengthBetween (4 , 12 );
96
- final String app = randomAlphaOfLengthBetween (3 , 8 );
97
132
final String resource = "cluster:" + MessageDigests .toHexString (randomByteArrayOfLength (16 ));
98
133
final String viewerAction = "role:cluster:view" ;
99
134
final String adminAction = "role:cluster:admin" ;
@@ -118,7 +153,6 @@ public void testResolveSsoWithNoRoleAccess() throws Exception {
118
153
119
154
public void testResolveSsoWithSingleRole () throws Exception {
120
155
final String username = randomAlphaOfLengthBetween (4 , 12 );
121
- final String app = randomAlphaOfLengthBetween (3 , 8 );
122
156
final String resource = "cluster:" + MessageDigests .toHexString (randomByteArrayOfLength (16 ));
123
157
final String viewerAction = "role:cluster:view" ;
124
158
final String adminAction = "role:cluster:admin" ;
@@ -143,7 +177,6 @@ public void testResolveSsoWithSingleRole() throws Exception {
143
177
144
178
public void testResolveSsoWithMultipleRoles () throws Exception {
145
179
final String username = randomAlphaOfLengthBetween (4 , 12 );
146
- final String app = randomAlphaOfLengthBetween (3 , 8 );
147
180
final String resource = "cluster:" + MessageDigests .toHexString (randomByteArrayOfLength (16 ));
148
181
final String viewerAction = "role:cluster:view" ;
149
182
final String adminAction = "role:cluster:admin" ;
@@ -183,6 +216,35 @@ public void testResolveSsoWithMultipleRoles() throws Exception {
183
216
});
184
217
}
185
218
219
+ public void testResolveSsoWithActionDefinedInUserPrivileges () throws Exception {
220
+ final String username = randomAlphaOfLengthBetween (4 , 12 );
221
+ final String resource = "cluster:" + MessageDigests .toHexString (randomByteArrayOfLength (16 ));
222
+ final String actionInUserPrivs = "role:extra2" ;
223
+ final String adminAction = "role:cluster:admin" ;
224
+
225
+ setupUser (username , () -> {
226
+ setupHasPrivileges (username , app , access (resource , actionInUserPrivs , true ), access (resource , adminAction , false ));
227
+
228
+ final PlainActionFuture <UserPrivilegeResolver .UserPrivileges > future = new PlainActionFuture <>();
229
+ final Function <String , Set <String >> roleMapping = Map .of (
230
+ actionInUserPrivs ,
231
+ Set .of ("extra2" ),
232
+ adminAction ,
233
+ Set .of ("admin" )
234
+ )::get ;
235
+ resolver .resolve (service (app , resource , roleMapping ), future );
236
+ final UserPrivilegeResolver .UserPrivileges privileges ;
237
+ try {
238
+ privileges = future .get ();
239
+ } catch (Exception e ) {
240
+ throw new RuntimeException (e );
241
+ }
242
+ assertThat (privileges .principal , equalTo (username ));
243
+ assertThat (privileges .hasAccess , equalTo (true ));
244
+ assertThat (privileges .roles , containsInAnyOrder ("extra2" ));
245
+ });
246
+ }
247
+
186
248
private ServiceProviderPrivileges service (String appName , String resource , Function <String , Set <String >> roleMapping ) {
187
249
return new ServiceProviderPrivileges (appName , resource , roleMapping );
188
250
}
@@ -209,10 +271,24 @@ private HasPrivilegesResponse setupHasPrivileges(
209
271
final Map <String , Collection <ResourcePrivileges >> appPrivs = Map .of (appName , privileges );
210
272
final HasPrivilegesResponse response = new HasPrivilegesResponse (username , isCompleteMatch , Map .of (), Set .of (), appPrivs );
211
273
212
- Mockito . doAnswer (inv -> {
274
+ doAnswer (inv -> {
213
275
final Object [] args = inv .getArguments ();
214
276
assertThat (args .length , equalTo (3 ));
215
277
ActionListener <HasPrivilegesResponse > listener = (ActionListener <HasPrivilegesResponse >) args [args .length - 1 ];
278
+ HasPrivilegesRequest request = (HasPrivilegesRequest ) args [1 ];
279
+ Set <String > gotPriviliges = Arrays .stream (request .applicationPrivileges ())
280
+ .flatMap (appPriv -> Arrays .stream (appPriv .getPrivileges ()))
281
+ .collect (Collectors .toUnmodifiableSet ());
282
+ Set <String > expectedPrivileges = Set .of (
283
+ "role:cluster:view" ,
284
+ "role:cluster:admin" ,
285
+ "role:cluster:operator" ,
286
+ "role:cluster:monitor" ,
287
+ "role:extra1" ,
288
+ "role:extra2" ,
289
+ "role:extra3"
290
+ );
291
+ assertEquals (expectedPrivileges , gotPriviliges );
216
292
listener .onResponse (response );
217
293
return null ;
218
294
}).when (client ).execute (same (HasPrivilegesAction .INSTANCE ), any (HasPrivilegesRequest .class ), any (ActionListener .class ));
0 commit comments