importorg.springframework.security.authentication.AuthenticationProvider;importorg.springframework.security.core.Authentication;importorg.springframework.security.core.AuthenticationException;importorg.springframework.security.oauth2.core.ClaimAccessor;importorg.springframework.security.oauth2.core.OAuth2AccessToken;importorg.springframework.security.oauth2.core.OAuth2AuthenticationException;importorg.springframework.security.oauth2.core.OAuth2Error;importorg.springframework.security.oauth2.core.OAuth2ErrorCodes;importorg.springframework.security.oauth2.core.OAuth2Token;importorg.springframework.security.oauth2.server.authorization.OAuth2Authorization;importorg.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;importorg.springframework.security.oauth2.server.authorization.OAuth2TokenType;importorg.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;importorg.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;importorg.springframework.security.oauth2.server.authorization.client.RegisteredClient;importorg.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;importorg.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;importorg.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;importorg.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;importorg.springframework.util.Assert;publicclassCustomCodeGrantAuthenticationProviderimplementsAuthenticationProvider{privatefinalOAuth2AuthorizationServiceauthorizationService;privatefinalOAuth2TokenGenerator<?extendsOAuth2Token>tokenGenerator;publicCustomCodeGrantAuthenticationProvider(OAuth2AuthorizationServiceauthorizationService,OAuth2TokenGenerator<?extendsOAuth2Token>tokenGenerator){Assert.notNull(authorizationService,"authorizationService cannot be null");Assert.notNull(tokenGenerator,"tokenGenerator cannot be null");this.authorizationService=authorizationService;this.tokenGenerator=tokenGenerator;}@OverridepublicAuthenticationauthenticate(Authenticationauthentication)throwsAuthenticationException{CustomCodeGrantAuthenticationTokencustomCodeGrantAuthentication=(CustomCodeGrantAuthenticationToken)authentication;// Ensure the client is authenticatedOAuth2ClientAuthenticationTokenclientPrincipal=getAuthenticatedClientElseThrowInvalidClient(customCodeGrantAuthentication);RegisteredClientregisteredClient=clientPrincipal.getRegisteredClient();// Ensure the client is configured to use this authorization grant typeif(!registeredClient.getAuthorizationGrantTypes().contains(customCodeGrantAuthentication.getGrantType())){thrownewOAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);}// TODO Validate the code parameter// Generate the access tokenOAuth2TokenContexttokenContext=DefaultOAuth2TokenContext.builder().registeredClient(registeredClient).principal(clientPrincipal).authorizationServerContext(AuthorizationServerContextHolder.getContext()).tokenType(OAuth2TokenType.ACCESS_TOKEN).authorizationGrantType(customCodeGrantAuthentication.getGrantType()).authorizationGrant(customCodeGrantAuthentication).build();OAuth2TokengeneratedAccessToken=this.tokenGenerator.generate(tokenContext);if(generatedAccessToken==null){OAuth2Errorerror=newOAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,"The token generator failed to generate the access token.",null);thrownewOAuth2AuthenticationException(error);}OAuth2AccessTokenaccessToken=newOAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,generatedAccessToken.getTokenValue(),generatedAccessToken.getIssuedAt(),generatedAccessToken.getExpiresAt(),null);// Initialize the OAuth2AuthorizationOAuth2Authorization.BuilderauthorizationBuilder=OAuth2Authorization.withRegisteredClient(registeredClient).principalName(clientPrincipal.getName()).authorizationGrantType(customCodeGrantAuthentication.getGrantType());if(generatedAccessTokeninstanceofClaimAccessorclaimAccessor){authorizationBuilder.token(accessToken,(metadata)->metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME,claimAccessor.getClaims()));}else{authorizationBuilder.accessToken(accessToken);}OAuth2Authorizationauthorization=authorizationBuilder.build();// Save the OAuth2Authorizationthis.authorizationService.save(authorization);returnnewOAuth2AccessTokenAuthenticationToken(registeredClient,clientPrincipal,accessToken);}@Overridepublicbooleansupports(Class<?>authentication){returnCustomCodeGrantAuthenticationToken.class.isAssignableFrom(authentication);}privatestaticOAuth2ClientAuthenticationTokengetAuthenticatedClientElseThrowInvalidClient(Authenticationauthentication){OAuth2ClientAuthenticationTokenclientPrincipal=null;if(OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())){clientPrincipal=(OAuth2ClientAuthenticationToken)authentication.getPrincipal();}if(clientPrincipal!=null&&clientPrincipal.isAuthenticated()){returnclientPrincipal;}thrownewOAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);}}