Skip to content

Commit 69e4a5d

Browse files
authored
implement aad authn and authz (Azure#17325)
* Make aad authentication and authorization work together with spring-security-oauth2-client.
1 parent 37137eb commit 69e4a5d

17 files changed

+1116
-184
lines changed

sdk/spring/azure-spring-boot-test-aad/pom.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@
3030
<artifactId>spring-boot-starter-test</artifactId>
3131
<scope>test</scope>
3232
</dependency>
33+
34+
<dependency>
35+
<groupId>org.springframework.boot</groupId>
36+
<artifactId>spring-boot-starter-web</artifactId>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.springframework.boot</groupId>
40+
<artifactId>spring-boot-starter-oauth2-client</artifactId>
41+
</dependency>
3342
</dependencies>
3443

3544
<properties>
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
package com.azure.test.aad.auth;
2+
3+
import com.azure.spring.aad.implementation.AzureClientRegistrationRepository;
4+
import com.azure.spring.aad.implementation.DefaultClient;
5+
import com.azure.spring.aad.implementation.IdentityEndpoints;
6+
import com.azure.test.utils.AppRunner;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
9+
import org.springframework.context.annotation.Configuration;
10+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
11+
import org.springframework.security.oauth2.client.registration.ClientRegistration;
12+
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
13+
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
17+
import static org.junit.jupiter.api.Assertions.assertEquals;
18+
import static org.junit.jupiter.api.Assertions.assertFalse;
19+
import static org.junit.jupiter.api.Assertions.assertNotNull;
20+
import static org.junit.jupiter.api.Assertions.assertTrue;
21+
22+
public class AppAutoConfigTest {
23+
24+
@Test
25+
public void clientRegistered() {
26+
try (AppRunner appRunner = createApp()) {
27+
appRunner.start();
28+
29+
ClientRegistrationRepository clientRegistrationRepository =
30+
appRunner.getBean(ClientRegistrationRepository.class);
31+
ClientRegistration azureClientRegistration = clientRegistrationRepository.findByRegistrationId("azure");
32+
33+
assertNotNull(azureClientRegistration);
34+
assertEquals("fake-client-id", azureClientRegistration.getClientId());
35+
assertEquals("fake-client-secret", azureClientRegistration.getClientSecret());
36+
37+
IdentityEndpoints identityEndpoints = new IdentityEndpoints();
38+
assertEquals(
39+
identityEndpoints.authorizationEndpoint("fake-tenant-id"),
40+
azureClientRegistration.getProviderDetails().getAuthorizationUri()
41+
);
42+
assertEquals(
43+
identityEndpoints.tokenEndpoint("fake-tenant-id"),
44+
azureClientRegistration.getProviderDetails().getTokenUri()
45+
);
46+
assertEquals(
47+
identityEndpoints.jwkSetEndpoint("fake-tenant-id"),
48+
azureClientRegistration.getProviderDetails().getJwkSetUri()
49+
);
50+
assertEquals(
51+
"{baseUrl}/login/oauth2/code/{registrationId}",
52+
azureClientRegistration.getRedirectUriTemplate()
53+
);
54+
assertDefaultScopes(azureClientRegistration, "openid", "profile");
55+
}
56+
}
57+
58+
@Test
59+
public void clientRequiresPermissionRegistered() {
60+
try (AppRunner appRunner = createApp()) {
61+
appRunner.property("azure.activedirectory.authorization.graph.scope", "Calendars.Read");
62+
appRunner.start();
63+
64+
ClientRegistrationRepository clientRegistrationRepository =
65+
appRunner.getBean(ClientRegistrationRepository.class);
66+
ClientRegistration azureClientRegistration = clientRegistrationRepository.findByRegistrationId("azure");
67+
ClientRegistration graphClientRegistration = clientRegistrationRepository.findByRegistrationId("graph");
68+
69+
assertNotNull(azureClientRegistration);
70+
assertDefaultScopes(azureClientRegistration, "openid", "profile", "offline_access", "Calendars.Read");
71+
72+
assertNotNull(graphClientRegistration);
73+
assertDefaultScopes(graphClientRegistration, "Calendars.Read");
74+
}
75+
}
76+
77+
@Test
78+
public void clientRequiresMultiPermissions() {
79+
try (AppRunner appRunner = createApp()) {
80+
appRunner.property("azure.activedirectory.authorization.graph.scope", "Calendars.Read");
81+
appRunner.property(
82+
"azure.activedirectory.authorization.arm.scope",
83+
"https://management.core.windows.net/user_impersonation"
84+
);
85+
appRunner.start();
86+
87+
ClientRegistrationRepository clientRegistrationRepository =
88+
appRunner.getBean(ClientRegistrationRepository.class);
89+
ClientRegistration azureClientRegistration = clientRegistrationRepository.findByRegistrationId("azure");
90+
ClientRegistration graphClientRegistration = clientRegistrationRepository.findByRegistrationId("graph");
91+
92+
assertNotNull(azureClientRegistration);
93+
assertDefaultScopes(
94+
azureClientRegistration,
95+
"openid",
96+
"profile",
97+
"offline_access",
98+
"Calendars.Read",
99+
"https://management.core.windows.net/user_impersonation"
100+
);
101+
102+
assertNotNull(graphClientRegistration);
103+
assertDefaultScopes(graphClientRegistration, "Calendars.Read");
104+
}
105+
}
106+
107+
@Test
108+
public void clientRequiresPermissionInDefaultClient() {
109+
try (AppRunner appRunner = createApp()) {
110+
appRunner.property("azure.activedirectory.authorization.azure.scope", "Calendars.Read");
111+
appRunner.start();
112+
113+
ClientRegistrationRepository clientRegistrationRepository =
114+
appRunner.getBean(ClientRegistrationRepository.class);
115+
ClientRegistration azureClientRegistration = clientRegistrationRepository.findByRegistrationId("azure");
116+
117+
assertNotNull(azureClientRegistration);
118+
assertDefaultScopes(
119+
azureClientRegistration,
120+
"openid", "profile", "offline_access", "Calendars.Read"
121+
);
122+
}
123+
}
124+
125+
@Test
126+
public void aadAwareClientRepository() {
127+
try (AppRunner appRunner = createApp()) {
128+
appRunner.property("azure.activedirectory.authorization.graph.scope", "Calendars.Read");
129+
appRunner.start();
130+
131+
AzureClientRegistrationRepository azureClientRegistrationRepository =
132+
(AzureClientRegistrationRepository) appRunner.getBean(ClientRegistrationRepository.class);
133+
ClientRegistration azureClientRegistration =
134+
azureClientRegistrationRepository.findByRegistrationId("azure");
135+
ClientRegistration graphClientRegistration =
136+
azureClientRegistrationRepository.findByRegistrationId("graph");
137+
138+
assertDefaultScopes(
139+
azureClientRegistrationRepository.defaultClient(),
140+
"openid", "profile", "offline_access"
141+
);
142+
assertEquals(azureClientRegistrationRepository.defaultClient().getClientRegistration(), azureClientRegistration);
143+
144+
assertFalse(azureClientRegistrationRepository.isAuthorizedClient(azureClientRegistration));
145+
assertTrue(azureClientRegistrationRepository.isAuthorizedClient(graphClientRegistration));
146+
assertFalse(azureClientRegistrationRepository.isAuthorizedClient("azure"));
147+
assertTrue(azureClientRegistrationRepository.isAuthorizedClient("graph"));
148+
149+
List<ClientRegistration> clientRegistrations = collectClients(azureClientRegistrationRepository);
150+
assertEquals(1, clientRegistrations.size());
151+
assertEquals("azure", clientRegistrations.get(0).getRegistrationId());
152+
}
153+
}
154+
155+
@Test
156+
public void defaultClientWithAuthzScope() {
157+
try (AppRunner appRunner = createApp()) {
158+
appRunner.property("azure.activedirectory.authorization.azure.scope", "Calendars.Read");
159+
appRunner.start();
160+
161+
AzureClientRegistrationRepository azureClientRegistrationRepository =
162+
appRunner.getBean(AzureClientRegistrationRepository.class);
163+
assertDefaultScopes(
164+
azureClientRegistrationRepository.defaultClient(),
165+
"openid", "profile", "offline_access", "Calendars.Read"
166+
);
167+
}
168+
}
169+
170+
@Test
171+
public void customizeUri() {
172+
try (AppRunner appRunner = createApp()) {
173+
appRunner.property("azure.activedirectory.uri", "http://localhost/");
174+
appRunner.start();
175+
176+
AzureClientRegistrationRepository azureClientRegistrationRepository =
177+
appRunner.getBean(AzureClientRegistrationRepository.class);
178+
ClientRegistration azureClientRegistration =
179+
azureClientRegistrationRepository.findByRegistrationId("azure");
180+
181+
IdentityEndpoints endpoints = new IdentityEndpoints("http://localhost/");
182+
assertEquals(
183+
endpoints.authorizationEndpoint("fake-tenant-id"),
184+
azureClientRegistration.getProviderDetails().getAuthorizationUri()
185+
);
186+
assertEquals(
187+
endpoints.tokenEndpoint("fake-tenant-id"),
188+
azureClientRegistration.getProviderDetails().getTokenUri()
189+
);
190+
assertEquals(
191+
endpoints.jwkSetEndpoint("fake-tenant-id"),
192+
azureClientRegistration.getProviderDetails().getJwkSetUri()
193+
);
194+
}
195+
}
196+
197+
private AppRunner createApp() {
198+
AppRunner result = new AppRunner(DumbApp.class);
199+
result.property("azure.activedirectory.tenant-id", "fake-tenant-id");
200+
result.property("azure.activedirectory.client-id", "fake-client-id");
201+
result.property("azure.activedirectory.client-secret", "fake-client-secret");
202+
result.property("azure.activedirectory.user-group.allowed-groups", "group1");
203+
return result;
204+
}
205+
206+
private void assertDefaultScopes(ClientRegistration client, String ... scopes) {
207+
assertEquals(scopes.length, client.getScopes().size());
208+
for (String s : scopes) {
209+
assertTrue(client.getScopes().contains(s));
210+
}
211+
}
212+
213+
private void assertDefaultScopes(DefaultClient client, String ... expected) {
214+
assertEquals(expected.length, client.getScopeList().size());
215+
for (String e : expected) {
216+
assertTrue(client.getScopeList().contains(e));
217+
}
218+
}
219+
220+
private List<ClientRegistration> collectClients(Iterable<ClientRegistration> iterable) {
221+
List<ClientRegistration> result = new ArrayList<>();
222+
iterable.forEach(result::add);
223+
return result;
224+
}
225+
226+
@Configuration
227+
@EnableAutoConfiguration
228+
@EnableWebSecurity
229+
public static class DumbApp {}
230+
}

0 commit comments

Comments
 (0)