15
15
*/
16
16
package org .springframework .security .oauth2 .client .web .server ;
17
17
18
- import java .net .URI ;
19
- import java .util .Base64 ;
20
- import java .util .HashMap ;
21
- import java .util .Map ;
22
-
23
- import org .springframework .http .HttpStatus ;
24
- import org .springframework .http .server .reactive .ServerHttpRequest ;
25
- import org .springframework .http .server .reactive .ServerHttpRequestDecorator ;
26
- import org .springframework .security .crypto .keygen .Base64StringKeyGenerator ;
27
- import org .springframework .security .crypto .keygen .StringKeyGenerator ;
28
18
import org .springframework .security .oauth2 .client .ClientAuthorizationRequiredException ;
29
19
import org .springframework .security .oauth2 .client .registration .ClientRegistration ;
30
20
import org .springframework .security .oauth2 .client .registration .ClientRegistrationRepository ;
31
21
import org .springframework .security .oauth2 .client .registration .ReactiveClientRegistrationRepository ;
32
22
import org .springframework .security .oauth2 .client .web .AuthorizationRequestRepository ;
33
23
import org .springframework .security .oauth2 .core .AuthorizationGrantType ;
34
24
import org .springframework .security .oauth2 .core .endpoint .OAuth2AuthorizationRequest ;
35
- import org .springframework .security .oauth2 .core .endpoint .OAuth2ParameterNames ;
36
25
import org .springframework .security .web .server .DefaultServerRedirectStrategy ;
37
26
import org .springframework .security .web .server .ServerRedirectStrategy ;
38
- import org .springframework .security .web .server .util .matcher .PathPatternParserServerWebExchangeMatcher ;
39
- import org .springframework .security .web .server .util .matcher .ServerWebExchangeMatcher ;
40
27
import org .springframework .util .Assert ;
41
28
import org .springframework .web .server .ServerWebExchange ;
42
29
import org .springframework .web .server .WebFilter ;
43
30
import org .springframework .web .server .WebFilterChain ;
44
31
import org .springframework .web .util .UriComponentsBuilder ;
45
-
46
32
import reactor .core .publisher .Mono ;
47
33
34
+ import java .net .URI ;
35
+
48
36
/**
49
37
* This {@code WebFilter} initiates the authorization code grant or implicit grant flow
50
38
* by redirecting the End-User's user-agent to the Authorization Server's Authorization Endpoint.
63
51
* {@link ClientRegistration#getRegistrationId() registration identifier} of the client
64
52
* that is used for initiating the OAuth 2.0 Authorization Request.
65
53
*
66
- * <p>
67
- * <b>NOTE:</b> The default base {@code URI} {@code /oauth2/authorization} may be overridden
68
- * via it's constructor {@link #OAuth2AuthorizationRequestRedirectWebFilter(ReactiveClientRegistrationRepository, String)}.
69
-
70
54
* @author Rob Winch
71
55
* @since 5.1
72
56
* @see OAuth2AuthorizationRequest
79
63
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.2.1">Section 4.2.1 Authorization Request (Implicit)</a>
80
64
*/
81
65
public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
82
- /**
83
- * The default base {@code URI} used for authorization requests.
84
- */
85
- public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization" ;
86
- private static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId" ;
87
- private static final String AUTHORIZATION_REQUIRED_EXCEPTION_ATTR_NAME =
88
- ClientAuthorizationRequiredException .class .getName () + ".AUTHORIZATION_REQUIRED_EXCEPTION" ;
89
- private final ServerWebExchangeMatcher authorizationRequestMatcher ;
90
- private final ReactiveClientRegistrationRepository clientRegistrationRepository ;
91
66
private final ServerRedirectStrategy authorizationRedirectStrategy = new DefaultServerRedirectStrategy ();
92
- private final StringKeyGenerator stateGenerator = new Base64StringKeyGenerator ( Base64 . getUrlEncoder ()) ;
67
+ private final ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver ;
93
68
private ServerAuthorizationRequestRepository <OAuth2AuthorizationRequest > authorizationRequestRepository =
94
69
new WebSessionOAuth2ServerAuthorizationRequestRepository ();
95
70
@@ -99,23 +74,17 @@ public class OAuth2AuthorizationRequestRedirectWebFilter implements WebFilter {
99
74
* @param clientRegistrationRepository the repository of client registrations
100
75
*/
101
76
public OAuth2AuthorizationRequestRedirectWebFilter (ReactiveClientRegistrationRepository clientRegistrationRepository ) {
102
- this (clientRegistrationRepository , DEFAULT_AUTHORIZATION_REQUEST_BASE_URI );
77
+ this . authorizationRequestResolver = new DefaultServerOAuth2AuthorizationRequestResolver (clientRegistrationRepository );
103
78
}
104
79
105
80
/**
106
81
* Constructs an {@code OAuth2AuthorizationRequestRedirectFilter} using the provided parameters.
107
82
*
108
- * @param clientRegistrationRepository the repository of client registrations
109
- * @param authorizationRequestBaseUri the base {@code URI} used for authorization requests
83
+ * @param authorizationRequestResolver the resolver to use
110
84
*/
111
- public OAuth2AuthorizationRequestRedirectWebFilter (
112
- ReactiveClientRegistrationRepository clientRegistrationRepository , String authorizationRequestBaseUri ) {
113
-
114
- Assert .hasText (authorizationRequestBaseUri , "authorizationRequestBaseUri cannot be empty" );
115
- Assert .notNull (clientRegistrationRepository , "clientRegistrationRepository cannot be null" );
116
- this .authorizationRequestMatcher = new PathPatternParserServerWebExchangeMatcher (
117
- authorizationRequestBaseUri + "/{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}" );
118
- this .clientRegistrationRepository = clientRegistrationRepository ;
85
+ public OAuth2AuthorizationRequestRedirectWebFilter (ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver ) {
86
+ Assert .notNull (authorizationRequestResolver , "authorizationRequestResolver cannot be null" );
87
+ this .authorizationRequestResolver = authorizationRequestResolver ;
119
88
}
120
89
121
90
/**
@@ -131,54 +100,15 @@ public final void setAuthorizationRequestRepository(
131
100
132
101
@ Override
133
102
public Mono <Void > filter (ServerWebExchange exchange , WebFilterChain chain ) {
134
- return this .authorizationRequestMatcher .matches (exchange )
135
- .filter (matchResult -> matchResult .isMatch ())
103
+ return this .authorizationRequestResolver .resolve (exchange )
136
104
.switchIfEmpty (chain .filter (exchange ).then (Mono .empty ()))
137
- .map (ServerWebExchangeMatcher .MatchResult ::getVariables )
138
- .map (variables -> variables .get (REGISTRATION_ID_URI_VARIABLE_NAME ))
139
- .cast (String .class )
140
- .onErrorResume (ClientAuthorizationRequiredException .class , e -> Mono .just (e .getClientRegistrationId ()))
141
- .flatMap (clientRegistrationId -> this .findByRegistrationId (exchange , clientRegistrationId ))
105
+ .onErrorResume (ClientAuthorizationRequiredException .class , e -> this .authorizationRequestResolver .resolve (exchange , e .getClientRegistrationId ()))
142
106
.flatMap (clientRegistration -> sendRedirectForAuthorization (exchange , clientRegistration ));
143
107
}
144
108
145
- private Mono <ClientRegistration > findByRegistrationId (ServerWebExchange exchange , String clientRegistration ) {
146
- return this .clientRegistrationRepository .findByRegistrationId (clientRegistration )
147
- .switchIfEmpty (Mono .defer (() -> {
148
- exchange .getResponse ().setStatusCode (HttpStatus .BAD_REQUEST );
149
- return exchange .getResponse ().setComplete ().then (Mono .empty ());
150
- }));
151
- }
152
-
153
109
private Mono <Void > sendRedirectForAuthorization (ServerWebExchange exchange ,
154
- ClientRegistration clientRegistration ) {
110
+ OAuth2AuthorizationRequest authorizationRequest ) {
155
111
return Mono .defer (() -> {
156
- String redirectUriStr = this
157
- .expandRedirectUri (exchange .getRequest (), clientRegistration );
158
-
159
- Map <String , Object > additionalParameters = new HashMap <>();
160
- additionalParameters .put (OAuth2ParameterNames .REGISTRATION_ID ,
161
- clientRegistration .getRegistrationId ());
162
-
163
- OAuth2AuthorizationRequest .Builder builder ;
164
- if (AuthorizationGrantType .AUTHORIZATION_CODE .equals (clientRegistration .getAuthorizationGrantType ())) {
165
- builder = OAuth2AuthorizationRequest .authorizationCode ();
166
- }
167
- else if (AuthorizationGrantType .IMPLICIT .equals (clientRegistration .getAuthorizationGrantType ())) {
168
- builder = OAuth2AuthorizationRequest .implicit ();
169
- }
170
- else {
171
- throw new IllegalArgumentException (
172
- "Invalid Authorization Grant Type (" + clientRegistration .getAuthorizationGrantType ().getValue ()
173
- + ") for Client Registration with Id: " + clientRegistration .getRegistrationId ());
174
- }
175
- OAuth2AuthorizationRequest authorizationRequest = builder
176
- .clientId (clientRegistration .getClientId ())
177
- .authorizationUri (clientRegistration .getProviderDetails ().getAuthorizationUri ())
178
- .redirectUri (redirectUriStr ).scopes (clientRegistration .getScopes ())
179
- .state (this .stateGenerator .generateKey ())
180
- .additionalParameters (additionalParameters ).build ();
181
-
182
112
Mono <Void > saveAuthorizationRequest = Mono .empty ();
183
113
if (AuthorizationGrantType .AUTHORIZATION_CODE .equals (authorizationRequest .getGrantType ())) {
184
114
saveAuthorizationRequest = this .authorizationRequestRepository
@@ -192,27 +122,4 @@ else if (AuthorizationGrantType.IMPLICIT.equals(clientRegistration.getAuthorizat
192
122
.then (this .authorizationRedirectStrategy .sendRedirect (exchange , redirectUri ));
193
123
});
194
124
}
195
-
196
- private String expandRedirectUri (ServerHttpRequest request , ClientRegistration clientRegistration ) {
197
- // Supported URI variables -> baseUrl, action, registrationId
198
- // Used in -> CommonOAuth2Provider.DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}"
199
- Map <String , String > uriVariables = new HashMap <>();
200
- uriVariables .put ("registrationId" , clientRegistration .getRegistrationId ());
201
-
202
- String baseUrl = UriComponentsBuilder .fromHttpRequest (new ServerHttpRequestDecorator (request ))
203
- .replacePath (request .getPath ().contextPath ().value ())
204
- .replaceQuery (null )
205
- .build ()
206
- .toUriString ();
207
- uriVariables .put ("baseUrl" , baseUrl );
208
-
209
- if (AuthorizationGrantType .AUTHORIZATION_CODE .equals (clientRegistration .getAuthorizationGrantType ())) {
210
- String loginAction = "login" ;
211
- uriVariables .put ("action" , loginAction );
212
- }
213
-
214
- return UriComponentsBuilder .fromUriString (clientRegistration .getRedirectUriTemplate ())
215
- .buildAndExpand (uriVariables )
216
- .toUriString ();
217
- }
218
125
}
0 commit comments