Skip to content

Commit 9b748c4

Browse files
Add builder to OAuth2Authorization
Fixes spring-projectsgh-43
1 parent 02ec85a commit 9b748c4

File tree

3 files changed

+258
-54
lines changed

3 files changed

+258
-54
lines changed

core/src/main/java/org/springframework/security/oauth2/server/authorization/OAuth2Authorization.java

Lines changed: 117 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
*/
1616
package org.springframework.security.oauth2.server.authorization;
1717

18-
import org.springframework.lang.Nullable;
1918
import org.springframework.security.oauth2.core.OAuth2AccessToken;
2019
import org.springframework.util.Assert;
20+
import org.springframework.util.CollectionUtils;
2121

2222
import java.util.Collections;
2323
import java.util.Map;
@@ -30,48 +30,12 @@
3030
* @author Krisztian Toth
3131
*/
3232
public class OAuth2Authorization {
33-
private final String registeredClientId;
34-
private final String principalName;
35-
private final OAuth2AccessToken accessToken;
36-
private final Map<String, Object> attributes;
33+
private String registeredClientId;
34+
private String principalName;
35+
private OAuth2AccessToken accessToken;
36+
private Map<String, Object> attributes;
3737

38-
/**
39-
* Creates a {@link OAuth2Authorization} object with the provided params and an empty, unmodifiable
40-
* {@code attributes} map.
41-
*
42-
* @see #OAuth2Authorization(String, String, OAuth2AccessToken, Map)
43-
*/
44-
public OAuth2Authorization(String registeredClientId, String principalName, OAuth2AccessToken accessToken) {
45-
this(registeredClientId, principalName, accessToken, Collections.emptyMap());
46-
}
47-
48-
/**
49-
* Creates a {@link OAuth2Authorization} object without an {@link OAuth2AccessToken}.
50-
*
51-
* @see #OAuth2Authorization(String, String, OAuth2AccessToken, Map)
52-
*/
53-
public OAuth2Authorization(String registeredClientId, String principalName, Map<String, Object> attributes) {
54-
this(registeredClientId, principalName, null, attributes);
55-
}
56-
57-
/**
58-
* Creates an {@link OAuth2Authorization} object with the provided params.
59-
*
60-
* @param registeredClientId the client's identifier which issued the authorization
61-
* @param principalName the name of the principal the client wants to authorize
62-
* @param accessToken the access token of the authorization
63-
* @param attributes additional attributes associated with the authorization
64-
*/
65-
public OAuth2Authorization(String registeredClientId, String principalName,
66-
@Nullable OAuth2AccessToken accessToken, @Nullable Map<String, Object> attributes) {
67-
Assert.hasText(registeredClientId, "registeredClientId cannot be empty");
68-
Assert.hasText(principalName, "principalName cannot be empty");
69-
this.registeredClientId = registeredClientId;
70-
this.principalName = principalName;
71-
this.accessToken = accessToken;
72-
this.attributes = attributes == null ?
73-
Collections.emptyMap() :
74-
Collections.unmodifiableMap(attributes);
38+
private OAuth2Authorization() {
7539
}
7640

7741
public String getRegisteredClientId() {
@@ -119,4 +83,115 @@ public String toString() {
11983
", attributes=" + attributes +
12084
'}';
12185
}
86+
87+
/**
88+
* Returns an empty {@link Builder}.
89+
*
90+
* @return the {@link Builder}
91+
*/
92+
public static Builder builder() {
93+
return new Builder();
94+
}
95+
96+
/**
97+
* Returns a new {@link Builder}, initialized with the provided {@link OAuth2Authorization}.
98+
*
99+
* @param authorization the {@link OAuth2Authorization} to copy from
100+
* @return the {@link Builder}
101+
*/
102+
public static Builder withOAuth2Authorization(OAuth2Authorization authorization) {
103+
Assert.notNull(authorization, "authorization cannot be null");
104+
return new Builder(authorization);
105+
}
106+
107+
/**
108+
* Builder class for {@link OAuth2Authorization}.
109+
*/
110+
public static final class Builder {
111+
private String registeredClientId;
112+
private String principalName;
113+
private OAuth2AccessToken accessToken;
114+
private Map<String, Object> attributes;
115+
116+
protected Builder() {
117+
}
118+
119+
protected Builder(OAuth2Authorization authorization) {
120+
this.registeredClientId = authorization.registeredClientId;
121+
this.principalName = authorization.principalName;
122+
this.accessToken = authorization.accessToken;
123+
this.attributes = authorization.attributes;
124+
}
125+
126+
/**
127+
* Sets the registered client identifier.
128+
*
129+
* @param registeredClientId the client id
130+
* @return the {@link Builder}
131+
*/
132+
public Builder registeredClientId(String registeredClientId) {
133+
this.registeredClientId = registeredClientId;
134+
return this;
135+
}
136+
137+
/**
138+
* Sets the principal name.
139+
*
140+
* @param principalName the principal name
141+
* @return the {@link Builder}
142+
*/
143+
public Builder principalName(String principalName) {
144+
this.principalName = principalName;
145+
return this;
146+
}
147+
148+
/**
149+
* Sets the {@link OAuth2AccessToken}.
150+
*
151+
* @param accessToken the {@link OAuth2AccessToken}
152+
* @return the {@link Builder}
153+
*/
154+
public Builder accessToken(OAuth2AccessToken accessToken) {
155+
this.accessToken = accessToken;
156+
return this;
157+
}
158+
159+
/**
160+
* Sets the attributes map.
161+
*
162+
* @param attributes the attributes map
163+
* @return the {@link Builder}
164+
*/
165+
public Builder attributes(Map<String, Object> attributes) {
166+
this.attributes = attributes;
167+
return this;
168+
}
169+
170+
/**
171+
* Builds a new {@link OAuth2Authorization}.
172+
*
173+
* @return the {@link OAuth2Authorization}
174+
*/
175+
public OAuth2Authorization build() {
176+
Assert.hasText(this.registeredClientId, "registeredClientId cannot be empty");
177+
Assert.hasText(this.principalName, "principalName cannot be empty");
178+
if (CollectionUtils.isEmpty(this.attributes)) {
179+
this.attributes = Collections.emptyMap();
180+
}
181+
if (this.accessToken == null && this.attributes.get(TokenType.AUTHORIZATION_CODE.getValue()) == null) {
182+
throw new IllegalArgumentException("either accessToken has to be set or the authorization code with key '"
183+
+ TokenType.AUTHORIZATION_CODE.getValue() + "' must be provided in the attributes map");
184+
}
185+
return create();
186+
}
187+
188+
private OAuth2Authorization create() {
189+
OAuth2Authorization oAuth2Authorization = new OAuth2Authorization();
190+
oAuth2Authorization.registeredClientId = this.registeredClientId;
191+
oAuth2Authorization.principalName = this.principalName;
192+
oAuth2Authorization.accessToken = this.accessToken;
193+
oAuth2Authorization.attributes = this.attributes;
194+
return oAuth2Authorization;
195+
}
196+
}
122197
}

core/src/test/java/org/springframework/security/oauth2/server/authorization/InMemoryOAuth2AuthorizationServiceTest.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public class InMemoryOAuth2AuthorizationServiceTest {
3636
private static final String TOKEN = "token";
3737
private static final TokenType AUTHORIZATION_CODE = TokenType.AUTHORIZATION_CODE;
3838
private static final TokenType ACCESS_TOKEN = TokenType.ACCESS_TOKEN;
39-
public static final Instant ISSUED_AT = Instant.now().minusSeconds(60);
40-
public static final Instant EXPIRES_AT = Instant.now();
39+
private static final Instant ISSUED_AT = Instant.now().minusSeconds(60);
40+
private static final Instant EXPIRES_AT = Instant.now();
4141

4242
private List<OAuth2Authorization> store;
4343
private InMemoryOAuth2AuthorizationService authorizationService;
@@ -50,8 +50,11 @@ public void setUp() throws Exception {
5050

5151
@Test
5252
public void testSave() {
53-
OAuth2Authorization authorization = new OAuth2Authorization("clientId", "principalName",
54-
Collections.singletonMap(AUTHORIZATION_CODE.getValue(), TOKEN));
53+
OAuth2Authorization authorization = OAuth2Authorization.builder()
54+
.registeredClientId("clientId")
55+
.principalName("principalName")
56+
.attributes(Collections.singletonMap(AUTHORIZATION_CODE.getValue(), TOKEN))
57+
.build();
5558
authorizationService.save(authorization);
5659

5760
assertEquals(1, store.size());
@@ -65,9 +68,11 @@ public void testSaveWithNullParam() {
6568

6669
@Test
6770
public void testFindByTokenAndTokenTypeWhenTokenTypeIsAuthorizationCode() {
68-
OAuth2Authorization authorization = new OAuth2Authorization("clientId", "principalName",
69-
Collections.singletonMap(AUTHORIZATION_CODE.getValue(), TOKEN));
70-
71+
OAuth2Authorization authorization = OAuth2Authorization.builder()
72+
.registeredClientId("clientId")
73+
.principalName("principalName")
74+
.attributes(Collections.singletonMap(AUTHORIZATION_CODE.getValue(), TOKEN))
75+
.build();
7176
store.add(authorization);
7277

7378
OAuth2Authorization result = authorizationService.findByTokenAndTokenType(TOKEN, TokenType.AUTHORIZATION_CODE);
@@ -78,8 +83,11 @@ public void testFindByTokenAndTokenTypeWhenTokenTypeIsAuthorizationCode() {
7883
public void testFindByTokenAndTokenTypeWhenTokenTypeIsAccessToken() {
7984
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, TOKEN, ISSUED_AT,
8085
EXPIRES_AT);
81-
OAuth2Authorization authorization = new OAuth2Authorization("clientId", "principalName", accessToken);
82-
86+
OAuth2Authorization authorization = OAuth2Authorization.builder()
87+
.registeredClientId("clientId")
88+
.principalName("principalName")
89+
.accessToken(accessToken)
90+
.build();
8391
store.add(authorization);
8492

8593
OAuth2Authorization result = authorizationService.findByTokenAndTokenType(TOKEN, ACCESS_TOKEN);
@@ -88,9 +96,11 @@ public void testFindByTokenAndTokenTypeWhenTokenTypeIsAccessToken() {
8896

8997
@Test
9098
public void testFindByTokenAndTokenTypeWhenTokenNotFound() {
91-
OAuth2Authorization authorization = new OAuth2Authorization("clientId", "principalName",
92-
Collections.singletonMap(AUTHORIZATION_CODE.getValue(), TOKEN));
93-
99+
OAuth2Authorization authorization = OAuth2Authorization.builder()
100+
.registeredClientId("clientId")
101+
.principalName("principalName")
102+
.attributes(Collections.singletonMap(AUTHORIZATION_CODE.getValue(), TOKEN))
103+
.build();
94104
store.add(authorization);
95105

96106
OAuth2Authorization result = authorizationService.findByTokenAndTokenType(TOKEN, ACCESS_TOKEN);
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2020 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 org.springframework.security.oauth2.server.authorization;
17+
18+
import org.junit.Test;
19+
import org.springframework.security.oauth2.core.OAuth2AccessToken;
20+
21+
import java.time.Instant;
22+
import java.util.Collections;
23+
import java.util.Map;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
27+
28+
/**
29+
* Unit tests For {@link OAuth2Authorization}.
30+
*
31+
* @author Krisztian Toth
32+
*/
33+
public class OAuth2AuthorizationTest {
34+
35+
public static final String REGISTERED_CLIENT_ID = "clientId";
36+
public static final String PRINCIPAL_NAME = "principal";
37+
public static final OAuth2AccessToken ACCESS_TOKEN = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
38+
"token", Instant.now().minusSeconds(60), Instant.now());
39+
public static final Map<String, Object> ATTRIBUTES = Collections.singletonMap(
40+
TokenType.AUTHORIZATION_CODE.getValue(), "code");
41+
42+
@Test
43+
public void buildWhenAllAttributesAreProvidedThenAllAttributesAreSet() {
44+
OAuth2Authorization authorization = OAuth2Authorization.builder()
45+
.registeredClientId(REGISTERED_CLIENT_ID)
46+
.principalName(PRINCIPAL_NAME)
47+
.accessToken(ACCESS_TOKEN)
48+
.attributes(ATTRIBUTES)
49+
.build();
50+
51+
assertThat(authorization.getRegisteredClientId()).isEqualTo(REGISTERED_CLIENT_ID);
52+
assertThat(authorization.getPrincipalName()).isEqualTo(PRINCIPAL_NAME);
53+
assertThat(authorization.getAccessToken()).isEqualTo(ACCESS_TOKEN);
54+
assertThat(authorization.getAttributes()).isEqualTo(ATTRIBUTES);
55+
}
56+
57+
@Test
58+
public void buildWhenAttributesNotProvidedThenEmptyImmutableMapCreated() {
59+
OAuth2Authorization authorization = OAuth2Authorization.builder()
60+
.registeredClientId(REGISTERED_CLIENT_ID)
61+
.principalName(PRINCIPAL_NAME)
62+
.accessToken(ACCESS_TOKEN)
63+
.build();
64+
65+
assertThat(authorization.getAttributes()).isEqualTo(Collections.emptyMap());
66+
assertThatThrownBy(() -> authorization.getAttributes().put("any", "value"))
67+
.isInstanceOf(UnsupportedOperationException.class);
68+
}
69+
70+
@Test
71+
public void buildWhenAccessTokenAndAuthorizationCodeNotProvidedThenThrowIllegalArgumentException() {
72+
assertThatThrownBy(() ->
73+
OAuth2Authorization.builder()
74+
.registeredClientId(REGISTERED_CLIENT_ID)
75+
.principalName(PRINCIPAL_NAME)
76+
.build()
77+
).isInstanceOf(IllegalArgumentException.class);
78+
}
79+
80+
@Test
81+
public void buildWhenRegisteredClientIdNotProvidedThenThrowIllegalArgumentException() {
82+
assertThatThrownBy(() ->
83+
OAuth2Authorization.builder()
84+
.principalName(PRINCIPAL_NAME)
85+
.accessToken(ACCESS_TOKEN)
86+
.attributes(ATTRIBUTES)
87+
.build()
88+
).isInstanceOf(IllegalArgumentException.class);
89+
}
90+
91+
@Test
92+
public void buildWhenPrincipalNameNotProvidedThenThrowIllegalArgumentException() {
93+
assertThatThrownBy(() ->
94+
OAuth2Authorization.builder()
95+
.registeredClientId(REGISTERED_CLIENT_ID)
96+
.accessToken(ACCESS_TOKEN)
97+
.attributes(ATTRIBUTES)
98+
.build()
99+
).isInstanceOf(IllegalArgumentException.class);
100+
}
101+
102+
@Test
103+
public void withOAuth2AuthorizationWhenAuthorizationProvidedThenAllAttributesAreCopied() {
104+
OAuth2Authorization authorizationToCopy = OAuth2Authorization.builder()
105+
.registeredClientId(REGISTERED_CLIENT_ID)
106+
.principalName(PRINCIPAL_NAME)
107+
.attributes(ATTRIBUTES)
108+
.build();
109+
110+
OAuth2Authorization authorization = OAuth2Authorization.withOAuth2Authorization(authorizationToCopy)
111+
.accessToken(ACCESS_TOKEN)
112+
.build();
113+
114+
assertThat(authorization.getRegisteredClientId()).isEqualTo(REGISTERED_CLIENT_ID);
115+
assertThat(authorization.getPrincipalName()).isEqualTo(PRINCIPAL_NAME);
116+
assertThat(authorization.getAccessToken()).isEqualTo(ACCESS_TOKEN);
117+
assertThat(authorization.getAttributes()).isEqualTo(ATTRIBUTES);
118+
}
119+
}

0 commit comments

Comments
 (0)