Skip to content

Commit e7feb6c

Browse files
committed
Polish gh-189
1 parent 8224a0d commit e7feb6c

File tree

36 files changed

+2285
-1502
lines changed

36 files changed

+2285
-1502
lines changed

oauth2-authorization-server/spring-security-oauth2-authorization-server.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ dependencies {
1616
testCompile 'org.assertj:assertj-core'
1717
testCompile 'org.mockito:mockito-core'
1818
testCompile 'com.jayway.jsonpath:json-path'
19-
testCompile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
2019

2120
provided 'javax.servlet:javax.servlet-api'
2221
}

oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configuration/OAuth2AuthorizationServerConfiguration.java

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,35 @@
1515
*/
1616
package org.springframework.security.config.annotation.web.configuration;
1717

18+
import java.util.HashSet;
19+
import java.util.Set;
20+
21+
import com.nimbusds.jose.JWSAlgorithm;
22+
import com.nimbusds.jose.jwk.source.JWKSource;
23+
import com.nimbusds.jose.proc.JWSKeySelector;
24+
import com.nimbusds.jose.proc.JWSVerificationKeySelector;
25+
import com.nimbusds.jose.proc.SecurityContext;
26+
import com.nimbusds.jwt.proc.ConfigurableJWTProcessor;
27+
import com.nimbusds.jwt.proc.DefaultJWTProcessor;
28+
1829
import org.springframework.context.annotation.Bean;
1930
import org.springframework.context.annotation.Configuration;
2031
import org.springframework.core.Ordered;
2132
import org.springframework.core.annotation.Order;
2233
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2334
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer;
2435
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
36+
import org.springframework.security.oauth2.jwt.JwtDecoder;
37+
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
2538
import org.springframework.security.web.SecurityFilterChain;
2639
import org.springframework.security.web.util.matcher.RequestMatcher;
2740

2841
/**
2942
* {@link Configuration} for OAuth 2.0 Authorization Server support.
3043
*
3144
* @author Joe Grandja
32-
* @see OAuth2AuthorizationServerConfigurer
3345
* @since 0.0.1
46+
* @see OAuth2AuthorizationServerConfigurer
3447
*/
3548
@Configuration(proxyBeanMethods = false)
3649
public class OAuth2AuthorizationServerConfiguration {
@@ -48,16 +61,32 @@ public static void applyDefaultSecurity(HttpSecurity http) throws Exception {
4861
new OAuth2AuthorizationServerConfigurer<>();
4962
RequestMatcher endpointsMatcher = authorizationServerConfigurer
5063
.getEndpointsMatcher();
64+
5165
http
5266
.requestMatcher(endpointsMatcher)
5367
.authorizeRequests(authorizeRequests ->
54-
authorizeRequests.anyRequest().authenticated()
55-
).csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
68+
authorizeRequests.anyRequest().authenticated()
69+
)
70+
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
71+
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
5672
.apply(authorizationServerConfigurer);
57-
58-
if (authorizationServerConfigurer.isOidcClientRegistrationEnabled()) {
59-
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
60-
}
6173
}
6274
// @formatter:on
75+
76+
@Bean
77+
public static JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
78+
Set<JWSAlgorithm> jwsAlgs = new HashSet<>();
79+
jwsAlgs.addAll(JWSAlgorithm.Family.RSA);
80+
jwsAlgs.addAll(JWSAlgorithm.Family.EC);
81+
jwsAlgs.addAll(JWSAlgorithm.Family.HMAC_SHA);
82+
ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
83+
JWSKeySelector<SecurityContext> jwsKeySelector =
84+
new JWSVerificationKeySelector<>(jwsAlgs, jwkSource);
85+
jwtProcessor.setJWSKeySelector(jwsKeySelector);
86+
// Override the default Nimbus claims set verifier as NimbusJwtDecoder handles it instead
87+
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
88+
});
89+
return new NimbusJwtDecoder(jwtProcessor);
90+
}
91+
6392
}

oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerConfigurer.java

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@
4444
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2RefreshTokenAuthenticationProvider;
4545
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenIntrospectionAuthenticationProvider;
4646
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenRevocationAuthenticationProvider;
47-
import org.springframework.security.oauth2.server.authorization.authentication.OidcClientRegistrationAuthenticationProvider;
4847
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
4948
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
49+
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcClientRegistrationAuthenticationProvider;
5050
import org.springframework.security.oauth2.server.authorization.oidc.web.OidcClientRegistrationEndpointFilter;
5151
import org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter;
5252
import org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter;
@@ -152,17 +152,6 @@ public RequestMatcher getEndpointsMatcher() {
152152
return this.endpointsMatcher;
153153
}
154154

155-
/**
156-
* Returns {@code true} if the OIDC Client Registration endpoint is enabled.
157-
* The default is {@code false}.
158-
*
159-
* @return {@code true} if the OIDC Client Registration endpoint is enabled, {@code false} otherwise
160-
*/
161-
public boolean isOidcClientRegistrationEnabled() {
162-
ProviderSettings providerSettings = getProviderSettings(this.getBuilder());
163-
return providerSettings.isOidClientRegistrationEndpointEnabled();
164-
}
165-
166155
@Override
167156
public void init(B builder) {
168157
ProviderSettings providerSettings = getProviderSettings(builder);
@@ -216,10 +205,12 @@ public void init(B builder) {
216205
getAuthorizationService(builder));
217206
builder.authenticationProvider(postProcess(tokenRevocationAuthenticationProvider));
218207

219-
OidcClientRegistrationAuthenticationProvider clientRegistrationAuthenticationProvider =
208+
// TODO Make OpenID Client Registration an "opt-in" feature
209+
OidcClientRegistrationAuthenticationProvider oidcClientRegistrationAuthenticationProvider =
220210
new OidcClientRegistrationAuthenticationProvider(
211+
getRegisteredClientRepository(builder),
221212
getAuthorizationService(builder));
222-
builder.authenticationProvider(postProcess(clientRegistrationAuthenticationProvider));
213+
builder.authenticationProvider(postProcess(oidcClientRegistrationAuthenticationProvider));
223214

224215
ExceptionHandlingConfigurer<B> exceptionHandling = builder.getConfigurer(ExceptionHandlingConfigurer.class);
225216
if (exceptionHandling != null) {
@@ -246,9 +237,6 @@ public void configure(B builder) {
246237
builder.addFilterBefore(postProcess(authorizationServerMetadataEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
247238
}
248239

249-
RegisteredClientRepository registeredClientRepository = getRegisteredClientRepository(builder);
250-
OAuth2AuthorizationService authorizationService = getAuthorizationService(builder);
251-
252240
JWKSource<SecurityContext> jwkSource = getJwkSource(builder);
253241
NimbusJwkSetEndpointFilter jwkSetEndpointFilter = new NimbusJwkSetEndpointFilter(
254242
jwkSource,
@@ -268,8 +256,8 @@ public void configure(B builder) {
268256

269257
OAuth2AuthorizationEndpointFilter authorizationEndpointFilter =
270258
new OAuth2AuthorizationEndpointFilter(
271-
registeredClientRepository,
272-
authorizationService,
259+
getRegisteredClientRepository(builder),
260+
getAuthorizationService(builder),
273261
providerSettings.authorizationEndpoint());
274262
builder.addFilterBefore(postProcess(authorizationEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
275263

@@ -291,14 +279,12 @@ public void configure(B builder) {
291279
providerSettings.tokenRevocationEndpoint());
292280
builder.addFilterAfter(postProcess(tokenRevocationEndpointFilter), OAuth2TokenIntrospectionEndpointFilter.class);
293281

294-
if (providerSettings.isOidClientRegistrationEndpointEnabled()) {
295-
OidcClientRegistrationEndpointFilter oidcClientRegistrationEndpointFilter =
296-
new OidcClientRegistrationEndpointFilter(
297-
registeredClientRepository,
298-
authenticationManager,
299-
providerSettings.oidcClientRegistrationEndpoint());
300-
builder.addFilterAfter(postProcess(oidcClientRegistrationEndpointFilter), OAuth2TokenRevocationEndpointFilter.class);
301-
}
282+
// TODO Make OpenID Client Registration an "opt-in" feature
283+
OidcClientRegistrationEndpointFilter oidcClientRegistrationEndpointFilter =
284+
new OidcClientRegistrationEndpointFilter(
285+
authenticationManager,
286+
providerSettings.oidcClientRegistrationEndpoint());
287+
builder.addFilterAfter(postProcess(oidcClientRegistrationEndpointFilter), OAuth2TokenRevocationEndpointFilter.class);
302288
}
303289

304290
private void initEndpointMatchers(ProviderSettings providerSettings) {
@@ -322,8 +308,7 @@ private void initEndpointMatchers(ProviderSettings providerSettings) {
322308
this.authorizationServerMetadataEndpointMatcher = new AntPathRequestMatcher(
323309
OAuth2AuthorizationServerMetadataEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI, HttpMethod.GET.name());
324310
this.oidcClientRegistrationEndpointMatcher = new AntPathRequestMatcher(
325-
providerSettings.oidcClientRegistrationEndpoint(),
326-
HttpMethod.POST.name());
311+
providerSettings.oidcClientRegistrationEndpoint(), HttpMethod.POST.name());
327312
}
328313

329314
private static void validateProviderSettings(ProviderSettings providerSettings) {

oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/core/oidc/OidcClientMetadataClaimAccessor.java

Lines changed: 51 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@
1515
*/
1616
package org.springframework.security.oauth2.core.oidc;
1717

18-
import org.springframework.security.oauth2.core.ClaimAccessor;
19-
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
20-
2118
import java.time.Instant;
2219
import java.util.List;
2320

21+
import org.springframework.security.oauth2.core.ClaimAccessor;
22+
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
23+
2424
/**
25-
* A {@link ClaimAccessor} for the "claims" that can be returned
26-
* in the OpenID Client Registration Response.
25+
* A {@link ClaimAccessor} for the "claims" that are contained
26+
* in the OpenID Client Registration Request and Response.
2727
*
2828
* @author Ovidiu Popa
29+
* @author Joe Grandja
2930
* @since 0.1.1
3031
* @see ClaimAccessor
3132
* @see OidcClientMetadataClaimNames
@@ -35,96 +36,102 @@
3536
public interface OidcClientMetadataClaimAccessor extends ClaimAccessor {
3637

3738
/**
38-
* Returns the redirect URI(s) that the client may use in redirect-based flows.
39+
* Returns the Client Identifier {@code (client_id)}.
3940
*
40-
* @return the {@code List} of redirect URI(s)
41+
* @return the Client Identifier
4142
*/
42-
default List<String> getRedirectUris() {
43-
return getClaimAsStringList(OidcClientMetadataClaimNames.REDIRECT_URIS);
43+
default String getClientId() {
44+
return getClaimAsString(OidcClientMetadataClaimNames.CLIENT_ID);
4445
}
4546

4647
/**
47-
* Returns the OAuth 2.0 {@code response_type} values that the client may use.
48+
* Returns the time at which the Client Identifier was issued {@code (client_id_issued_at)}.
4849
*
49-
* @return the {@code List} of {@code response_type}
50+
* @return the time at which the Client Identifier was issued
5051
*/
51-
default List<String> getResponseTypes() {
52-
return getClaimAsStringList(OidcClientMetadataClaimNames.RESPONSE_TYPES);
52+
default Instant getClientIdIssuedAt() {
53+
return getClaimAsInstant(OidcClientMetadataClaimNames.CLIENT_ID_ISSUED_AT);
5354
}
5455

5556
/**
56-
* Returns the authorization {@code grant_types} that the client may use.
57+
* Returns the Client Secret {@code (client_secret)}.
5758
*
58-
* @return the {@code List} of authorization {@code grant_types}
59+
* @return the Client Secret
5960
*/
60-
default List<String> getGrantTypes() {
61-
return getClaimAsStringList(OidcClientMetadataClaimNames.GRANT_TYPES);
61+
default String getClientSecret() {
62+
return getClaimAsString(OidcClientMetadataClaimNames.CLIENT_SECRET);
63+
}
64+
65+
/**
66+
* Returns the time at which the {@code client_secret} will expire {@code (client_secret_expires_at)}.
67+
*
68+
* @return the time at which the {@code client_secret} will expire
69+
*/
70+
default Instant getClientSecretExpiresAt() {
71+
return getClaimAsInstant(OidcClientMetadataClaimNames.CLIENT_SECRET_EXPIRES_AT);
6272
}
6373

6474
/**
65-
* Returns the {@code client_name}.
75+
* Returns the name of the Client to be presented to the End-User {@code (client_name)}.
6676
*
67-
* @return the {@code client_name}
77+
* @return the name of the Client to be presented to the End-User
6878
*/
6979
default String getClientName() {
7080
return getClaimAsString(OidcClientMetadataClaimNames.CLIENT_NAME);
7181
}
7282

7383
/**
74-
* Returns the scope(s) that the client may use.
84+
* Returns the redirection {@code URI} values used by the Client {@code (redirect_uris)}.
7585
*
76-
* @return the scope(s)
86+
* @return the redirection {@code URI} values used by the Client
7787
*/
78-
default String getScope() {
79-
return getClaimAsString(OidcClientMetadataClaimNames.SCOPE);
88+
default List<String> getRedirectUris() {
89+
return getClaimAsStringList(OidcClientMetadataClaimNames.REDIRECT_URIS);
8090
}
8191

8292
/**
83-
* Returns the {@link ClientAuthenticationMethod authentication method} that the client may use.
93+
* Returns the authentication method used by the Client for the Token Endpoint {@code (token_endpoint_auth_method)}.
8494
*
85-
* @return the {@link ClientAuthenticationMethod authentication method}
95+
* @return the authentication method used by the Client for the Token Endpoint
8696
*/
8797
default String getTokenEndpointAuthenticationMethod() {
8898
return getClaimAsString(OidcClientMetadataClaimNames.TOKEN_ENDPOINT_AUTH_METHOD);
8999
}
90100

91101
/**
92-
* Returns the {@code client_id}.
102+
* Returns the OAuth 2.0 {@code grant_type} values that the Client will restrict itself to using {@code (grant_types)}.
93103
*
94-
* @return the {@code client_id}
104+
* @return the OAuth 2.0 {@code grant_type} values that the Client will restrict itself to using
95105
*/
96-
default String getClientId() {
97-
return getClaimAsString(OidcClientMetadataClaimNames.CLIENT_ID);
106+
default List<String> getGrantTypes() {
107+
return getClaimAsStringList(OidcClientMetadataClaimNames.GRANT_TYPES);
98108
}
99109

100110
/**
101-
* Returns the {@code client_id_issued_at} timestamp.
111+
* Returns the OAuth 2.0 {@code response_type} values that the Client will restrict itself to using {@code (response_types)}.
102112
*
103-
* @return the {@code client_id_issued_at} timestamp
113+
* @return the OAuth 2.0 {@code response_type} values that the Client will restrict itself to using
104114
*/
105-
default Instant getClientIdIssuedAt() {
106-
return getClaimAsInstant(OidcClientMetadataClaimNames.CLIENT_ID_ISSUED_AT);
115+
default List<String> getResponseTypes() {
116+
return getClaimAsStringList(OidcClientMetadataClaimNames.RESPONSE_TYPES);
107117
}
108118

109119
/**
110-
* Returns the {@code client_secret}.
120+
* Returns the OAuth 2.0 {@code scope} values that the Client will restrict itself to using {@code (scope)}.
111121
*
112-
* @return the {@code client_secret}
122+
* @return the OAuth 2.0 {@code scope} values that the Client will restrict itself to using
113123
*/
114-
default String getClientSecret() {
115-
return getClaimAsString(OidcClientMetadataClaimNames.CLIENT_SECRET);
124+
default List<String> getScopes() {
125+
return getClaimAsStringList(OidcClientMetadataClaimNames.SCOPE);
116126
}
117127

118128
/**
119-
* Returns the {@code client_secret_expires_at} timestamp.
129+
* Returns the {@link SignatureAlgorithm JWS} algorithm required for signing the {@link OidcIdToken ID Token} issued to the Client {@code (id_token_signed_response_alg)}.
120130
*
121-
* @return the {@code client_secret_expires_at} timestamp
131+
* @return the {@link SignatureAlgorithm JWS} algorithm required for signing the {@link OidcIdToken ID Token} issued to the Client
122132
*/
123-
default Instant getClientSecretExpiresAt() {
124-
return getClaimAsInstant(OidcClientMetadataClaimNames.CLIENT_SECRET_EXPIRES_AT);
133+
default String getIdTokenSignedResponseAlgorithm() {
134+
return getClaimAsString(OidcClientMetadataClaimNames.ID_TOKEN_SIGNED_RESPONSE_ALG);
125135
}
126136

127-
128-
129-
130137
}

0 commit comments

Comments
 (0)