Skip to content

Commit 5230ce6

Browse files
committed
Implement OAuth 2.0 Server Metadata (RFC 8414)
See See https://tools.ietf.org/html/rfc8414 Closes gh-54
1 parent 2d8d568 commit 5230ce6

File tree

24 files changed

+2120
-414
lines changed

24 files changed

+2120
-414
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter;
4949
import org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter;
5050
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter;
51+
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerConfigurationEndpointFilter;
5152
import org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter;
5253
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter;
5354
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter;
@@ -84,12 +85,14 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
8485
private RequestMatcher tokenRevocationEndpointMatcher;
8586
private RequestMatcher jwkSetEndpointMatcher;
8687
private RequestMatcher oidcProviderConfigurationEndpointMatcher;
88+
private RequestMatcher oauth2ServerConfigurationEndpointMatcher;
8789
private final RequestMatcher endpointsMatcher = (request) ->
8890
this.authorizationEndpointMatcher.matches(request) ||
8991
this.tokenEndpointMatcher.matches(request) ||
9092
this.tokenRevocationEndpointMatcher.matches(request) ||
9193
this.jwkSetEndpointMatcher.matches(request) ||
92-
this.oidcProviderConfigurationEndpointMatcher.matches(request);
94+
this.oidcProviderConfigurationEndpointMatcher.matches(request) ||
95+
this.oauth2ServerConfigurationEndpointMatcher.matches(request);
9396

9497
/**
9598
* Sets the repository of registered clients.
@@ -201,6 +204,10 @@ public void configure(B builder) {
201204
OidcProviderConfigurationEndpointFilter oidcProviderConfigurationEndpointFilter =
202205
new OidcProviderConfigurationEndpointFilter(providerSettings);
203206
builder.addFilterBefore(postProcess(oidcProviderConfigurationEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
207+
208+
OAuth2AuthorizationServerConfigurationEndpointFilter authorizationServerConfigurationFilter
209+
= new OAuth2AuthorizationServerConfigurationEndpointFilter(providerSettings);
210+
builder.addFilterBefore(postProcess(authorizationServerConfigurationFilter), AbstractPreAuthenticatedProcessingFilter.class);
204211
}
205212

206213
JWKSource<SecurityContext> jwkSource = getJwkSource(builder);
@@ -255,6 +262,8 @@ private void initEndpointMatchers(ProviderSettings providerSettings) {
255262
providerSettings.jwkSetEndpoint(), HttpMethod.GET.name());
256263
this.oidcProviderConfigurationEndpointMatcher = new AntPathRequestMatcher(
257264
OidcProviderConfigurationEndpointFilter.DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI, HttpMethod.GET.name());
265+
this.oauth2ServerConfigurationEndpointMatcher = new AntPathRequestMatcher(
266+
OAuth2AuthorizationServerConfigurationEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_CONFIGURATION_ENDPOINT_URI, HttpMethod.GET.name());
258267
}
259268

260269
private static void validateProviderSettings(ProviderSettings providerSettings) {

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

Lines changed: 370 additions & 0 deletions
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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.core;
17+
18+
19+
import java.net.URL;
20+
import java.util.List;
21+
22+
/**
23+
* A base {@link ClaimAccessor} for the "claims" the Authorization Server can make about
24+
* its configuration, used either in OpenID Connect Discovery 1.0 or OAuth 2.0 Authorization
25+
* Server Metadata.
26+
*
27+
* @author Daniel Garnier-Moiroux
28+
* @since 0.1.1
29+
* @see ClaimAccessor
30+
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc8414#section-2">2. Authorization Server Metadata</a>
31+
* @see <a target="_blank" href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata">3. OpenID Provider Metadata</a>
32+
*/
33+
public interface OAuth2AuthorizationServerMetadataClaimAccessor extends ClaimAccessor {
34+
35+
/**
36+
* Returns the {@code URL} the Authorization Server asserts as its Issuer Identifier {@code (issuer)}.
37+
*
38+
* @return the {@code URL} the Authorization Server asserts as its Issuer Identifier
39+
*/
40+
default URL getIssuer() {
41+
return getClaimAsURL(OAuth2AuthorizationServerMetadataClaimNames.ISSUER);
42+
}
43+
44+
/**
45+
* Returns the {@code URL} of the OAuth 2.0 Authorization Endpoint {@code (authorization_endpoint)}.
46+
*
47+
* @return the {@code URL} of the OAuth 2.0 Authorization Endpoint
48+
*/
49+
default URL getAuthorizationEndpoint() {
50+
return getClaimAsURL(OAuth2AuthorizationServerMetadataClaimNames.AUTHORIZATION_ENDPOINT);
51+
}
52+
53+
/**
54+
* Returns the {@code URL} of the OAuth 2.0 Token Endpoint {@code (token_endpoint)}.
55+
*
56+
* @return the {@code URL} of the OAuth 2.0 Token Endpoint
57+
*/
58+
default URL getTokenEndpoint() {
59+
return getClaimAsURL(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT);
60+
}
61+
62+
/**
63+
* Returns the client authentication methods supported by the OAuth 2.0 Token Endpoint {@code (token_endpoint_auth_methods_supported)}.
64+
*
65+
* @return the client authentication methods supported by the OAuth 2.0 Token Endpoint
66+
*/
67+
default List<String> getTokenEndpointAuthenticationMethods() {
68+
return getClaimAsStringList(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT_AUTH_METHODS_SUPPORTED);
69+
}
70+
71+
/**
72+
* Returns the {@code URL} of the JSON Web Key Set {@code (jwks_uri)}.
73+
*
74+
* @return the {@code URL} of the JSON Web Key Set
75+
*/
76+
default URL getJwkSetUri() {
77+
return getClaimAsURL(OAuth2AuthorizationServerMetadataClaimNames.JWKS_URI);
78+
}
79+
80+
/**
81+
* Returns the OAuth 2.0 {@code response_type} values supported {@code (response_types_supported)}.
82+
*
83+
* @return the OAuth 2.0 {@code response_type} values supported
84+
*/
85+
default List<String> getResponseTypes() {
86+
return getClaimAsStringList(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED);
87+
}
88+
89+
/**
90+
* Returns the OAuth 2.0 {@code grant_type} values supported {@code (grant_types_supported)}.
91+
*
92+
* @return the OAuth 2.0 {@code grant_type} values supported
93+
*/
94+
default List<String> getGrantTypes() {
95+
return getClaimAsStringList(OAuth2AuthorizationServerMetadataClaimNames.GRANT_TYPES_SUPPORTED);
96+
}
97+
98+
/**
99+
* Returns the OAuth 2.0 {@code scope} values supported {@code (scopes_supported)}.
100+
*
101+
* @return the OAuth 2.0 {@code scope} values supported
102+
*/
103+
default List<String> getScopes() {
104+
return this.getClaimAsStringList(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED);
105+
}
106+
107+
/**
108+
* Returns the {@code URL} of the OAuth 2.0 Token Revocation Endpoint {@code (revocation_endpoint)}.
109+
*
110+
* @return the {@code URL} of the OAuth 2.0 Token Revocation Endpoint
111+
*/
112+
default URL getTokenRevocationEndpoint() {
113+
return this.getClaimAsURL(OAuth2AuthorizationServerMetadataClaimNames.REVOCATION_ENDPOINT);
114+
}
115+
116+
/**
117+
* Returns the client authentication methods supported by the OAuth 2.0 Token Revocation Endpoint {@code (revocation_endpoint_auth_methods_supported)}.
118+
*
119+
* @return the client authentication methods supported by the OAuth 2.0 Token Revocation Endpoint
120+
*/
121+
default List<String> getTokenRevocationEndpointAuthenticationMethods() {
122+
return this.getClaimAsStringList(OAuth2AuthorizationServerMetadataClaimNames.REVOCATION_ENDPOINT_AUTH_METHODS_SUPPORTED);
123+
}
124+
125+
/**
126+
* Returns the Proof Key for Code Exchange (PKCE) code challenge methods supported by the
127+
* OAuth 2.0 Authorization Server {@code (code_challenge_methods_supported)}.
128+
*
129+
* @return the code challenge methods supported by the OAuth 2.0 Authorization Server
130+
*/
131+
default List<String> getCodeChallengeMethods() {
132+
return this.getClaimAsStringList(OAuth2AuthorizationServerMetadataClaimNames.CODE_CHALLENGE_METHODS_SUPPORTED);
133+
}
134+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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.core;
17+
18+
import org.springframework.security.oauth2.core.oidc.OidcProviderMetadataClaimNames;
19+
20+
/**
21+
* The names of the "claims" an Authorization Server can make about its configuration,
22+
* used either in OpenID Connect Discovery 1.0 or OAuth 2.0 Authorization Server Metadata.
23+
*
24+
* @author Daniel Garnier-Moiroux
25+
* @since 0.1.1
26+
* @see OidcProviderMetadataClaimNames
27+
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc8414#section-2">2. Authorization Server Metadata</a>
28+
* @see <a target="_blank" href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata">3. OpenID Provider Metadata</a>
29+
*/
30+
public interface OAuth2AuthorizationServerMetadataClaimNames {
31+
32+
/**
33+
* {@code issuer} - the {@code URL} the Authorization Server asserts as its Issuer Identifier
34+
*/
35+
String ISSUER = "issuer";
36+
37+
/**
38+
* {@code authorization_endpoint} - the {@code URL} of the OAuth 2.0 Authorization Endpoint
39+
*/
40+
String AUTHORIZATION_ENDPOINT = "authorization_endpoint";
41+
42+
/**
43+
* {@code token_endpoint} - the {@code URL} of the OAuth 2.0 Token Endpoint
44+
*/
45+
String TOKEN_ENDPOINT = "token_endpoint";
46+
47+
/**
48+
* {@code token_endpoint_auth_methods_supported} - the client authentication methods supported by the OAuth 2.0 Token Endpoint
49+
*/
50+
String TOKEN_ENDPOINT_AUTH_METHODS_SUPPORTED = "token_endpoint_auth_methods_supported";
51+
52+
/**
53+
* {@code jwks_uri} - the {@code URL} of the JSON Web Key Set
54+
*/
55+
String JWKS_URI = "jwks_uri";
56+
57+
/**
58+
* {@code response_types_supported} - the OAuth 2.0 {@code response_type} values supported
59+
*/
60+
String RESPONSE_TYPES_SUPPORTED = "response_types_supported";
61+
62+
/**
63+
* {@code grant_types_supported} - the OAuth 2.0 {@code grant_type} values supported
64+
*/
65+
String GRANT_TYPES_SUPPORTED = "grant_types_supported";
66+
67+
/**
68+
* {@code scopes_supported} - the OAuth 2.0 {@code scope} values supported
69+
*/
70+
String SCOPES_SUPPORTED = "scopes_supported";
71+
72+
/**
73+
* {@code revocation_endpoint} - the {@code URL} of the OAuth 2.0 Token Revocation Endpoint
74+
*/
75+
String REVOCATION_ENDPOINT = "revocation_endpoint";
76+
77+
/**
78+
* {@code token_endpoint_auth_methods_supported} - the client authentication methods supported by the OAuth 2.0 Token Revocation Endpoint
79+
*/
80+
String REVOCATION_ENDPOINT_AUTH_METHODS_SUPPORTED = "revocation_endpoint_auth_methods_supported";
81+
82+
/**
83+
* {@code code_challenge_methods_supported} - the Proof Key for Code Exchange (PKCE) code challenge methods
84+
* supported by the OAuth 2.0 Authorization Server
85+
*/
86+
String CODE_CHALLENGE_METHODS_SUPPORTED = "code_challenge_methods_supported";
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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.core.endpoint;
17+
18+
import org.springframework.security.oauth2.core.AbstractOAuth2AuthorizationServerConfiguration;
19+
import org.springframework.security.oauth2.core.OAuth2AuthorizationServerMetadataClaimAccessor;
20+
import org.springframework.security.oauth2.core.Version;
21+
import org.springframework.util.Assert;
22+
23+
import java.io.Serializable;
24+
import java.util.Map;
25+
26+
/**
27+
* A representation of an OAuth 2.0 Authorization Server Configuration response,
28+
* which is returned form an OAuth 2.0 Authorization Server's Configuration Endpoint,
29+
* and contains a set of claims about the Authorization Server's configuration.
30+
* The claims are defined by the OAuth 2.0 Authorization Server Metadata
31+
* specification (RFC 8414).
32+
*
33+
* @author Daniel Garnier-Moiroux
34+
* @since 0.1.1
35+
* @see AbstractOAuth2AuthorizationServerConfiguration
36+
* @see OAuth2AuthorizationServerMetadataClaimAccessor
37+
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc8414#section-3.2">3.2. Authorization Server Metadata Response</a>
38+
*/
39+
public final class OAuth2AuthorizationServerConfiguration extends AbstractOAuth2AuthorizationServerConfiguration
40+
implements OAuth2AuthorizationServerMetadataClaimAccessor, Serializable {
41+
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
42+
43+
private OAuth2AuthorizationServerConfiguration(Map<String, Object> claims) {
44+
super(claims);
45+
}
46+
47+
/**
48+
* Constructs a new {@link Builder} with empty claims.
49+
*
50+
* @return the {@link Builder}
51+
*/
52+
public static Builder builder() {
53+
return new Builder();
54+
}
55+
56+
/**
57+
* Constructs a new {@link Builder} with the provided claims.
58+
*
59+
* @param claims the claims to initialize the builder
60+
* @return the {@link Builder}
61+
*/
62+
public static Builder withClaims(Map<String, Object> claims) {
63+
Assert.notEmpty(claims, "claims cannot be empty");
64+
return new Builder()
65+
.claims(c -> c.putAll(claims));
66+
}
67+
68+
/**
69+
* Helps configure an {@link OAuth2AuthorizationServerConfiguration}.
70+
*/
71+
public static class Builder
72+
extends AbstractOAuth2AuthorizationServerConfiguration.AbstractBuilder<OAuth2AuthorizationServerConfiguration, Builder> {
73+
private Builder() {
74+
}
75+
76+
/**
77+
* Validate the claims and build the {@link OAuth2AuthorizationServerConfiguration}.
78+
* <p>
79+
* The following claims are REQUIRED:
80+
* {@code issuer}, {@code authorization_endpoint}, {@code token_endpoint},
81+
* {@code jwks_uri} and {@code response_types_supported}.
82+
*
83+
* @return the {@link OAuth2AuthorizationServerConfiguration}
84+
*/
85+
public OAuth2AuthorizationServerConfiguration build() {
86+
validateCommonClaims();
87+
removeEmptyClaims();
88+
return new OAuth2AuthorizationServerConfiguration(this.claims);
89+
}
90+
91+
}
92+
}

0 commit comments

Comments
 (0)