Skip to content

Commit 00f3874

Browse files
committed
Add integration tests for How-to: Implement core services with Redis
Issue gh-1019
1 parent 20f1048 commit 00f3874

File tree

4 files changed

+233
-13
lines changed

4 files changed

+233
-13
lines changed

Diff for: docs/spring-authorization-server-docs.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ dependencies {
7070
runtimeOnly "com.h2database:h2"
7171
testImplementation "org.springframework.boot:spring-boot-starter-test"
7272
testImplementation "org.springframework.security:spring-security-test"
73+
testImplementation "com.github.codemonstur:embedded-redis:1.4.3"
7374
}
7475

7576
tasks.named("test") {

Diff for: docs/src/main/java/sample/redis/repository/OAuth2AuthorizationGrantAuthorizationRepository.java

+13-11
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,26 @@
2727
public interface OAuth2AuthorizationGrantAuthorizationRepository
2828
extends CrudRepository<OAuth2AuthorizationGrantAuthorization, String> {
2929

30-
<T extends OAuth2AuthorizationCodeGrantAuthorization> T findByState(String token);
30+
<T extends OAuth2AuthorizationCodeGrantAuthorization> T findByState(String state);
3131

32-
<T extends OAuth2AuthorizationCodeGrantAuthorization> T findByAuthorizationCode_TokenValue(String token);
32+
<T extends OAuth2AuthorizationCodeGrantAuthorization> T findByAuthorizationCode_TokenValue(String authorizationCode);
3333

34-
<T extends OAuth2AuthorizationGrantAuthorization> T findByAccessToken_TokenValue(String token);
34+
<T extends OAuth2AuthorizationCodeGrantAuthorization> T findByStateOrAuthorizationCode_TokenValue(String state, String authorizationCode);
3535

36-
<T extends OAuth2AuthorizationGrantAuthorization> T findByRefreshToken_TokenValue(String token);
36+
<T extends OAuth2AuthorizationGrantAuthorization> T findByAccessToken_TokenValue(String accessToken);
3737

38-
<T extends OidcAuthorizationCodeGrantAuthorization> T findByIdToken_TokenValue(String token);
38+
<T extends OAuth2AuthorizationGrantAuthorization> T findByRefreshToken_TokenValue(String refreshToken);
3939

40-
<T extends OAuth2DeviceCodeGrantAuthorization> T findByDeviceState(String token);
40+
<T extends OAuth2AuthorizationGrantAuthorization> T findByAccessToken_TokenValueOrRefreshToken_TokenValue(String accessToken, String refreshToken);
4141

42-
<T extends OAuth2DeviceCodeGrantAuthorization> T findByDeviceCode_TokenValue(String token);
42+
<T extends OidcAuthorizationCodeGrantAuthorization> T findByIdToken_TokenValue(String idToken);
4343

44-
<T extends OAuth2DeviceCodeGrantAuthorization> T findByUserCode_TokenValue(String token);
44+
<T extends OAuth2DeviceCodeGrantAuthorization> T findByDeviceState(String deviceState);
4545

46-
<T extends OAuth2AuthorizationGrantAuthorization> T findByStateOrAuthorizationCode_TokenValueOrAccessToken_TokenValueOrRefreshToken_TokenValueOrIdToken_TokenValueOrDeviceStateOrDeviceCode_TokenValueOrUserCode_TokenValue(
47-
String state, String authorizationCode, String accessToken, String refreshToken, String idToken,
48-
String deviceState, String deviceCode, String userCode);
46+
<T extends OAuth2DeviceCodeGrantAuthorization> T findByDeviceCode_TokenValue(String deviceCode);
47+
48+
<T extends OAuth2DeviceCodeGrantAuthorization> T findByUserCode_TokenValue(String userCode);
49+
50+
<T extends OAuth2DeviceCodeGrantAuthorization> T findByDeviceStateOrDeviceCode_TokenValueOrUserCode_TokenValue(String deviceState, String deviceCode, String userCode);
4951

5052
}

Diff for: docs/src/main/java/sample/redis/service/RedisOAuth2AuthorizationService.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,19 @@ public OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType)
7373
OAuth2AuthorizationGrantAuthorization authorizationGrantAuthorization = null;
7474
if (tokenType == null) {
7575
authorizationGrantAuthorization = this.authorizationGrantAuthorizationRepository
76-
.findByStateOrAuthorizationCode_TokenValueOrAccessToken_TokenValueOrRefreshToken_TokenValueOrIdToken_TokenValueOrDeviceStateOrDeviceCode_TokenValueOrUserCode_TokenValue(
77-
token, token, token, token, token, token, token, token);
76+
.findByStateOrAuthorizationCode_TokenValue(token, token);
77+
if (authorizationGrantAuthorization == null) {
78+
authorizationGrantAuthorization = this.authorizationGrantAuthorizationRepository
79+
.findByAccessToken_TokenValueOrRefreshToken_TokenValue(token, token);
80+
}
81+
if (authorizationGrantAuthorization == null) {
82+
authorizationGrantAuthorization = this.authorizationGrantAuthorizationRepository
83+
.findByIdToken_TokenValue(token);
84+
}
85+
if (authorizationGrantAuthorization == null) {
86+
authorizationGrantAuthorization = this.authorizationGrantAuthorizationRepository
87+
.findByDeviceStateOrDeviceCode_TokenValueOrUserCode_TokenValue(token, token, token);
88+
}
7889
}
7990
else if (OAuth2ParameterNames.STATE.equals(tokenType.getValue())) {
8091
authorizationGrantAuthorization = this.authorizationGrantAuthorizationRepository.findByState(token);

Diff for: docs/src/test/java/sample/redis/RedisTests.java

+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/*
2+
* Copyright 2020-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package sample.redis;
17+
18+
import java.io.IOException;
19+
import java.util.Map;
20+
21+
import jakarta.annotation.PostConstruct;
22+
import jakarta.annotation.PreDestroy;
23+
import org.assertj.core.api.ObjectAssert;
24+
import org.junit.jupiter.api.Test;
25+
import redis.embedded.RedisServer;
26+
import sample.AuthorizationCodeGrantFlow;
27+
import sample.DeviceAuthorizationGrantFlow;
28+
import sample.redis.service.RedisOAuth2AuthorizationConsentService;
29+
import sample.redis.service.RedisOAuth2AuthorizationService;
30+
import sample.redis.service.RedisRegisteredClientRepository;
31+
import sample.util.RegisteredClients;
32+
33+
import org.springframework.beans.factory.annotation.Autowired;
34+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
35+
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
36+
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
37+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
38+
import org.springframework.boot.test.context.SpringBootTest;
39+
import org.springframework.boot.test.context.TestConfiguration;
40+
import org.springframework.context.annotation.ComponentScan;
41+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
42+
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
43+
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
44+
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
45+
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
46+
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
47+
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
48+
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
49+
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
50+
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
51+
import org.springframework.test.web.servlet.MockMvc;
52+
import org.springframework.util.StringUtils;
53+
54+
import static org.assertj.core.api.Assertions.assertThat;
55+
56+
/**
57+
* Tests for the guide How-to: Implement core services with Redis.
58+
*
59+
* @author Joe Grandja
60+
*/
61+
@SpringBootTest(classes = {RedisTests.AuthorizationServerConfig.class})
62+
@AutoConfigureMockMvc
63+
public class RedisTests {
64+
private static final RegisteredClient TEST_MESSAGING_CLIENT = RegisteredClients.messagingClient();
65+
66+
@Autowired
67+
private MockMvc mockMvc;
68+
69+
@Autowired
70+
private RegisteredClientRepository registeredClientRepository;
71+
72+
@Autowired
73+
private OAuth2AuthorizationService authorizationService;
74+
75+
@Autowired
76+
private OAuth2AuthorizationConsentService authorizationConsentService;
77+
78+
@Test
79+
public void oidcLoginWhenRedisCoreServicesAutowiredThenUsed() throws Exception {
80+
assertThat(this.registeredClientRepository).isInstanceOf(RedisRegisteredClientRepository.class);
81+
assertThat(this.authorizationService).isInstanceOf(RedisOAuth2AuthorizationService.class);
82+
assertThat(this.authorizationConsentService).isInstanceOf(RedisOAuth2AuthorizationConsentService.class);
83+
84+
RegisteredClient registeredClient = TEST_MESSAGING_CLIENT;
85+
86+
AuthorizationCodeGrantFlow authorizationCodeGrantFlow = new AuthorizationCodeGrantFlow(this.mockMvc);
87+
authorizationCodeGrantFlow.setUsername("user");
88+
authorizationCodeGrantFlow.addScope("message.read");
89+
authorizationCodeGrantFlow.addScope("message.write");
90+
91+
String state = authorizationCodeGrantFlow.authorize(registeredClient);
92+
assertThatAuthorization(state, OAuth2ParameterNames.STATE).isNotNull();
93+
assertThatAuthorization(state, null).isNotNull();
94+
95+
String authorizationCode = authorizationCodeGrantFlow.submitConsent(registeredClient, state);
96+
assertThatAuthorization(authorizationCode, OAuth2ParameterNames.CODE).isNotNull();
97+
assertThatAuthorization(authorizationCode, null).isNotNull();
98+
99+
Map<String, Object> tokenResponse = authorizationCodeGrantFlow.getTokenResponse(registeredClient, authorizationCode);
100+
String accessToken = (String) tokenResponse.get(OAuth2ParameterNames.ACCESS_TOKEN);
101+
assertThatAuthorization(accessToken, OAuth2ParameterNames.ACCESS_TOKEN).isNotNull();
102+
assertThatAuthorization(accessToken, null).isNotNull();
103+
104+
String refreshToken = (String) tokenResponse.get(OAuth2ParameterNames.REFRESH_TOKEN);
105+
assertThatAuthorization(refreshToken, OAuth2ParameterNames.REFRESH_TOKEN).isNotNull();
106+
assertThatAuthorization(refreshToken, null).isNotNull();
107+
108+
String idToken = (String) tokenResponse.get(OidcParameterNames.ID_TOKEN);
109+
assertThatAuthorization(idToken, OidcParameterNames.ID_TOKEN).isNotNull();
110+
assertThatAuthorization(idToken, null).isNotNull();
111+
112+
OAuth2Authorization authorization = findAuthorization(accessToken, OAuth2ParameterNames.ACCESS_TOKEN);
113+
assertThat(authorization.getToken(idToken)).isNotNull();
114+
115+
String scopes = (String) tokenResponse.get(OAuth2ParameterNames.SCOPE);
116+
OAuth2AuthorizationConsent authorizationConsent = this.authorizationConsentService.findById(
117+
registeredClient.getId(), "user");
118+
assertThat(authorizationConsent).isNotNull();
119+
assertThat(authorizationConsent.getScopes()).containsExactlyInAnyOrder(
120+
StringUtils.delimitedListToStringArray(scopes, " "));
121+
}
122+
123+
@Test
124+
public void deviceAuthorizationWhenRedisCoreServicesAutowiredThenUsed() throws Exception {
125+
assertThat(this.registeredClientRepository).isInstanceOf(RedisRegisteredClientRepository.class);
126+
assertThat(this.authorizationService).isInstanceOf(RedisOAuth2AuthorizationService.class);
127+
assertThat(this.authorizationConsentService).isInstanceOf(RedisOAuth2AuthorizationConsentService.class);
128+
129+
RegisteredClient registeredClient = TEST_MESSAGING_CLIENT;
130+
131+
DeviceAuthorizationGrantFlow deviceAuthorizationGrantFlow = new DeviceAuthorizationGrantFlow(this.mockMvc);
132+
deviceAuthorizationGrantFlow.setUsername("user");
133+
deviceAuthorizationGrantFlow.addScope("message.read");
134+
deviceAuthorizationGrantFlow.addScope("message.write");
135+
136+
Map<String, Object> deviceAuthorizationResponse = deviceAuthorizationGrantFlow.authorize(registeredClient);
137+
String userCode = (String) deviceAuthorizationResponse.get(OAuth2ParameterNames.USER_CODE);
138+
assertThatAuthorization(userCode, OAuth2ParameterNames.USER_CODE).isNotNull();
139+
assertThatAuthorization(userCode, null).isNotNull();
140+
141+
String deviceCode = (String) deviceAuthorizationResponse.get(OAuth2ParameterNames.DEVICE_CODE);
142+
assertThatAuthorization(deviceCode, OAuth2ParameterNames.DEVICE_CODE).isNotNull();
143+
assertThatAuthorization(deviceCode, null).isNotNull();
144+
145+
String state = deviceAuthorizationGrantFlow.submitCode(userCode);
146+
assertThatAuthorization(state, OAuth2ParameterNames.STATE).isNotNull();
147+
assertThatAuthorization(state, null).isNotNull();
148+
149+
deviceAuthorizationGrantFlow.submitConsent(registeredClient, state, userCode);
150+
151+
Map<String, Object> tokenResponse = deviceAuthorizationGrantFlow.getTokenResponse(registeredClient, deviceCode);
152+
String accessToken = (String) tokenResponse.get(OAuth2ParameterNames.ACCESS_TOKEN);
153+
assertThatAuthorization(accessToken, OAuth2ParameterNames.ACCESS_TOKEN).isNotNull();
154+
assertThatAuthorization(accessToken, null).isNotNull();
155+
156+
String refreshToken = (String) tokenResponse.get(OAuth2ParameterNames.REFRESH_TOKEN);
157+
assertThatAuthorization(refreshToken, OAuth2ParameterNames.REFRESH_TOKEN).isNotNull();
158+
assertThatAuthorization(refreshToken, null).isNotNull();
159+
160+
String scopes = (String) tokenResponse.get(OAuth2ParameterNames.SCOPE);
161+
OAuth2AuthorizationConsent authorizationConsent = this.authorizationConsentService.findById(
162+
registeredClient.getId(), "user");
163+
assertThat(authorizationConsent).isNotNull();
164+
assertThat(authorizationConsent.getScopes()).containsExactlyInAnyOrder(
165+
StringUtils.delimitedListToStringArray(scopes, " "));
166+
}
167+
168+
private ObjectAssert<OAuth2Authorization> assertThatAuthorization(String token, String tokenType) {
169+
return assertThat(findAuthorization(token, tokenType));
170+
}
171+
172+
private OAuth2Authorization findAuthorization(String token, String tokenType) {
173+
return this.authorizationService.findByToken(token, tokenType == null ? null : new OAuth2TokenType(tokenType));
174+
}
175+
176+
@EnableWebSecurity
177+
@EnableAutoConfiguration(exclude = {JpaRepositoriesAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
178+
@ComponentScan
179+
static class AuthorizationServerConfig {
180+
}
181+
182+
@TestConfiguration
183+
static class RedisServerConfig {
184+
private final RedisServer redisServer;
185+
186+
@Autowired
187+
private RegisteredClientRepository registeredClientRepository;
188+
189+
RedisServerConfig() throws IOException {
190+
this.redisServer = new RedisServer();
191+
}
192+
193+
@PostConstruct
194+
void postConstruct() throws IOException {
195+
this.redisServer.start();
196+
this.registeredClientRepository.save(TEST_MESSAGING_CLIENT);
197+
}
198+
199+
@PreDestroy
200+
void preDestroy() throws IOException {
201+
this.redisServer.stop();
202+
}
203+
204+
}
205+
206+
}

0 commit comments

Comments
 (0)