35
35
import org .springframework .security .oauth2 .server .authorization .OAuth2AuthorizationService ;
36
36
import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2AccessTokenAuthenticationToken ;
37
37
import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2AuthorizationCodeAuthenticationToken ;
38
+ import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2ClientAuthenticationToken ;
39
+ import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2ClientCredentialsAuthenticationToken ;
38
40
import org .springframework .security .web .util .matcher .AntPathRequestMatcher ;
39
41
import org .springframework .security .web .util .matcher .RequestMatcher ;
40
42
import org .springframework .util .Assert ;
48
50
import javax .servlet .http .HttpServletResponse ;
49
51
import java .io .IOException ;
50
52
import java .time .temporal .ChronoUnit ;
53
+ import java .util .Arrays ;
54
+ import java .util .HashMap ;
55
+ import java .util .HashSet ;
56
+ import java .util .Map ;
57
+ import java .util .Set ;
51
58
52
59
/**
53
60
* A {@code Filter} for the OAuth 2.0 Authorization Code Grant,
@@ -86,8 +93,8 @@ public class OAuth2TokenEndpointFilter extends OncePerRequestFilter {
86
93
private final AuthenticationManager authenticationManager ;
87
94
private final OAuth2AuthorizationService authorizationService ;
88
95
private final RequestMatcher tokenEndpointMatcher ;
89
- private final Converter <HttpServletRequest , Authentication > authorizationGrantAuthenticationConverter =
90
- new AuthorizationCodeAuthenticationConverter ();
96
+ private final Converter <HttpServletRequest , Authentication > authorizationGrantAuthenticationConverter ;
97
+
91
98
private final HttpMessageConverter <OAuth2AccessTokenResponse > accessTokenHttpResponseConverter =
92
99
new OAuth2AccessTokenResponseHttpMessageConverter ();
93
100
private final HttpMessageConverter <OAuth2Error > errorHttpResponseConverter =
@@ -119,6 +126,11 @@ public OAuth2TokenEndpointFilter(AuthenticationManager authenticationManager,
119
126
this .authenticationManager = authenticationManager ;
120
127
this .authorizationService = authorizationService ;
121
128
this .tokenEndpointMatcher = new AntPathRequestMatcher (tokenEndpointUri , HttpMethod .POST .name ());
129
+
130
+ Map <AuthorizationGrantType , Converter <HttpServletRequest , Authentication >> converters = new HashMap <>();
131
+ converters .put (AuthorizationGrantType .AUTHORIZATION_CODE , new AuthorizationCodeAuthenticationConverter ());
132
+ converters .put (AuthorizationGrantType .CLIENT_CREDENTIALS , new ClientCredentialsAuthenticationConverter ());
133
+ this .authorizationGrantAuthenticationConverter = new DelegatingAuthorizationGrantAuthenticationConverter (converters );
122
134
}
123
135
124
136
@ Override
@@ -131,8 +143,16 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
131
143
}
132
144
133
145
try {
134
- Authentication authorizationGrantAuthentication =
135
- this .authorizationGrantAuthenticationConverter .convert (request );
146
+ String [] grantTypes = request .getParameterValues (OAuth2ParameterNames .GRANT_TYPE );
147
+ if (grantTypes == null || grantTypes .length == 0 ) {
148
+ throwError (OAuth2ErrorCodes .INVALID_REQUEST , "grant_type" );
149
+ }
150
+
151
+ Authentication authorizationGrantAuthentication = this .authorizationGrantAuthenticationConverter .convert (request );
152
+ if (authorizationGrantAuthentication == null ) {
153
+ throwError (OAuth2ErrorCodes .UNSUPPORTED_GRANT_TYPE , "grant_type" );
154
+ }
155
+
136
156
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
137
157
(OAuth2AccessTokenAuthenticationToken ) this .authenticationManager .authenticate (authorizationGrantAuthentication );
138
158
sendAccessTokenResponse (response , accessTokenAuthentication .getAccessToken ());
@@ -161,7 +181,7 @@ private void sendErrorResponse(HttpServletResponse response, OAuth2Error error)
161
181
this .errorHttpResponseConverter .write (error , null , httpResponse );
162
182
}
163
183
164
- private static OAuth2AuthenticationException throwError (String errorCode , String parameterName ) {
184
+ private static void throwError (String errorCode , String parameterName ) {
165
185
OAuth2Error error = new OAuth2Error (errorCode , "OAuth 2.0 Parameter: " + parameterName ,
166
186
"https://tools.ietf.org/html/rfc6749#section-5.2" );
167
187
throw new OAuth2AuthenticationException (error );
@@ -214,4 +234,29 @@ public Authentication convert(HttpServletRequest request) {
214
234
new OAuth2AuthorizationCodeAuthenticationToken (code , clientId , redirectUri );
215
235
}
216
236
}
237
+
238
+ private static class ClientCredentialsAuthenticationConverter implements Converter <HttpServletRequest , Authentication > {
239
+
240
+ @ Override
241
+ public Authentication convert (HttpServletRequest request ) {
242
+ final Authentication authentication = SecurityContextHolder .getContext ().getAuthentication ();
243
+ final OAuth2ClientAuthenticationToken clientAuthenticationToken = (OAuth2ClientAuthenticationToken ) authentication ;
244
+
245
+ // grant_type (REQUIRED)
246
+ String grantType = request .getParameter (OAuth2ParameterNames .GRANT_TYPE );
247
+ if (!AuthorizationGrantType .CLIENT_CREDENTIALS .getValue ().equals (grantType )) {
248
+ throwError (OAuth2ErrorCodes .UNSUPPORTED_GRANT_TYPE , OAuth2ParameterNames .GRANT_TYPE );
249
+ }
250
+
251
+ // scope (OPTIONAL)
252
+ // https://tools.ietf.org/html/rfc6749#section-4.4.2
253
+ String scopeParameter = request .getParameter (OAuth2ParameterNames .SCOPE );
254
+ if (StringUtils .isEmpty (scopeParameter )) {
255
+ return new OAuth2ClientCredentialsAuthenticationToken (clientAuthenticationToken );
256
+ }
257
+
258
+ Set <String > requestedScopes = new HashSet <>(Arrays .asList (StringUtils .delimitedListToStringArray (scopeParameter , " " )));
259
+ return new OAuth2ClientCredentialsAuthenticationToken (clientAuthenticationToken , requestedScopes );
260
+ }
261
+ }
217
262
}
0 commit comments