Skip to content

Commit a0bba42

Browse files
implement unit tests
1 parent 85d123a commit a0bba42

File tree

5 files changed

+453
-37
lines changed

5 files changed

+453
-37
lines changed

plugins/microsoft-graph-authz/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ dependencies {
7777
testRuntimeOnly "net.minidev:json-smart:2.5.2"
7878
testRuntimeOnly "com.nimbusds:oauth2-oidc-sdk:11.22.2"
7979
testRuntimeOnly "com.nimbusds:content-type:2.3"
80+
testImplementation testArtifact(project(":x-pack:plugin:core"))
8081

8182
attributesSchema {
8283
attribute(patched)

plugins/microsoft-graph-authz/licenses/microsoft-graph-NOTICE.txt

Whitespace-only changes.

plugins/microsoft-graph-authz/src/main/java/org/elasticsearch/xpack/security/authz/microsoft/MicrosoftGraphAuthzRealm.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.elasticsearch.license.License;
2828
import org.elasticsearch.license.LicenseUtils;
2929
import org.elasticsearch.license.LicensedFeature;
30+
import org.elasticsearch.license.XPackLicenseState;
3031
import org.elasticsearch.logging.LogManager;
3132
import org.elasticsearch.logging.Logger;
3233
import org.elasticsearch.xpack.core.XPackPlugin;
@@ -51,7 +52,7 @@ public class MicrosoftGraphAuthzRealm extends Realm {
5152
"false"
5253
).equals("true");
5354

54-
private static final LicensedFeature.Momentary MICROSOFT_GRAPH_FEATURE = LicensedFeature.momentary(
55+
static final LicensedFeature.Momentary MICROSOFT_GRAPH_FEATURE = LicensedFeature.momentary(
5556
"security-realms",
5657
"microsoft_graph",
5758
License.OperationMode.PLATINUM
@@ -60,6 +61,7 @@ public class MicrosoftGraphAuthzRealm extends Realm {
6061
private final RealmConfig config;
6162
private final UserRoleMapper roleMapper;
6263
private final GraphServiceClient client;
64+
private final XPackLicenseState licenseState;
6365

6466
public MicrosoftGraphAuthzRealm(UserRoleMapper roleMapper, RealmConfig config) {
6567
super(config);
@@ -79,7 +81,17 @@ public MicrosoftGraphAuthzRealm(UserRoleMapper roleMapper, RealmConfig config) {
7981
);
8082
}
8183

82-
client = buildClient(clientSecret);
84+
this.client = buildClient(clientSecret);
85+
this.licenseState = XPackPlugin.getSharedLicenseState();
86+
}
87+
88+
// for testing
89+
MicrosoftGraphAuthzRealm(UserRoleMapper roleMapper, RealmConfig config, GraphServiceClient client, XPackLicenseState licenseState) {
90+
super(config);
91+
this.config = config;
92+
this.roleMapper = roleMapper;
93+
this.client = client;
94+
this.licenseState = licenseState;
8395
}
8496

8597
private void require(Setting.AffixSetting<String> setting) {
@@ -106,7 +118,7 @@ public void authenticate(AuthenticationToken token, ActionListener<Authenticatio
106118

107119
@Override
108120
public void lookupUser(String principal, ActionListener<User> listener) {
109-
if (MICROSOFT_GRAPH_FEATURE.check(XPackPlugin.getSharedLicenseState()) == false) {
121+
if (MICROSOFT_GRAPH_FEATURE.check(licenseState) == false) {
110122
listener.onFailure(LicenseUtils.newComplianceException(MICROSOFT_GRAPH_FEATURE.getName()));
111123
return;
112124
}

plugins/microsoft-graph-authz/src/test/java/org/elasticsearch/xpack/security/authz/microsoft/MicrosoftGraphAuthzRealmTests.java

Lines changed: 235 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,82 +9,283 @@
99

1010
package org.elasticsearch.xpack.security.authz.microsoft;
1111

12+
import com.microsoft.graph.models.Group;
13+
import com.microsoft.graph.models.GroupCollectionResponse;
14+
import com.microsoft.graph.models.odataerrors.MainError;
15+
import com.microsoft.graph.models.odataerrors.ODataError;
16+
import com.microsoft.graph.serviceclient.GraphServiceClient;
17+
import com.microsoft.graph.users.UsersRequestBuilder;
18+
import com.microsoft.graph.users.item.UserItemRequestBuilder;
19+
import com.microsoft.graph.users.item.memberof.MemberOfRequestBuilder;
20+
import com.microsoft.graph.users.item.memberof.graphgroup.GraphGroupRequestBuilder;
21+
import com.microsoft.kiota.RequestAdapter;
22+
23+
import org.elasticsearch.ElasticsearchSecurityException;
24+
import org.elasticsearch.action.ActionListener;
1225
import org.elasticsearch.action.support.PlainActionFuture;
13-
import org.elasticsearch.common.settings.MockSecureSettings;
26+
import org.elasticsearch.common.Strings;
1427
import org.elasticsearch.common.settings.Settings;
1528
import org.elasticsearch.common.util.concurrent.ThreadContext;
1629
import org.elasticsearch.env.Environment;
1730
import org.elasticsearch.env.TestEnvironment;
31+
import org.elasticsearch.license.MockLicenseState;
1832
import org.elasticsearch.test.ESTestCase;
1933
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
2034
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
2135
import org.elasticsearch.xpack.core.security.authc.support.UserRoleMapper;
2236
import org.elasticsearch.xpack.core.security.user.User;
23-
import org.junit.Before;
37+
38+
import java.util.List;
39+
import java.util.Set;
2440

2541
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
42+
import static org.elasticsearch.xpack.security.authz.microsoft.MicrosoftGraphAuthzRealm.MICROSOFT_GRAPH_FEATURE;
2643
import static org.hamcrest.Matchers.arrayContaining;
2744
import static org.hamcrest.Matchers.equalTo;
45+
import static org.mockito.ArgumentMatchers.any;
46+
import static org.mockito.ArgumentMatchers.eq;
47+
import static org.mockito.Mockito.doAnswer;
2848
import static org.mockito.Mockito.mock;
49+
import static org.mockito.Mockito.when;
2950

3051
public class MicrosoftGraphAuthzRealmTests extends ESTestCase {
3152

32-
private Settings globalSettings;
33-
private Environment env;
34-
private ThreadContext threadContext;
53+
private final Settings globalSettings = Settings.builder().put("path.home", createTempDir()).build();
54+
private final Environment env = TestEnvironment.newEnvironment(globalSettings);
55+
private final ThreadContext threadContext = new ThreadContext(globalSettings);
3556

36-
@Before
37-
public void setup() {
38-
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
39-
env = TestEnvironment.newEnvironment(globalSettings);
40-
threadContext = new ThreadContext(globalSettings);
41-
}
57+
private final String realmName = randomAlphaOfLengthBetween(4, 10);
58+
private final String roleName = randomAlphaOfLengthBetween(4, 10);
59+
private final String username = randomAlphaOfLengthBetween(4, 10);
60+
private final String name = randomAlphaOfLengthBetween(4, 10);
61+
private final String email = Strings.format("[%s]@example.com", randomAlphaOfLengthBetween(4, 10));
62+
private final String groupId = randomAlphaOfLengthBetween(4, 10);
63+
private final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier(
64+
MicrosoftGraphAuthzRealmSettings.REALM_TYPE,
65+
realmName
66+
);
4267

4368
public void testLookupUser() {
44-
final var realmName = "ms-graph";
45-
final var realmId = new RealmConfig.RealmIdentifier(MicrosoftGraphAuthzRealmSettings.REALM_TYPE, realmName);
69+
final var roleMapper = mockRoleMapper(Set.of(groupId), Set.of(roleName));
4670

47-
final var roleMapper = mock(UserRoleMapper.class);
48-
final var secureSettings = new MockSecureSettings();
49-
secureSettings.setString(getFullSettingKey(realmName, MicrosoftGraphAuthzRealmSettings.CLIENT_SECRET), "client-secret");
5071
final var realmSettings = Settings.builder()
5172
.put(globalSettings)
5273
.put(getFullSettingKey(realmId, RealmSettings.ORDER_SETTING), 0)
53-
.put(getFullSettingKey(realmName, MicrosoftGraphAuthzRealmSettings.CLIENT_ID), "client-id")
54-
.put(getFullSettingKey(realmName, MicrosoftGraphAuthzRealmSettings.TENANT_ID), "tenant-id")
55-
.put(getFullSettingKey(realmName, MicrosoftGraphAuthzRealmSettings.ACCESS_TOKEN_HOST), "https://localhost:12345")
56-
.put(getFullSettingKey(realmName, MicrosoftGraphAuthzRealmSettings.API_HOST), "https://localhost:12345/v1.0")
57-
.setSecureSettings(secureSettings)
5874
.build();
5975

6076
final var config = new RealmConfig(realmId, realmSettings, env, threadContext);
77+
final var client = mock(GraphServiceClient.class);
78+
final var requestAdapter = mock(RequestAdapter.class);
79+
when(client.getRequestAdapter()).thenReturn(requestAdapter);
80+
81+
final var userRequestBuilder = mock(UsersRequestBuilder.class);
82+
final var userItemRequestBuilder = mock(UserItemRequestBuilder.class);
83+
final var msUser = new com.microsoft.graph.models.User();
84+
msUser.setDisplayName(name);
85+
msUser.setMail(email);
86+
87+
when(client.users()).thenReturn(userRequestBuilder);
88+
when(userRequestBuilder.byUserId(eq(username))).thenReturn(userItemRequestBuilder);
89+
when(userItemRequestBuilder.get(any())).thenReturn(msUser);
90+
91+
final var memberOfRequestBuilder = mock(MemberOfRequestBuilder.class);
92+
final var graphGroupRequestBuilder = mock(GraphGroupRequestBuilder.class);
93+
final var group = new Group();
94+
group.setId(groupId);
95+
final var groupMembership = new GroupCollectionResponse();
96+
groupMembership.setValue(List.of(group));
97+
98+
when(userItemRequestBuilder.memberOf()).thenReturn(memberOfRequestBuilder);
99+
when(memberOfRequestBuilder.graphGroup()).thenReturn(graphGroupRequestBuilder);
100+
when(graphGroupRequestBuilder.get(any())).thenReturn(groupMembership);
101+
102+
final var licenseState = MockLicenseState.createMock();
103+
when(licenseState.isAllowed(eq(MICROSOFT_GRAPH_FEATURE))).thenReturn(true);
61104

62-
final var realm = new MicrosoftGraphAuthzRealm(roleMapper, config);
105+
final var realm = new MicrosoftGraphAuthzRealm(roleMapper, config, client, licenseState);
63106
final var future = new PlainActionFuture<User>();
64-
realm.lookupUser("principal", future);
107+
realm.lookupUser(username, future);
65108
final var user = future.actionGet();
66-
assertThat(user.principal(), equalTo("principal"));
67-
assertThat(user.email(), equalTo("email"));
68-
assertThat(user.roles(), arrayContaining("role1"));
69-
}
70-
71-
public void testHandleGetAccessTokenError() {
72-
fail();
109+
assertThat(user.principal(), equalTo(username));
110+
assertThat(user.fullName(), equalTo(name));
111+
assertThat(user.email(), equalTo(email));
112+
assertThat(user.roles(), arrayContaining(roleName));
73113
}
74114

75115
public void testHandleGetUserPropertiesError() {
76-
fail();
116+
final var roleMapper = mockRoleMapper(Set.of(groupId), Set.of(roleName));
117+
118+
final var realmSettings = Settings.builder()
119+
.put(globalSettings)
120+
.put(getFullSettingKey(realmId, RealmSettings.ORDER_SETTING), 0)
121+
.build();
122+
123+
final var config = new RealmConfig(realmId, realmSettings, env, threadContext);
124+
final var client = mock(GraphServiceClient.class);
125+
final var requestAdapter = mock(RequestAdapter.class);
126+
when(client.getRequestAdapter()).thenReturn(requestAdapter);
127+
128+
final var userRequestBuilder = mock(UsersRequestBuilder.class);
129+
final var userItemRequestBuilder = mock(UserItemRequestBuilder.class);
130+
final var graphError = new ODataError();
131+
final var error = new MainError();
132+
error.setCode("badRequest");
133+
error.setMessage("bad stuff happened");
134+
graphError.setError(error);
135+
136+
when(client.users()).thenReturn(userRequestBuilder);
137+
when(userRequestBuilder.byUserId(eq(username))).thenReturn(userItemRequestBuilder);
138+
when(userItemRequestBuilder.get(any())).thenThrow(graphError);
139+
140+
final var licenseState = MockLicenseState.createMock();
141+
when(licenseState.isAllowed(eq(MICROSOFT_GRAPH_FEATURE))).thenReturn(true);
142+
143+
final var realm = new MicrosoftGraphAuthzRealm(roleMapper, config, client, licenseState);
144+
final var future = new PlainActionFuture<User>();
145+
realm.lookupUser(username, future);
146+
final var thrown = assertThrows(ODataError.class, future::actionGet);
147+
assertThat(thrown.getMessage(), equalTo("bad stuff happened"));
77148
}
78149

79150
public void testHandleGetGroupMembershipError() {
80-
fail();
151+
final var roleMapper = mockRoleMapper(Set.of(groupId), Set.of(roleName));
152+
153+
final var realmSettings = Settings.builder()
154+
.put(globalSettings)
155+
.put(getFullSettingKey(realmId, RealmSettings.ORDER_SETTING), 0)
156+
.build();
157+
158+
final var config = new RealmConfig(realmId, realmSettings, env, threadContext);
159+
final var client = mock(GraphServiceClient.class);
160+
final var requestAdapter = mock(RequestAdapter.class);
161+
when(client.getRequestAdapter()).thenReturn(requestAdapter);
162+
163+
final var userRequestBuilder = mock(UsersRequestBuilder.class);
164+
final var userItemRequestBuilder = mock(UserItemRequestBuilder.class);
165+
final var msUser = new com.microsoft.graph.models.User();
166+
msUser.setDisplayName(name);
167+
msUser.setMail(email);
168+
169+
when(client.users()).thenReturn(userRequestBuilder);
170+
when(userRequestBuilder.byUserId(eq(username))).thenReturn(userItemRequestBuilder);
171+
when(userItemRequestBuilder.get(any())).thenReturn(msUser);
172+
173+
final var memberOfRequestBuilder = mock(MemberOfRequestBuilder.class);
174+
final var graphGroupRequestBuilder = mock(GraphGroupRequestBuilder.class);
175+
final var graphError = new ODataError();
176+
final var error = new MainError();
177+
error.setCode("badRequest");
178+
error.setMessage("bad stuff happened");
179+
graphError.setError(error);
180+
181+
when(userItemRequestBuilder.memberOf()).thenReturn(memberOfRequestBuilder);
182+
when(memberOfRequestBuilder.graphGroup()).thenReturn(graphGroupRequestBuilder);
183+
when(graphGroupRequestBuilder.get(any())).thenThrow(graphError);
184+
185+
final var licenseState = MockLicenseState.createMock();
186+
when(licenseState.isAllowed(eq(MICROSOFT_GRAPH_FEATURE))).thenReturn(true);
187+
188+
final var realm = new MicrosoftGraphAuthzRealm(roleMapper, config, client, licenseState);
189+
final var future = new PlainActionFuture<User>();
190+
realm.lookupUser(username, future);
191+
final var thrown = assertThrows(ODataError.class, future::actionGet);
192+
assertThat(thrown.getMessage(), equalTo("bad stuff happened"));
81193
}
82194

83195
public void testGroupMembershipPagination() {
84-
fail();
196+
final var groupId2 = randomAlphaOfLengthBetween(4, 10);
197+
final var groupId3 = randomAlphaOfLengthBetween(4, 10);
198+
199+
final var roleMapper = mockRoleMapper(Set.of(groupId, groupId2, groupId3), Set.of(roleName));
200+
201+
final var realmSettings = Settings.builder()
202+
.put(globalSettings)
203+
.put(getFullSettingKey(realmId, RealmSettings.ORDER_SETTING), 0)
204+
.build();
205+
206+
final var config = new RealmConfig(realmId, realmSettings, env, threadContext);
207+
final var client = mock(GraphServiceClient.class);
208+
final var requestAdapter = mock(RequestAdapter.class);
209+
when(client.getRequestAdapter()).thenReturn(requestAdapter);
210+
211+
final var userRequestBuilder = mock(UsersRequestBuilder.class);
212+
final var userItemRequestBuilder = mock(UserItemRequestBuilder.class);
213+
final var msUser = new com.microsoft.graph.models.User();
214+
msUser.setDisplayName(name);
215+
msUser.setMail(email);
216+
217+
when(client.users()).thenReturn(userRequestBuilder);
218+
when(userRequestBuilder.byUserId(eq(username))).thenReturn(userItemRequestBuilder);
219+
when(userItemRequestBuilder.get(any())).thenReturn(msUser);
220+
221+
final var memberOfRequestBuilder = mock(MemberOfRequestBuilder.class);
222+
final var graphGroupRequestBuilder = mock(GraphGroupRequestBuilder.class);
223+
final var group1 = new Group();
224+
group1.setId(groupId);
225+
final var groupMembership1 = new GroupCollectionResponse();
226+
groupMembership1.setValue(List.of(group1));
227+
groupMembership1.setOdataNextLink("http://localhost:12345/page2");
228+
229+
final var group2 = new Group();
230+
group2.setId(groupId2);
231+
final var groupMembership2 = new GroupCollectionResponse();
232+
groupMembership2.setValue(List.of(group2));
233+
groupMembership2.setOdataNextLink("http://localhost:12345/page3");
234+
235+
final var group3 = new Group();
236+
group3.setId(groupId3);
237+
final var groupMembership3 = new GroupCollectionResponse();
238+
groupMembership3.setValue(List.of(group3));
239+
240+
when(userItemRequestBuilder.memberOf()).thenReturn(memberOfRequestBuilder);
241+
when(memberOfRequestBuilder.graphGroup()).thenReturn(graphGroupRequestBuilder);
242+
when(graphGroupRequestBuilder.get(any())).thenReturn(groupMembership1);
243+
when(requestAdapter.send(any(), any(), any())).thenReturn(groupMembership2, groupMembership3);
244+
245+
final var licenseState = MockLicenseState.createMock();
246+
when(licenseState.isAllowed(eq(MICROSOFT_GRAPH_FEATURE))).thenReturn(true);
247+
248+
final var realm = new MicrosoftGraphAuthzRealm(roleMapper, config, client, licenseState);
249+
final var future = new PlainActionFuture<User>();
250+
realm.lookupUser(username, future);
251+
final var user = future.actionGet();
252+
assertThat(user.principal(), equalTo(username));
253+
assertThat(user.fullName(), equalTo(name));
254+
assertThat(user.email(), equalTo(email));
255+
assertThat(user.roles(), arrayContaining(roleName));
85256
}
86257

87258
public void testLicenseCheck() {
88-
fail();
259+
final var roleMapper = mock(UserRoleMapper.class);
260+
final var realmSettings = Settings.builder()
261+
.put(globalSettings)
262+
.put(getFullSettingKey(realmId, RealmSettings.ORDER_SETTING), 0)
263+
.build();
264+
265+
final var config = new RealmConfig(realmId, realmSettings, env, threadContext);
266+
final var client = mock(GraphServiceClient.class);
267+
268+
final var licenseState = MockLicenseState.createMock();
269+
when(licenseState.isAllowed(eq(MICROSOFT_GRAPH_FEATURE))).thenReturn(false);
270+
271+
final var realm = new MicrosoftGraphAuthzRealm(roleMapper, config, client, licenseState);
272+
final var future = new PlainActionFuture<User>();
273+
realm.lookupUser(username, future);
274+
final var thrown = assertThrows(ElasticsearchSecurityException.class, future::actionGet);
275+
assertThat(thrown.getMessage(), equalTo("current license is non-compliant for [microsoft_graph]"));
276+
}
277+
278+
private UserRoleMapper mockRoleMapper(Set<String> expectedGroups, Set<String> rolesToReturn) {
279+
final var roleMapper = mock(UserRoleMapper.class);
280+
doAnswer(invocation -> {
281+
var userData = (UserRoleMapper.UserData) invocation.getArguments()[0];
282+
assertEquals(userData.getGroups(), expectedGroups);
283+
@SuppressWarnings("unchecked")
284+
var listener = (ActionListener<Set<String>>) invocation.getArguments()[1];
285+
listener.onResponse(rolesToReturn);
286+
return null;
287+
}).when(roleMapper).resolveRoles(any(), any());
288+
289+
return roleMapper;
89290
}
90291
}

0 commit comments

Comments
 (0)