77import io .github .patternhelloworld .securityhelper .oauth2 .api .config .security .response .error .dto .EasyPlusErrorMessages ;
88import io .github .patternhelloworld .securityhelper .oauth2 .api .config .security .response .error .exception .EasyPlusOauth2AuthenticationException ;
99import io .github .patternhelloworld .securityhelper .oauth2 .api .config .security .serivce .persistence .authorization .OAuth2AuthorizationServiceImpl ;
10+ import io .github .patternhelloworld .securityhelper .oauth2 .api .config .security .validator .endpoint .authorization .CodeValidationResult ;
11+ import io .github .patternhelloworld .securityhelper .oauth2 .api .config .util .EasyPlusErrorCodeConstants ;
1012import io .github .patternhelloworld .securityhelper .oauth2 .api .config .util .EasyPlusOAuth2EndpointUtils ;
11- import io .github .patternhelloworld .securityhelper .oauth2 .api .config .util .ErrorCodeConstants ;
1213import jakarta .servlet .http .HttpServletRequest ;
1314import lombok .RequiredArgsConstructor ;
1415import org .springframework .http .HttpMethod ;
15- import org .springframework .security .authentication .AnonymousAuthenticationToken ;
1616import org .springframework .security .core .Authentication ;
17- import org .springframework .security .core .authority .AuthorityUtils ;
1817import org .springframework .security .core .context .SecurityContextHolder ;
1918import org .springframework .security .oauth2 .core .ClientAuthenticationMethod ;
2019import org .springframework .security .oauth2 .core .endpoint .OAuth2ParameterNames ;
2120import org .springframework .security .oauth2 .core .oidc .OidcScopes ;
2221import org .springframework .security .oauth2 .server .authorization .OAuth2Authorization ;
2322import org .springframework .security .oauth2 .server .authorization .OAuth2TokenType ;
2423import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2AuthorizationCodeAuthenticationToken ;
24+ import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2AuthorizationCodeRequestAuthenticationToken ;
2525import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2ClientAuthenticationToken ;
2626import org .springframework .security .oauth2 .server .authorization .client .RegisteredClient ;
27- import org .springframework .security .oauth2 .server .authorization .client .RegisteredClientRepository ;
2827import org .springframework .security .web .authentication .AuthenticationConverter ;
2928import org .springframework .security .web .util .matcher .AndRequestMatcher ;
3029import org .springframework .security .web .util .matcher .RequestMatcher ;
30+ import org .springframework .util .Assert ;
3131import org .springframework .util .MultiValueMap ;
3232import org .springframework .util .StringUtils ;
3333
34- import java .util .*;
34+ import java .util .Map ;
35+ import java .util .function .Function ;
3536
3637@ RequiredArgsConstructor
37- public final class AuthorizationCodeAuthorizationRequestConverter implements AuthenticationConverter {
38+ public final class CodeAuthorizationConditionalConverter implements AuthenticationConverter {
39+
40+ private Function <MultiValueMap <String , String >, CodeValidationResult > authenticationValidator ;
3841
39- private final RegisteredClientRepository registeredClientRepository ;
4042 private final EasyPlusAuthorizationConsentRepository easyPlusAuthorizationConsentRepository ;
4143 private final OAuth2AuthorizationServiceImpl oAuth2AuthorizationService ;
4244
4345 private final ISecurityUserExceptionMessageService iSecurityUserExceptionMessageService ;
4446
4547 private final String consentYN ;
4648
47- private static final Authentication ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken ("anonymous" ,
48- "anonymousUser" , AuthorityUtils .createAuthorityList ("ROLE_ANONYMOUS" ));
49-
50- private static final RequestMatcher OIDC_REQUEST_MATCHER = createOidcRequestMatcher ();
51-
5249 /*
5350 * Why is the validation check done here?
5451 * - Because if an OAuth2AuthenticationException is thrown in the CustomizedProvider,
@@ -62,56 +59,19 @@ public Authentication convert(HttpServletRequest request) {
6259
6360 MultiValueMap <String , String > parameters = EasyPlusOAuth2EndpointUtils .getWebParametersContainingEasyPlusHeaders (request );
6461
65- String clientId = parameters .getFirst (OAuth2ParameterNames .CLIENT_ID );
66- if (!StringUtils .hasText (clientId )) {
67- throw new EasyPlusOauth2AuthenticationException (iSecurityUserExceptionMessageService .getUserMessage (DefaultSecurityUserExceptionMessage .AUTHENTICATION_CLIENT_ID_MISSING ));
68- }
69- String redirectUri = parameters .getFirst (OAuth2ParameterNames .REDIRECT_URI );
70- if (!StringUtils .hasText (redirectUri )) {
71- throw new EasyPlusOauth2AuthenticationException (iSecurityUserExceptionMessageService .getUserMessage (DefaultSecurityUserExceptionMessage .AUTHENTICATION_REDIRECT_URI_MISSING ));
72- }
73-
74- Map <String , Object > additionalParameters = new HashMap <>();
62+ CodeValidationResult codeValidationResult = this .authenticationValidator .apply (parameters );
7563
76- parameters .forEach ((key , value ) -> {
77- additionalParameters .put (key , (value .size () == 1 ) ? value .get (0 ) : value .toArray (new String [0 ]));
78- });
79-
80-
81- String state = parameters .getFirst (OAuth2ParameterNames .STATE );
82- if (!StringUtils .hasText (state )) {
83- throw new EasyPlusOauth2AuthenticationException (iSecurityUserExceptionMessageService .getUserMessage (DefaultSecurityUserExceptionMessage .AUTHENTICATION_STATE_MISSING ));
84- }
85-
86- Set <String > requestedScopes = new HashSet <>(parameters .getOrDefault (OAuth2ParameterNames .SCOPE , Collections .emptyList ()));
64+ Map <String , Object > additionalParameters = EasyPlusOAuth2EndpointUtils .convertMultiValueMapToMap (parameters );
8765
8866 Authentication principal = SecurityContextHolder .getContext ().getAuthentication ();
8967 if (principal == null ) {
90- setClientAuthenticationContext (clientId );
68+ setClientAuthenticationContext (codeValidationResult . getRegisteredClient () );
9169 principal = SecurityContextHolder .getContext ().getAuthentication ();
9270 }
9371
94- RegisteredClient registeredClient = ((OAuth2ClientAuthenticationToken ) principal ).getRegisteredClient ();
95-
96- if (registeredClient == null ) {
97- throw new EasyPlusOauth2AuthenticationException (iSecurityUserExceptionMessageService .getUserMessage (DefaultSecurityUserExceptionMessage .AUTHENTICATION_REGISTERED_CLIENT_NOT_FOUND ));
98- }
99-
100- if (!registeredClient .getRedirectUris ().contains (redirectUri )) {
101- throw new EasyPlusOauth2AuthenticationException (iSecurityUserExceptionMessageService .getUserMessage (DefaultSecurityUserExceptionMessage .AUTHENTICATION_INVALID_REDIRECT_URI ));
102- }
103-
104- Set <String > registeredScopes = registeredClient .getScopes (); // Scopes from the RegisteredClient
105-
106- if (!registeredScopes .containsAll (requestedScopes )) {
107- throw new EasyPlusOauth2AuthenticationException (EasyPlusErrorMessages .builder ().userMessage (iSecurityUserExceptionMessageService .getUserMessage (DefaultSecurityUserExceptionMessage .AUTHENTICATION_LOGIN_ERROR ))
108- .message ("Invalid scopes: " + requestedScopes + ". Allowed scopes: " + registeredScopes ).build ());
109- }
110-
11172 String code = parameters .getFirst (OAuth2ParameterNames .CODE );
11273 if (!StringUtils .hasText (code )) {
113- throw new EasyPlusOauth2AuthenticationException (EasyPlusErrorMessages .builder ().userMessage (iSecurityUserExceptionMessageService .getUserMessage (DefaultSecurityUserExceptionMessage .AUTHENTICATION_AUTHORIZATION_CODE_MISSING ))
114- .errorCode (ErrorCodeConstants .REDIRECT_TO_LOGIN ).build ());
74+ return new OAuth2AuthorizationCodeRequestAuthenticationToken (request .getRequestURL ().toString (), codeValidationResult .getClientId (), principal , codeValidationResult .getRedirectUri (), codeValidationResult .getState (), codeValidationResult .getScope (), additionalParameters );
11575 }
11676
11777 // Check Consent
@@ -129,15 +89,15 @@ public Authentication convert(HttpServletRequest request) {
12989 } else {
13090 // This means the user should check authorization consent OK
13191 throw new EasyPlusOauth2AuthenticationException (EasyPlusErrorMessages .builder ().userMessage (iSecurityUserExceptionMessageService .getUserMessage (DefaultSecurityUserExceptionMessage .AUTHENTICATION_AUTHORIZATION_CODE_MISSING ))
132- .errorCode (ErrorCodeConstants .REDIRECT_TO_CONSENT ).build ());
92+ .errorCode (EasyPlusErrorCodeConstants .REDIRECT_TO_CONSENT ).build ());
13393 }
13494 }
13595 }
13696
13797 return new OAuth2AuthorizationCodeAuthenticationToken (
13898 code ,
13999 principal ,
140- redirectUri ,
100+ codeValidationResult . getRedirectUri () ,
141101 additionalParameters
142102 );
143103 }
@@ -153,12 +113,7 @@ private static RequestMatcher createOidcRequestMatcher() {
153113 return new AndRequestMatcher (postMethodMatcher , responseTypeParameterMatcher , openidScopeMatcher );
154114 }
155115
156- public void setClientAuthenticationContext (String clientId ) {
157- RegisteredClient registeredClient = registeredClientRepository .findByClientId (clientId );
158- if (registeredClient == null ) {
159- throw new IllegalArgumentException ("Invalid client ID" );
160- }
161-
116+ public void setClientAuthenticationContext (RegisteredClient registeredClient ) {
162117 OAuth2ClientAuthenticationToken clientAuthenticationToken = new OAuth2ClientAuthenticationToken (
163118 registeredClient ,
164119 ClientAuthenticationMethod .CLIENT_SECRET_BASIC ,
@@ -168,5 +123,9 @@ public void setClientAuthenticationContext(String clientId) {
168123 SecurityContextHolder .getContext ().setAuthentication (clientAuthenticationToken );
169124 }
170125
126+ public void setAuthenticationValidator (Function <MultiValueMap <String , String >, CodeValidationResult > authenticationValidator ) {
127+ Assert .notNull (authenticationValidator , "authenticationValidator cannot be null" );
128+ this .authenticationValidator = authenticationValidator ;
129+ }
171130}
172131
0 commit comments