Joe Grandja 1 anno fa
parent
commit
7f1cde0117

+ 0 - 156
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/AuthorizationServerRuntimeHintsRegistrar.java

@@ -1,156 +0,0 @@
-/*
- * Copyright 2020-2021 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.security.oauth2.server.authorization;
-
-import org.springframework.aot.hint.*;
-import org.springframework.security.authentication.AbstractAuthenticationToken;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.jackson2.CoreJackson2Module;
-import org.springframework.security.oauth2.core.AbstractOAuth2Token;
-import org.springframework.security.oauth2.core.AuthorizationGrantType;
-import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
-import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
-import org.springframework.security.oauth2.core.oidc.OidcIdToken;
-import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
-import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
-import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
-import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
-import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
-import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
-import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
-import org.springframework.security.web.authentication.WebAuthenticationDetails;
-import org.springframework.security.web.jackson2.WebServletJackson2Module;
-import org.springframework.util.ClassUtils;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * {@link RuntimeHintsRegistrar} that registers {@link RuntimeHints} required for the
- * sample. Statically registered via META-INF/spring/aot.factories.
- *
- * @author Joe Grandja
- * @author Josh Long
- * @since 1.2
- */
-class AuthorizationServerRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
-
-	private final BindingReflectionHintsRegistrar reflectionHintsRegistrar = new BindingReflectionHintsRegistrar();
-
-	@Override
-	public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
-
-		// Collections -> UnmodifiableSet, UnmodifiableList, UnmodifiableMap,
-		// UnmodifiableRandomAccessList, etc.
-		hints.reflection().registerType(Collections.class, MemberCategory.DECLARED_CLASSES);
-
-		// HashSet
-		hints.reflection().registerType(HashSet.class, MemberCategory.DECLARED_FIELDS,
-				MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS);
-
-		// Spring Security and Spring Authorization Server
-		if (ClassUtils.isPresent("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken",
-				ClassUtils.getDefaultClassLoader()))
-			hints.reflection().registerType(
-					TypeReference
-							.of("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken"),
-					builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
-							MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS));
-
-		hints.reflection().registerTypes(Arrays.asList(TypeReference.of(AbstractAuthenticationToken.class),
-				TypeReference.of(WebAuthenticationDetails.class),
-				TypeReference.of(UsernamePasswordAuthenticationToken.class), TypeReference.of(User.class),
-				TypeReference.of(DefaultOidcUser.class), TypeReference.of(DefaultOAuth2User.class),
-				TypeReference.of(OidcUserAuthority.class), TypeReference.of(OAuth2UserAuthority.class),
-				TypeReference.of(SimpleGrantedAuthority.class), TypeReference.of(OidcIdToken.class),
-				TypeReference.of(AbstractOAuth2Token.class), TypeReference.of(OidcUserInfo.class),
-				TypeReference.of(OAuth2AuthorizationRequest.class), TypeReference.of(AuthorizationGrantType.class),
-				TypeReference.of(OAuth2AuthorizationResponseType.class), TypeReference.of(OAuth2TokenFormat.class)),
-				builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
-						MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS));
-
-		// Jackson Modules - Spring Security and Spring Authorization Server
-		hints.reflection().registerTypes(
-				Set.of(CoreJackson2Module.class.getName(), WebServletJackson2Module.class.getName(),
-						OAuth2AuthorizationServerJackson2Module.class.getName()).stream().map(TypeReference::of)
-						.toList(),
-				builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
-						MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS));
-
-		if (ClassUtils.isPresent("org.springframework.security.oauth2.client.jackson2.OAuth2ClientJackson2Module",
-				ClassUtils.getDefaultClassLoader()))
-			hints.reflection().registerType(
-					TypeReference.of("org.springframework.security.oauth2.client.jackson2.OAuth2ClientJackson2Module"),
-					b -> b.withMembers(MemberCategory.DECLARED_FIELDS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
-							MemberCategory.INVOKE_DECLARED_METHODS));
-
-		hints.reflection().registerTypes(
-				Set.of(CoreJackson2Module.class.getName(), WebServletJackson2Module.class.getName(),
-						OAuth2AuthorizationServerJackson2Module.class.getName()).stream().map(TypeReference::of)
-						.toList(),
-				builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
-						MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS));
-
-		// Jackson Mixins - Spring Security and Spring Authorization Server
-		try {
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.jackson2.UnmodifiableSetMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.jackson2.UnmodifiableListMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.jackson2.UnmodifiableMapMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), Class
-					.forName("org.springframework.security.oauth2.server.authorization.jackson2.UnmodifiableMapMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.oauth2.server.authorization.jackson2.HashSetMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.web.jackson2.WebAuthenticationDetailsMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.jackson2.UsernamePasswordAuthenticationTokenMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.jackson2.UserMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), Class
-					.forName("org.springframework.security.oauth2.client.jackson2.OAuth2AuthenticationTokenMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.oauth2.client.jackson2.DefaultOidcUserMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.oauth2.client.jackson2.DefaultOAuth2UserMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.oauth2.client.jackson2.OidcUserAuthorityMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.oauth2.client.jackson2.OAuth2UserAuthorityMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.jackson2.SimpleGrantedAuthorityMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.oauth2.client.jackson2.OidcIdTokenMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
-					Class.forName("org.springframework.security.oauth2.client.jackson2.OidcUserInfoMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), Class.forName(
-					"org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationRequestMixin"));
-			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), Class.forName(
-					"org.springframework.security.oauth2.server.authorization.jackson2.OAuth2TokenFormatMixin"));
-		}
-		catch (ClassNotFoundException ex) {
-			throw new RuntimeException(ex);
-		}
-
-	}
-
-}

+ 29 - 34
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationConsentService.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-2023 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -47,10 +47,10 @@ import org.springframework.util.StringUtils;
  * {@link JdbcOperations} for {@link OAuth2AuthorizationConsent} persistence.
  * {@link JdbcOperations} for {@link OAuth2AuthorizationConsent} persistence.
  *
  *
  * <p>
  * <p>
- * <b>NOTE:</b> This {@code OAuth2AuthorizationConsentService} depends on the table
- * definition described in
- * "classpath:org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql"
- * and therefore MUST be defined in the database schema.
+ * <b>NOTE:</b> This {@code OAuth2AuthorizationConsentService} depends on the table definition
+ * described in
+ * "classpath:org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql" and
+ * therefore MUST be defined in the database schema.
  *
  *
  * @author Ovidiu Popa
  * @author Ovidiu Popa
  * @author Josh Long
  * @author Josh Long
@@ -103,15 +103,13 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
 	private static final String REMOVE_AUTHORIZATION_CONSENT_SQL = "DELETE FROM " + TABLE_NAME + " WHERE " + PK_FILTER;
 	private static final String REMOVE_AUTHORIZATION_CONSENT_SQL = "DELETE FROM " + TABLE_NAME + " WHERE " + PK_FILTER;
 
 
 	private final JdbcOperations jdbcOperations;
 	private final JdbcOperations jdbcOperations;
-
 	private RowMapper<OAuth2AuthorizationConsent> authorizationConsentRowMapper;
 	private RowMapper<OAuth2AuthorizationConsent> authorizationConsentRowMapper;
-
 	private Function<OAuth2AuthorizationConsent, List<SqlParameterValue>> authorizationConsentParametersMapper;
 	private Function<OAuth2AuthorizationConsent, List<SqlParameterValue>> authorizationConsentParametersMapper;
 
 
 	/**
 	/**
-	 * Constructs a {@code JdbcOAuth2AuthorizationConsentService} using the provided
-	 * parameters.
-	 * @param jdbcOperations the JDBC operations
+	 * Constructs a {@code JdbcOAuth2AuthorizationConsentService} using the provided parameters.
+	 *
+	 * @param jdbcOperations             the JDBC operations
 	 * @param registeredClientRepository the registered client repository
 	 * @param registeredClientRepository the registered client repository
 	 */
 	 */
 	public JdbcOAuth2AuthorizationConsentService(JdbcOperations jdbcOperations,
 	public JdbcOAuth2AuthorizationConsentService(JdbcOperations jdbcOperations,
@@ -126,12 +124,11 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
 	@Override
 	@Override
 	public void save(OAuth2AuthorizationConsent authorizationConsent) {
 	public void save(OAuth2AuthorizationConsent authorizationConsent) {
 		Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
 		Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
-		OAuth2AuthorizationConsent existingAuthorizationConsent = findById(authorizationConsent.getRegisteredClientId(),
-				authorizationConsent.getPrincipalName());
+		OAuth2AuthorizationConsent existingAuthorizationConsent = findById(
+				authorizationConsent.getRegisteredClientId(), authorizationConsent.getPrincipalName());
 		if (existingAuthorizationConsent == null) {
 		if (existingAuthorizationConsent == null) {
 			insertAuthorizationConsent(authorizationConsent);
 			insertAuthorizationConsent(authorizationConsent);
-		}
-		else {
+		} else {
 			updateAuthorizationConsent(authorizationConsent);
 			updateAuthorizationConsent(authorizationConsent);
 		}
 		}
 	}
 	}
@@ -157,7 +154,8 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
 		Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
 		Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
 		SqlParameterValue[] parameters = new SqlParameterValue[] {
 		SqlParameterValue[] parameters = new SqlParameterValue[] {
 				new SqlParameterValue(Types.VARCHAR, authorizationConsent.getRegisteredClientId()),
 				new SqlParameterValue(Types.VARCHAR, authorizationConsent.getRegisteredClientId()),
-				new SqlParameterValue(Types.VARCHAR, authorizationConsent.getPrincipalName()) };
+				new SqlParameterValue(Types.VARCHAR, authorizationConsent.getPrincipalName())
+		};
 		PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters);
 		PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters);
 		this.jdbcOperations.update(REMOVE_AUTHORIZATION_CONSENT_SQL, pss);
 		this.jdbcOperations.update(REMOVE_AUTHORIZATION_CONSENT_SQL, pss);
 	}
 	}
@@ -169,7 +167,7 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
 		Assert.hasText(principalName, "principalName cannot be empty");
 		Assert.hasText(principalName, "principalName cannot be empty");
 		SqlParameterValue[] parameters = new SqlParameterValue[] {
 		SqlParameterValue[] parameters = new SqlParameterValue[] {
 				new SqlParameterValue(Types.VARCHAR, registeredClientId),
 				new SqlParameterValue(Types.VARCHAR, registeredClientId),
-				new SqlParameterValue(Types.VARCHAR, principalName) };
+				new SqlParameterValue(Types.VARCHAR, principalName)};
 		PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters);
 		PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters);
 		List<OAuth2AuthorizationConsent> result = this.jdbcOperations.query(LOAD_AUTHORIZATION_CONSENT_SQL, pss,
 		List<OAuth2AuthorizationConsent> result = this.jdbcOperations.query(LOAD_AUTHORIZATION_CONSENT_SQL, pss,
 				this.authorizationConsentRowMapper);
 				this.authorizationConsentRowMapper);
@@ -180,21 +178,22 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
 	 * Sets the {@link RowMapper} used for mapping the current row in
 	 * Sets the {@link RowMapper} used for mapping the current row in
 	 * {@code java.sql.ResultSet} to {@link OAuth2AuthorizationConsent}. The default is
 	 * {@code java.sql.ResultSet} to {@link OAuth2AuthorizationConsent}. The default is
 	 * {@link OAuth2AuthorizationConsentRowMapper}.
 	 * {@link OAuth2AuthorizationConsentRowMapper}.
-	 * @param authorizationConsentRowMapper the {@link RowMapper} used for mapping the
-	 * current row in {@code ResultSet} to {@link OAuth2AuthorizationConsent}
+	 *
+	 * @param authorizationConsentRowMapper the {@link RowMapper} used for mapping the current
+	 *                                      row in {@code ResultSet} to {@link OAuth2AuthorizationConsent}
 	 */
 	 */
-	public final void setAuthorizationConsentRowMapper(
-			RowMapper<OAuth2AuthorizationConsent> authorizationConsentRowMapper) {
+	public final void setAuthorizationConsentRowMapper(RowMapper<OAuth2AuthorizationConsent> authorizationConsentRowMapper) {
 		Assert.notNull(authorizationConsentRowMapper, "authorizationConsentRowMapper cannot be null");
 		Assert.notNull(authorizationConsentRowMapper, "authorizationConsentRowMapper cannot be null");
 		this.authorizationConsentRowMapper = authorizationConsentRowMapper;
 		this.authorizationConsentRowMapper = authorizationConsentRowMapper;
 	}
 	}
 
 
 	/**
 	/**
-	 * Sets the {@code Function} used for mapping {@link OAuth2AuthorizationConsent} to a
-	 * {@code List} of {@link SqlParameterValue}. The default is
+	 * Sets the {@code Function} used for mapping {@link OAuth2AuthorizationConsent} to
+	 * a {@code List} of {@link SqlParameterValue}. The default is
 	 * {@link OAuth2AuthorizationConsentParametersMapper}.
 	 * {@link OAuth2AuthorizationConsentParametersMapper}.
+	 *
 	 * @param authorizationConsentParametersMapper the {@code Function} used for mapping
 	 * @param authorizationConsentParametersMapper the {@code Function} used for mapping
-	 * {@link OAuth2AuthorizationConsent} to a {@code List} of {@link SqlParameterValue}
+	 *                                             {@link OAuth2AuthorizationConsent} to a {@code List} of {@link SqlParameterValue}
 	 */
 	 */
 	public final void setAuthorizationConsentParametersMapper(
 	public final void setAuthorizationConsentParametersMapper(
 			Function<OAuth2AuthorizationConsent, List<SqlParameterValue>> authorizationConsentParametersMapper) {
 			Function<OAuth2AuthorizationConsent, List<SqlParameterValue>> authorizationConsentParametersMapper) {
@@ -215,11 +214,10 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
 	}
 	}
 
 
 	/**
 	/**
-	 * The default {@link RowMapper} that maps the current row in {@code ResultSet} to
-	 * {@link OAuth2AuthorizationConsent}.
+	 * The default {@link RowMapper} that maps the current row in
+	 * {@code ResultSet} to {@link OAuth2AuthorizationConsent}.
 	 */
 	 */
 	public static class OAuth2AuthorizationConsentRowMapper implements RowMapper<OAuth2AuthorizationConsent> {
 	public static class OAuth2AuthorizationConsentRowMapper implements RowMapper<OAuth2AuthorizationConsent> {
-
 		private final RegisteredClientRepository registeredClientRepository;
 		private final RegisteredClientRepository registeredClientRepository;
 
 
 		public OAuth2AuthorizationConsentRowMapper(RegisteredClientRepository registeredClientRepository) {
 		public OAuth2AuthorizationConsentRowMapper(RegisteredClientRepository registeredClientRepository) {
@@ -232,14 +230,13 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
 			String registeredClientId = rs.getString("registered_client_id");
 			String registeredClientId = rs.getString("registered_client_id");
 			RegisteredClient registeredClient = this.registeredClientRepository.findById(registeredClientId);
 			RegisteredClient registeredClient = this.registeredClientRepository.findById(registeredClientId);
 			if (registeredClient == null) {
 			if (registeredClient == null) {
-				throw new DataRetrievalFailureException("The RegisteredClient with id '" + registeredClientId
-						+ "' was not found in the RegisteredClientRepository.");
+				throw new DataRetrievalFailureException(
+						"The RegisteredClient with id '" + registeredClientId + "' was not found in the RegisteredClientRepository.");
 			}
 			}
 
 
 			String principalName = rs.getString("principal_name");
 			String principalName = rs.getString("principal_name");
 
 
-			OAuth2AuthorizationConsent.Builder builder = OAuth2AuthorizationConsent.withId(registeredClientId,
-					principalName);
+			OAuth2AuthorizationConsent.Builder builder = OAuth2AuthorizationConsent.withId(registeredClientId, principalName);
 			String authorizationConsentAuthorities = rs.getString("authorities");
 			String authorizationConsentAuthorities = rs.getString("authorities");
 			if (authorizationConsentAuthorities != null) {
 			if (authorizationConsentAuthorities != null) {
 				for (String authority : StringUtils.commaDelimitedListToSet(authorizationConsentAuthorities)) {
 				for (String authority : StringUtils.commaDelimitedListToSet(authorizationConsentAuthorities)) {
@@ -259,8 +256,7 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
 	 * The default {@code Function} that maps {@link OAuth2AuthorizationConsent} to a
 	 * The default {@code Function} that maps {@link OAuth2AuthorizationConsent} to a
 	 * {@code List} of {@link SqlParameterValue}.
 	 * {@code List} of {@link SqlParameterValue}.
 	 */
 	 */
-	public static class OAuth2AuthorizationConsentParametersMapper
-			implements Function<OAuth2AuthorizationConsent, List<SqlParameterValue>> {
+	public static class OAuth2AuthorizationConsentParametersMapper implements Function<OAuth2AuthorizationConsent, List<SqlParameterValue>> {
 
 
 		@Override
 		@Override
 		public List<SqlParameterValue> apply(OAuth2AuthorizationConsent authorizationConsent) {
 		public List<SqlParameterValue> apply(OAuth2AuthorizationConsent authorizationConsent) {
@@ -272,8 +268,7 @@ public class JdbcOAuth2AuthorizationConsentService implements OAuth2Authorizatio
 			for (GrantedAuthority authority : authorizationConsent.getAuthorities()) {
 			for (GrantedAuthority authority : authorizationConsent.getAuthorities()) {
 				authorities.add(authority.getAuthority());
 				authorities.add(authority.getAuthority());
 			}
 			}
-			parameters.add(
-					new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToDelimitedString(authorities, ",")));
+			parameters.add(new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToDelimitedString(authorities, ",")));
 			return parameters;
 			return parameters;
 		}
 		}
 
 

+ 73 - 105
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationService.java

@@ -74,8 +74,8 @@ import org.springframework.util.StringUtils;
  * <p>
  * <p>
  * <b>NOTE:</b> This {@code OAuth2AuthorizationService} depends on the table definition
  * <b>NOTE:</b> This {@code OAuth2AuthorizationService} depends on the table definition
  * described in
  * described in
- * "classpath:org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql"
- * and therefore MUST be defined in the database schema.
+ * "classpath:org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql" and
+ * therefore MUST be defined in the database schema.
  *
  *
  * @author Ovidiu Popa
  * @author Ovidiu Popa
  * @author Joe Grandja
  * @author Joe Grandja
@@ -86,10 +86,10 @@ import org.springframework.util.StringUtils;
  * @see JdbcOperations
  * @see JdbcOperations
  * @see RowMapper
  * @see RowMapper
  */
  */
-@ImportRuntimeHints(JdbcOAuth2AuthorizationService.JdbcOAuth2AuthorizationServiceServiceRuntimeHintsRegistrar.class)
+@ImportRuntimeHints(JdbcOAuth2AuthorizationService.JdbcOAuth2AuthorizationServiceRuntimeHintsRegistrar.class)
 public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationService {
 public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationService {
 
 
-	static class JdbcOAuth2AuthorizationServiceServiceRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
+	static class JdbcOAuth2AuthorizationServiceRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
 
 
 		@Override
 		@Override
 		public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
 		public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
@@ -138,23 +138,16 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	private static final String TABLE_NAME = "oauth2_authorization";
 	private static final String TABLE_NAME = "oauth2_authorization";
 
 
 	private static final String PK_FILTER = "id = ?";
 	private static final String PK_FILTER = "id = ?";
-
 	private static final String UNKNOWN_TOKEN_TYPE_FILTER = "state = ? OR authorization_code_value = ? OR "
 	private static final String UNKNOWN_TOKEN_TYPE_FILTER = "state = ? OR authorization_code_value = ? OR "
 			+ "access_token_value = ? OR oidc_id_token_value = ? OR refresh_token_value = ? OR user_code_value = ? OR "
 			+ "access_token_value = ? OR oidc_id_token_value = ? OR refresh_token_value = ? OR user_code_value = ? OR "
 			+ "device_code_value = ?";
 			+ "device_code_value = ?";
 
 
 	private static final String STATE_FILTER = "state = ?";
 	private static final String STATE_FILTER = "state = ?";
-
 	private static final String AUTHORIZATION_CODE_FILTER = "authorization_code_value = ?";
 	private static final String AUTHORIZATION_CODE_FILTER = "authorization_code_value = ?";
-
 	private static final String ACCESS_TOKEN_FILTER = "access_token_value = ?";
 	private static final String ACCESS_TOKEN_FILTER = "access_token_value = ?";
-
 	private static final String ID_TOKEN_FILTER = "oidc_id_token_value = ?";
 	private static final String ID_TOKEN_FILTER = "oidc_id_token_value = ?";
-
 	private static final String REFRESH_TOKEN_FILTER = "refresh_token_value = ?";
 	private static final String REFRESH_TOKEN_FILTER = "refresh_token_value = ?";
-
 	private static final String USER_CODE_FILTER = "user_code_value = ?";
 	private static final String USER_CODE_FILTER = "user_code_value = ?";
-
 	private static final String DEVICE_CODE_FILTER = "device_code_value = ?";
 	private static final String DEVICE_CODE_FILTER = "device_code_value = ?";
 
 
 	// @formatter:off
 	// @formatter:off
@@ -185,16 +178,14 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	private static Map<String, ColumnMetadata> columnMetadataMap;
 	private static Map<String, ColumnMetadata> columnMetadataMap;
 
 
 	private final JdbcOperations jdbcOperations;
 	private final JdbcOperations jdbcOperations;
-
 	private final LobHandler lobHandler;
 	private final LobHandler lobHandler;
-
 	private RowMapper<OAuth2Authorization> authorizationRowMapper;
 	private RowMapper<OAuth2Authorization> authorizationRowMapper;
-
 	private Function<OAuth2Authorization, List<SqlParameterValue>> authorizationParametersMapper;
 	private Function<OAuth2Authorization, List<SqlParameterValue>> authorizationParametersMapper;
 
 
 	/**
 	/**
 	 * Constructs a {@code JdbcOAuth2AuthorizationService} using the provided parameters.
 	 * Constructs a {@code JdbcOAuth2AuthorizationService} using the provided parameters.
-	 * @param jdbcOperations the JDBC operations
+	 *
+	 * @param jdbcOperations             the JDBC operations
 	 * @param registeredClientRepository the registered client repository
 	 * @param registeredClientRepository the registered client repository
 	 */
 	 */
 	public JdbcOAuth2AuthorizationService(JdbcOperations jdbcOperations,
 	public JdbcOAuth2AuthorizationService(JdbcOperations jdbcOperations,
@@ -204,9 +195,10 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 
 
 	/**
 	/**
 	 * Constructs a {@code JdbcOAuth2AuthorizationService} using the provided parameters.
 	 * Constructs a {@code JdbcOAuth2AuthorizationService} using the provided parameters.
-	 * @param jdbcOperations the JDBC operations
+	 *
+	 * @param jdbcOperations             the JDBC operations
 	 * @param registeredClientRepository the registered client repository
 	 * @param registeredClientRepository the registered client repository
-	 * @param lobHandler the handler for large binary fields and large text fields
+	 * @param lobHandler                 the handler for large binary fields and large text fields
 	 */
 	 */
 	public JdbcOAuth2AuthorizationService(JdbcOperations jdbcOperations,
 	public JdbcOAuth2AuthorizationService(JdbcOperations jdbcOperations,
 			RegisteredClientRepository registeredClientRepository, LobHandler lobHandler) {
 			RegisteredClientRepository registeredClientRepository, LobHandler lobHandler) {
@@ -215,8 +207,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 		Assert.notNull(lobHandler, "lobHandler cannot be null");
 		Assert.notNull(lobHandler, "lobHandler cannot be null");
 		this.jdbcOperations = jdbcOperations;
 		this.jdbcOperations = jdbcOperations;
 		this.lobHandler = lobHandler;
 		this.lobHandler = lobHandler;
-		OAuth2AuthorizationRowMapper authorizationRowMapper = new OAuth2AuthorizationRowMapper(
-				registeredClientRepository);
+		OAuth2AuthorizationRowMapper authorizationRowMapper = new OAuth2AuthorizationRowMapper(registeredClientRepository);
 		authorizationRowMapper.setLobHandler(lobHandler);
 		authorizationRowMapper.setLobHandler(lobHandler);
 		this.authorizationRowMapper = authorizationRowMapper;
 		this.authorizationRowMapper = authorizationRowMapper;
 		this.authorizationParametersMapper = new OAuth2AuthorizationParametersMapper();
 		this.authorizationParametersMapper = new OAuth2AuthorizationParametersMapper();
@@ -229,8 +220,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 		OAuth2Authorization existingAuthorization = findById(authorization.getId());
 		OAuth2Authorization existingAuthorization = findById(authorization.getId());
 		if (existingAuthorization == null) {
 		if (existingAuthorization == null) {
 			insertAuthorization(authorization);
 			insertAuthorization(authorization);
-		}
-		else {
+		} else {
 			updateAuthorization(authorization);
 			updateAuthorization(authorization);
 		}
 		}
 	}
 	}
@@ -259,7 +249,8 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	public void remove(OAuth2Authorization authorization) {
 	public void remove(OAuth2Authorization authorization) {
 		Assert.notNull(authorization, "authorization cannot be null");
 		Assert.notNull(authorization, "authorization cannot be null");
 		SqlParameterValue[] parameters = new SqlParameterValue[] {
 		SqlParameterValue[] parameters = new SqlParameterValue[] {
-				new SqlParameterValue(Types.VARCHAR, authorization.getId()) };
+				new SqlParameterValue(Types.VARCHAR, authorization.getId())
+		};
 		PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters);
 		PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters);
 		this.jdbcOperations.update(REMOVE_AUTHORIZATION_SQL, pss);
 		this.jdbcOperations.update(REMOVE_AUTHORIZATION_SQL, pss);
 	}
 	}
@@ -287,32 +278,25 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 			parameters.add(mapToSqlParameter("user_code_value", token));
 			parameters.add(mapToSqlParameter("user_code_value", token));
 			parameters.add(mapToSqlParameter("device_code_value", token));
 			parameters.add(mapToSqlParameter("device_code_value", token));
 			return findBy(UNKNOWN_TOKEN_TYPE_FILTER, parameters);
 			return findBy(UNKNOWN_TOKEN_TYPE_FILTER, parameters);
-		}
-		else if (OAuth2ParameterNames.STATE.equals(tokenType.getValue())) {
+		} else if (OAuth2ParameterNames.STATE.equals(tokenType.getValue())) {
 			parameters.add(new SqlParameterValue(Types.VARCHAR, token));
 			parameters.add(new SqlParameterValue(Types.VARCHAR, token));
 			return findBy(STATE_FILTER, parameters);
 			return findBy(STATE_FILTER, parameters);
-		}
-		else if (OAuth2ParameterNames.CODE.equals(tokenType.getValue())) {
+		} else if (OAuth2ParameterNames.CODE.equals(tokenType.getValue())) {
 			parameters.add(mapToSqlParameter("authorization_code_value", token));
 			parameters.add(mapToSqlParameter("authorization_code_value", token));
 			return findBy(AUTHORIZATION_CODE_FILTER, parameters);
 			return findBy(AUTHORIZATION_CODE_FILTER, parameters);
-		}
-		else if (OAuth2TokenType.ACCESS_TOKEN.equals(tokenType)) {
+		} else if (OAuth2TokenType.ACCESS_TOKEN.equals(tokenType)) {
 			parameters.add(mapToSqlParameter("access_token_value", token));
 			parameters.add(mapToSqlParameter("access_token_value", token));
 			return findBy(ACCESS_TOKEN_FILTER, parameters);
 			return findBy(ACCESS_TOKEN_FILTER, parameters);
-		}
-		else if (OidcParameterNames.ID_TOKEN.equals(tokenType.getValue())) {
+		} else if (OidcParameterNames.ID_TOKEN.equals(tokenType.getValue())) {
 			parameters.add(mapToSqlParameter("oidc_id_token_value", token));
 			parameters.add(mapToSqlParameter("oidc_id_token_value", token));
 			return findBy(ID_TOKEN_FILTER, parameters);
 			return findBy(ID_TOKEN_FILTER, parameters);
-		}
-		else if (OAuth2TokenType.REFRESH_TOKEN.equals(tokenType)) {
+		} else if (OAuth2TokenType.REFRESH_TOKEN.equals(tokenType)) {
 			parameters.add(mapToSqlParameter("refresh_token_value", token));
 			parameters.add(mapToSqlParameter("refresh_token_value", token));
 			return findBy(REFRESH_TOKEN_FILTER, parameters);
 			return findBy(REFRESH_TOKEN_FILTER, parameters);
-		}
-		else if (OAuth2ParameterNames.USER_CODE.equals(tokenType.getValue())) {
+		} else if (OAuth2ParameterNames.USER_CODE.equals(tokenType.getValue())) {
 			parameters.add(mapToSqlParameter("user_code_value", token));
 			parameters.add(mapToSqlParameter("user_code_value", token));
 			return findBy(USER_CODE_FILTER, parameters);
 			return findBy(USER_CODE_FILTER, parameters);
-		}
-		else if (OAuth2ParameterNames.DEVICE_CODE.equals(tokenType.getValue())) {
+		} else if (OAuth2ParameterNames.DEVICE_CODE.equals(tokenType.getValue())) {
 			parameters.add(mapToSqlParameter("device_code_value", token));
 			parameters.add(mapToSqlParameter("device_code_value", token));
 			return findBy(DEVICE_CODE_FILTER, parameters);
 			return findBy(DEVICE_CODE_FILTER, parameters);
 		}
 		}
@@ -323,8 +307,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 		try (LobCreator lobCreator = getLobHandler().getLobCreator()) {
 		try (LobCreator lobCreator = getLobHandler().getLobCreator()) {
 			PreparedStatementSetter pss = new LobCreatorArgumentPreparedStatementSetter(lobCreator,
 			PreparedStatementSetter pss = new LobCreatorArgumentPreparedStatementSetter(lobCreator,
 					parameters.toArray());
 					parameters.toArray());
-			List<OAuth2Authorization> result = getJdbcOperations().query(LOAD_AUTHORIZATION_SQL + filter, pss,
-					getAuthorizationRowMapper());
+			List<OAuth2Authorization> result = getJdbcOperations().query(LOAD_AUTHORIZATION_SQL + filter, pss, getAuthorizationRowMapper());
 			return !result.isEmpty() ? result.get(0) : null;
 			return !result.isEmpty() ? result.get(0) : null;
 		}
 		}
 	}
 	}
@@ -333,8 +316,9 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	 * Sets the {@link RowMapper} used for mapping the current row in
 	 * Sets the {@link RowMapper} used for mapping the current row in
 	 * {@code java.sql.ResultSet} to {@link OAuth2Authorization}. The default is
 	 * {@code java.sql.ResultSet} to {@link OAuth2Authorization}. The default is
 	 * {@link OAuth2AuthorizationRowMapper}.
 	 * {@link OAuth2AuthorizationRowMapper}.
+	 *
 	 * @param authorizationRowMapper the {@link RowMapper} used for mapping the current
 	 * @param authorizationRowMapper the {@link RowMapper} used for mapping the current
-	 * row in {@code ResultSet} to {@link OAuth2Authorization}
+	 *                               row in {@code ResultSet} to {@link OAuth2Authorization}
 	 */
 	 */
 	public final void setAuthorizationRowMapper(RowMapper<OAuth2Authorization> authorizationRowMapper) {
 	public final void setAuthorizationRowMapper(RowMapper<OAuth2Authorization> authorizationRowMapper) {
 		Assert.notNull(authorizationRowMapper, "authorizationRowMapper cannot be null");
 		Assert.notNull(authorizationRowMapper, "authorizationRowMapper cannot be null");
@@ -342,11 +326,12 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	}
 	}
 
 
 	/**
 	/**
-	 * Sets the {@code Function} used for mapping {@link OAuth2Authorization} to a
-	 * {@code List} of {@link SqlParameterValue}. The default is
+	 * Sets the {@code Function} used for mapping {@link OAuth2Authorization} to
+	 * a {@code List} of {@link SqlParameterValue}. The default is
 	 * {@link OAuth2AuthorizationParametersMapper}.
 	 * {@link OAuth2AuthorizationParametersMapper}.
+	 *
 	 * @param authorizationParametersMapper the {@code Function} used for mapping
 	 * @param authorizationParametersMapper the {@code Function} used for mapping
-	 * {@link OAuth2Authorization} to a {@code List} of {@link SqlParameterValue}
+	 *                                      {@link OAuth2Authorization} to a {@code List} of {@link SqlParameterValue}
 	 */
 	 */
 	public final void setAuthorizationParametersMapper(
 	public final void setAuthorizationParametersMapper(
 			Function<OAuth2Authorization, List<SqlParameterValue>> authorizationParametersMapper) {
 			Function<OAuth2Authorization, List<SqlParameterValue>> authorizationParametersMapper) {
@@ -375,11 +360,8 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	 * {@code java.sql.ResultSet} to {@link OAuth2Authorization}.
 	 * {@code java.sql.ResultSet} to {@link OAuth2Authorization}.
 	 */
 	 */
 	public static class OAuth2AuthorizationRowMapper implements RowMapper<OAuth2Authorization> {
 	public static class OAuth2AuthorizationRowMapper implements RowMapper<OAuth2Authorization> {
-
 		private final RegisteredClientRepository registeredClientRepository;
 		private final RegisteredClientRepository registeredClientRepository;
-
 		private LobHandler lobHandler = new DefaultLobHandler();
 		private LobHandler lobHandler = new DefaultLobHandler();
-
 		private ObjectMapper objectMapper = new ObjectMapper();
 		private ObjectMapper objectMapper = new ObjectMapper();
 
 
 		public OAuth2AuthorizationRowMapper(RegisteredClientRepository registeredClientRepository) {
 		public OAuth2AuthorizationRowMapper(RegisteredClientRepository registeredClientRepository) {
@@ -398,8 +380,8 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 			String registeredClientId = rs.getString("registered_client_id");
 			String registeredClientId = rs.getString("registered_client_id");
 			RegisteredClient registeredClient = this.registeredClientRepository.findById(registeredClientId);
 			RegisteredClient registeredClient = this.registeredClientRepository.findById(registeredClientId);
 			if (registeredClient == null) {
 			if (registeredClient == null) {
-				throw new DataRetrievalFailureException("The RegisteredClient with id '" + registeredClientId
-						+ "' was not found in the RegisteredClientRepository.");
+				throw new DataRetrievalFailureException(
+						"The RegisteredClient with id '" + registeredClientId + "' was not found in the RegisteredClientRepository.");
 			}
 			}
 
 
 			OAuth2Authorization.Builder builder = OAuth2Authorization.withRegisteredClient(registeredClient);
 			OAuth2Authorization.Builder builder = OAuth2Authorization.withRegisteredClient(registeredClient);
@@ -413,9 +395,11 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 			}
 			}
 			Map<String, Object> attributes = parseMap(getLobValue(rs, "attributes"));
 			Map<String, Object> attributes = parseMap(getLobValue(rs, "attributes"));
 
 
-			builder.id(id).principalName(principalName)
+			builder.id(id)
+					.principalName(principalName)
 					.authorizationGrantType(new AuthorizationGrantType(authorizationGrantType))
 					.authorizationGrantType(new AuthorizationGrantType(authorizationGrantType))
-					.authorizedScopes(authorizedScopes).attributes((attrs) -> attrs.putAll(attributes));
+					.authorizedScopes(authorizedScopes)
+					.attributes((attrs) -> attrs.putAll(attributes));
 
 
 			String state = rs.getString("state");
 			String state = rs.getString("state");
 			if (StringUtils.hasText(state)) {
 			if (StringUtils.hasText(state)) {
@@ -429,11 +413,10 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 			if (StringUtils.hasText(authorizationCodeValue)) {
 			if (StringUtils.hasText(authorizationCodeValue)) {
 				tokenIssuedAt = rs.getTimestamp("authorization_code_issued_at").toInstant();
 				tokenIssuedAt = rs.getTimestamp("authorization_code_issued_at").toInstant();
 				tokenExpiresAt = rs.getTimestamp("authorization_code_expires_at").toInstant();
 				tokenExpiresAt = rs.getTimestamp("authorization_code_expires_at").toInstant();
-				Map<String, Object> authorizationCodeMetadata = parseMap(
-						getLobValue(rs, "authorization_code_metadata"));
+				Map<String, Object> authorizationCodeMetadata = parseMap(getLobValue(rs, "authorization_code_metadata"));
 
 
-				OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode(authorizationCodeValue,
-						tokenIssuedAt, tokenExpiresAt);
+				OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode(
+						authorizationCodeValue, tokenIssuedAt, tokenExpiresAt);
 				builder.token(authorizationCode, (metadata) -> metadata.putAll(authorizationCodeMetadata));
 				builder.token(authorizationCode, (metadata) -> metadata.putAll(authorizationCodeMetadata));
 			}
 			}
 
 
@@ -452,8 +435,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 				if (accessTokenScopes != null) {
 				if (accessTokenScopes != null) {
 					scopes = StringUtils.commaDelimitedListToSet(accessTokenScopes);
 					scopes = StringUtils.commaDelimitedListToSet(accessTokenScopes);
 				}
 				}
-				OAuth2AccessToken accessToken = new OAuth2AccessToken(tokenType, accessTokenValue, tokenIssuedAt,
-						tokenExpiresAt, scopes);
+				OAuth2AccessToken accessToken = new OAuth2AccessToken(tokenType, accessTokenValue, tokenIssuedAt, tokenExpiresAt, scopes);
 				builder.token(accessToken, (metadata) -> metadata.putAll(accessTokenMetadata));
 				builder.token(accessToken, (metadata) -> metadata.putAll(accessTokenMetadata));
 			}
 			}
 
 
@@ -463,8 +445,8 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 				tokenExpiresAt = rs.getTimestamp("oidc_id_token_expires_at").toInstant();
 				tokenExpiresAt = rs.getTimestamp("oidc_id_token_expires_at").toInstant();
 				Map<String, Object> oidcTokenMetadata = parseMap(getLobValue(rs, "oidc_id_token_metadata"));
 				Map<String, Object> oidcTokenMetadata = parseMap(getLobValue(rs, "oidc_id_token_metadata"));
 
 
-				OidcIdToken oidcToken = new OidcIdToken(oidcIdTokenValue, tokenIssuedAt, tokenExpiresAt,
-						(Map<String, Object>) oidcTokenMetadata.get(OAuth2Authorization.Token.CLAIMS_METADATA_NAME));
+				OidcIdToken oidcToken = new OidcIdToken(
+						oidcIdTokenValue, tokenIssuedAt, tokenExpiresAt, (Map<String, Object>) oidcTokenMetadata.get(OAuth2Authorization.Token.CLAIMS_METADATA_NAME));
 				builder.token(oidcToken, (metadata) -> metadata.putAll(oidcTokenMetadata));
 				builder.token(oidcToken, (metadata) -> metadata.putAll(oidcTokenMetadata));
 			}
 			}
 
 
@@ -478,8 +460,8 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 				}
 				}
 				Map<String, Object> refreshTokenMetadata = parseMap(getLobValue(rs, "refresh_token_metadata"));
 				Map<String, Object> refreshTokenMetadata = parseMap(getLobValue(rs, "refresh_token_metadata"));
 
 
-				OAuth2RefreshToken refreshToken = new OAuth2RefreshToken(refreshTokenValue, tokenIssuedAt,
-						tokenExpiresAt);
+				OAuth2RefreshToken refreshToken = new OAuth2RefreshToken(
+						refreshTokenValue, tokenIssuedAt, tokenExpiresAt);
 				builder.token(refreshToken, (metadata) -> metadata.putAll(refreshTokenMetadata));
 				builder.token(refreshToken, (metadata) -> metadata.putAll(refreshTokenMetadata));
 			}
 			}
 
 
@@ -514,11 +496,9 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 				if (columnValueBytes != null) {
 				if (columnValueBytes != null) {
 					columnValue = new String(columnValueBytes, StandardCharsets.UTF_8);
 					columnValue = new String(columnValueBytes, StandardCharsets.UTF_8);
 				}
 				}
-			}
-			else if (Types.CLOB == columnMetadata.getDataType()) {
+			} else if (Types.CLOB == columnMetadata.getDataType()) {
 				columnValue = this.lobHandler.getClobAsString(rs, columnName);
 				columnValue = this.lobHandler.getClobAsString(rs, columnName);
-			}
-			else {
+			} else {
 				columnValue = rs.getString(columnName);
 				columnValue = rs.getString(columnName);
 			}
 			}
 			return columnValue;
 			return columnValue;
@@ -548,10 +528,8 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 
 
 		private Map<String, Object> parseMap(String data) {
 		private Map<String, Object> parseMap(String data) {
 			try {
 			try {
-				return this.objectMapper.readValue(data, new TypeReference<Map<String, Object>>() {
-				});
-			}
-			catch (Exception ex) {
+				return this.objectMapper.readValue(data, new TypeReference<Map<String, Object>>() {});
+			} catch (Exception ex) {
 				throw new IllegalArgumentException(ex.getMessage(), ex);
 				throw new IllegalArgumentException(ex.getMessage(), ex);
 			}
 			}
 		}
 		}
@@ -562,9 +540,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	 * The default {@code Function} that maps {@link OAuth2Authorization} to a
 	 * The default {@code Function} that maps {@link OAuth2Authorization} to a
 	 * {@code List} of {@link SqlParameterValue}.
 	 * {@code List} of {@link SqlParameterValue}.
 	 */
 	 */
-	public static class OAuth2AuthorizationParametersMapper
-			implements Function<OAuth2Authorization, List<SqlParameterValue>> {
-
+	public static class OAuth2AuthorizationParametersMapper implements Function<OAuth2Authorization, List<SqlParameterValue>> {
 		private ObjectMapper objectMapper = new ObjectMapper();
 		private ObjectMapper objectMapper = new ObjectMapper();
 
 
 		public OAuth2AuthorizationParametersMapper() {
 		public OAuth2AuthorizationParametersMapper() {
@@ -598,46 +574,46 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 			}
 			}
 			parameters.add(new SqlParameterValue(Types.VARCHAR, state));
 			parameters.add(new SqlParameterValue(Types.VARCHAR, state));
 
 
-			OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
-					.getToken(OAuth2AuthorizationCode.class);
-			List<SqlParameterValue> authorizationCodeSqlParameters = toSqlParameterList("authorization_code_value",
-					"authorization_code_metadata", authorizationCode);
+			OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode =
+					authorization.getToken(OAuth2AuthorizationCode.class);
+			List<SqlParameterValue> authorizationCodeSqlParameters = toSqlParameterList(
+					"authorization_code_value", "authorization_code_metadata", authorizationCode);
 			parameters.addAll(authorizationCodeSqlParameters);
 			parameters.addAll(authorizationCodeSqlParameters);
 
 
-			OAuth2Authorization.Token<OAuth2AccessToken> accessToken = authorization.getToken(OAuth2AccessToken.class);
-			List<SqlParameterValue> accessTokenSqlParameters = toSqlParameterList("access_token_value",
-					"access_token_metadata", accessToken);
+			OAuth2Authorization.Token<OAuth2AccessToken> accessToken =
+					authorization.getToken(OAuth2AccessToken.class);
+			List<SqlParameterValue> accessTokenSqlParameters = toSqlParameterList(
+					"access_token_value", "access_token_metadata", accessToken);
 			parameters.addAll(accessTokenSqlParameters);
 			parameters.addAll(accessTokenSqlParameters);
 			String accessTokenType = null;
 			String accessTokenType = null;
 			String accessTokenScopes = null;
 			String accessTokenScopes = null;
 			if (accessToken != null) {
 			if (accessToken != null) {
 				accessTokenType = accessToken.getToken().getTokenType().getValue();
 				accessTokenType = accessToken.getToken().getTokenType().getValue();
 				if (!CollectionUtils.isEmpty(accessToken.getToken().getScopes())) {
 				if (!CollectionUtils.isEmpty(accessToken.getToken().getScopes())) {
-					accessTokenScopes = StringUtils.collectionToDelimitedString(accessToken.getToken().getScopes(),
-							",");
+					accessTokenScopes = StringUtils.collectionToDelimitedString(accessToken.getToken().getScopes(), ",");
 				}
 				}
 			}
 			}
 			parameters.add(new SqlParameterValue(Types.VARCHAR, accessTokenType));
 			parameters.add(new SqlParameterValue(Types.VARCHAR, accessTokenType));
 			parameters.add(new SqlParameterValue(Types.VARCHAR, accessTokenScopes));
 			parameters.add(new SqlParameterValue(Types.VARCHAR, accessTokenScopes));
 
 
 			OAuth2Authorization.Token<OidcIdToken> oidcIdToken = authorization.getToken(OidcIdToken.class);
 			OAuth2Authorization.Token<OidcIdToken> oidcIdToken = authorization.getToken(OidcIdToken.class);
-			List<SqlParameterValue> oidcIdTokenSqlParameters = toSqlParameterList("oidc_id_token_value",
-					"oidc_id_token_metadata", oidcIdToken);
+			List<SqlParameterValue> oidcIdTokenSqlParameters = toSqlParameterList(
+					"oidc_id_token_value", "oidc_id_token_metadata", oidcIdToken);
 			parameters.addAll(oidcIdTokenSqlParameters);
 			parameters.addAll(oidcIdTokenSqlParameters);
 
 
 			OAuth2Authorization.Token<OAuth2RefreshToken> refreshToken = authorization.getRefreshToken();
 			OAuth2Authorization.Token<OAuth2RefreshToken> refreshToken = authorization.getRefreshToken();
-			List<SqlParameterValue> refreshTokenSqlParameters = toSqlParameterList("refresh_token_value",
-					"refresh_token_metadata", refreshToken);
+			List<SqlParameterValue> refreshTokenSqlParameters = toSqlParameterList(
+					"refresh_token_value", "refresh_token_metadata", refreshToken);
 			parameters.addAll(refreshTokenSqlParameters);
 			parameters.addAll(refreshTokenSqlParameters);
 
 
 			OAuth2Authorization.Token<OAuth2UserCode> userCode = authorization.getToken(OAuth2UserCode.class);
 			OAuth2Authorization.Token<OAuth2UserCode> userCode = authorization.getToken(OAuth2UserCode.class);
-			List<SqlParameterValue> userCodeSqlParameters = toSqlParameterList("user_code_value", "user_code_metadata",
-					userCode);
+			List<SqlParameterValue> userCodeSqlParameters = toSqlParameterList(
+					"user_code_value", "user_code_metadata", userCode);
 			parameters.addAll(userCodeSqlParameters);
 			parameters.addAll(userCodeSqlParameters);
 
 
 			OAuth2Authorization.Token<OAuth2DeviceCode> deviceCode = authorization.getToken(OAuth2DeviceCode.class);
 			OAuth2Authorization.Token<OAuth2DeviceCode> deviceCode = authorization.getToken(OAuth2DeviceCode.class);
-			List<SqlParameterValue> deviceCodeSqlParameters = toSqlParameterList("device_code_value",
-					"device_code_metadata", deviceCode);
+			List<SqlParameterValue> deviceCodeSqlParameters = toSqlParameterList(
+					"device_code_value", "device_code_metadata", deviceCode);
 			parameters.addAll(deviceCodeSqlParameters);
 			parameters.addAll(deviceCodeSqlParameters);
 
 
 			return parameters;
 			return parameters;
@@ -652,8 +628,8 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 			return this.objectMapper;
 			return this.objectMapper;
 		}
 		}
 
 
-		private <T extends OAuth2Token> List<SqlParameterValue> toSqlParameterList(String tokenColumnName,
-				String tokenMetadataColumnName, OAuth2Authorization.Token<T> token) {
+		private <T extends OAuth2Token> List<SqlParameterValue> toSqlParameterList(
+				String tokenColumnName, String tokenMetadataColumnName, OAuth2Authorization.Token<T> token) {
 
 
 			List<SqlParameterValue> parameters = new ArrayList<>();
 			List<SqlParameterValue> parameters = new ArrayList<>();
 			String tokenValue = null;
 			String tokenValue = null;
@@ -681,8 +657,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 		private String writeMap(Map<String, Object> data) {
 		private String writeMap(Map<String, Object> data) {
 			try {
 			try {
 				return this.objectMapper.writeValueAsString(data);
 				return this.objectMapper.writeValueAsString(data);
-			}
-			catch (Exception ex) {
+			} catch (Exception ex) {
 				throw new IllegalArgumentException(ex.getMessage(), ex);
 				throw new IllegalArgumentException(ex.getMessage(), ex);
 			}
 			}
 		}
 		}
@@ -690,7 +665,6 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	}
 	}
 
 
 	private static final class LobCreatorArgumentPreparedStatementSetter extends ArgumentPreparedStatementSetter {
 	private static final class LobCreatorArgumentPreparedStatementSetter extends ArgumentPreparedStatementSetter {
-
 		private final LobCreator lobCreator;
 		private final LobCreator lobCreator;
 
 
 		private LobCreatorArgumentPreparedStatementSetter(LobCreator lobCreator, Object[] args) {
 		private LobCreatorArgumentPreparedStatementSetter(LobCreator lobCreator, Object[] args) {
@@ -727,9 +701,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	}
 	}
 
 
 	private static final class ColumnMetadata {
 	private static final class ColumnMetadata {
-
 		private final String columnName;
 		private final String columnName;
-
 		private final int dataType;
 		private final int dataType;
 
 
 		private ColumnMetadata(String columnName, int dataType) {
 		private ColumnMetadata(String columnName, int dataType) {
@@ -779,8 +751,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 		columnMetadataMap.put(columnMetadata.getColumnName(), columnMetadata);
 		columnMetadataMap.put(columnMetadata.getColumnName(), columnMetadata);
 	}
 	}
 
 
-	private static ColumnMetadata getColumnMetadata(JdbcOperations jdbcOperations, String columnName,
-			int defaultDataType) {
+	private static ColumnMetadata getColumnMetadata(JdbcOperations jdbcOperations, String columnName, int defaultDataType) {
 		Integer dataType = jdbcOperations.execute((ConnectionCallback<Integer>) conn -> {
 		Integer dataType = jdbcOperations.execute((ConnectionCallback<Integer>) conn -> {
 			DatabaseMetaData databaseMetaData = conn.getMetaData();
 			DatabaseMetaData databaseMetaData = conn.getMetaData();
 			ResultSet rs = databaseMetaData.getColumns(null, null, TABLE_NAME, columnName);
 			ResultSet rs = databaseMetaData.getColumns(null, null, TABLE_NAME, columnName);
@@ -788,13 +759,10 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 				return rs.getInt("DATA_TYPE");
 				return rs.getInt("DATA_TYPE");
 			}
 			}
 			// NOTE: (Applies to HSQL)
 			// NOTE: (Applies to HSQL)
-			// When a database object is created with one of the CREATE statements or
-			// renamed with the ALTER statement,
-			// if the name is enclosed in double quotes, the exact name is used as the
-			// case-normal form.
+			// When a database object is created with one of the CREATE statements or renamed with the ALTER statement,
+			// if the name is enclosed in double quotes, the exact name is used as the case-normal form.
 			// But if it is not enclosed in double quotes,
 			// But if it is not enclosed in double quotes,
-			// the name is converted to uppercase and this uppercase version is stored in
-			// the database as the case-normal form.
+			// the name is converted to uppercase and this uppercase version is stored in the database as the case-normal form.
 			rs = databaseMetaData.getColumns(null, null, TABLE_NAME.toUpperCase(), columnName.toUpperCase());
 			rs = databaseMetaData.getColumns(null, null, TABLE_NAME.toUpperCase(), columnName.toUpperCase());
 			if (rs.next()) {
 			if (rs.next()) {
 				return rs.getInt("DATA_TYPE");
 				return rs.getInt("DATA_TYPE");
@@ -806,9 +774,9 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 
 
 	private static SqlParameterValue mapToSqlParameter(String columnName, String value) {
 	private static SqlParameterValue mapToSqlParameter(String columnName, String value) {
 		ColumnMetadata columnMetadata = columnMetadataMap.get(columnName);
 		ColumnMetadata columnMetadata = columnMetadataMap.get(columnName);
-		return Types.BLOB == columnMetadata.getDataType() && StringUtils.hasText(value)
-				? new SqlParameterValue(Types.BLOB, value.getBytes(StandardCharsets.UTF_8))
-				: new SqlParameterValue(columnMetadata.getDataType(), value);
+		return Types.BLOB == columnMetadata.getDataType() && StringUtils.hasText(value) ?
+				new SqlParameterValue(Types.BLOB, value.getBytes(StandardCharsets.UTF_8)) :
+				new SqlParameterValue(columnMetadata.getDataType(), value);
 	}
 	}
 
 
 }
 }

+ 200 - 0
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/aot/hint/OAuth2AuthorizationServerBeanRegistrationAotProcessor.java

@@ -0,0 +1,200 @@
+/*
+ * Copyright 2020-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.oauth2.server.authorization.aot.hint;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+
+import org.springframework.aot.generate.GenerationContext;
+import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
+import org.springframework.aot.hint.MemberCategory;
+import org.springframework.aot.hint.RuntimeHints;
+import org.springframework.aot.hint.TypeReference;
+import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
+import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
+import org.springframework.beans.factory.aot.BeanRegistrationCode;
+import org.springframework.beans.factory.support.RegisteredBean;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.jackson2.CoreJackson2Module;
+import org.springframework.security.oauth2.core.AbstractOAuth2Token;
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
+import org.springframework.security.oauth2.core.oidc.OidcIdToken;
+import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
+import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
+import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
+import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
+import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
+import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
+import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
+import org.springframework.security.web.authentication.WebAuthenticationDetails;
+import org.springframework.security.web.jackson2.WebServletJackson2Module;
+import org.springframework.security.web.savedrequest.DefaultSavedRequest;
+import org.springframework.util.ClassUtils;
+
+/**
+ * {@link BeanRegistrationAotProcessor} that detects specific registered beans and contributes the required {@link RuntimeHints}.
+ * Statically registered via META-INF/spring/aot.factories.
+ *
+ * @author Joe Grandja
+ * @author Josh Long
+ * @since 1.2
+ */
+class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
+	private boolean jackson2Contributed;
+
+	@Override
+	public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
+		String beanClassName = registeredBean.getBeanClass().getName();
+		if ((beanClassName.equals("org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService") ||
+				beanClassName.equals("org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository")) &&
+				!jackson2Contributed) {
+			Jackson2ConfigurationBeanRegistrationAotContribution jackson2Contribution =
+					new Jackson2ConfigurationBeanRegistrationAotContribution();
+			jackson2Contributed = true;
+			return jackson2Contribution;
+		}
+		return null;
+	}
+
+	private static class Jackson2ConfigurationBeanRegistrationAotContribution implements BeanRegistrationAotContribution {
+		private final BindingReflectionHintsRegistrar reflectionHintsRegistrar = new BindingReflectionHintsRegistrar();
+
+		@Override
+		public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
+			registerHints(generationContext.getRuntimeHints());
+		}
+
+		private void registerHints(RuntimeHints hints) {
+			// Collections -> UnmodifiableSet, UnmodifiableList, UnmodifiableMap, UnmodifiableRandomAccessList, etc.
+			hints.reflection().registerType(Collections.class,
+					MemberCategory.DECLARED_CLASSES);
+
+			// HashSet
+			hints.reflection().registerType(HashSet.class,
+					MemberCategory.DECLARED_FIELDS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
+					MemberCategory.INVOKE_DECLARED_METHODS);
+
+			// Spring Security and Spring Authorization Server
+			hints.reflection().registerTypes(
+					Arrays.asList(
+							TypeReference.of(AbstractAuthenticationToken.class),
+							TypeReference.of(DefaultSavedRequest.Builder.class),
+							TypeReference.of(WebAuthenticationDetails.class),
+							TypeReference.of(UsernamePasswordAuthenticationToken.class),
+							TypeReference.of(User.class),
+							TypeReference.of(DefaultOidcUser.class),
+							TypeReference.of(DefaultOAuth2User.class),
+							TypeReference.of(OidcUserAuthority.class),
+							TypeReference.of(OAuth2UserAuthority.class),
+							TypeReference.of(SimpleGrantedAuthority.class),
+							TypeReference.of(OidcIdToken.class),
+							TypeReference.of(AbstractOAuth2Token.class),
+							TypeReference.of(OidcUserInfo.class),
+							TypeReference.of(OAuth2AuthorizationRequest.class),
+							TypeReference.of(AuthorizationGrantType.class),
+							TypeReference.of(OAuth2AuthorizationResponseType.class),
+							TypeReference.of(OAuth2TokenFormat.class)
+					), builder ->
+							builder.withMembers(MemberCategory.DECLARED_FIELDS,
+									MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)
+			);
+
+			// Jackson Modules - Spring Security and Spring Authorization Server
+			hints.reflection().registerTypes(
+					Arrays.asList(
+							TypeReference.of(CoreJackson2Module.class),
+							TypeReference.of(WebServletJackson2Module.class),
+							TypeReference.of(OAuth2AuthorizationServerJackson2Module.class)
+					), builder ->
+							builder.withMembers(MemberCategory.DECLARED_FIELDS,
+									MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)
+			);
+
+			// Jackson Mixins - Spring Security and Spring Authorization Server
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.jackson2.UnmodifiableSetMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.jackson2.UnmodifiableListMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.jackson2.UnmodifiableMapMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.oauth2.server.authorization.jackson2.UnmodifiableMapMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.oauth2.server.authorization.jackson2.HashSetMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.web.jackson2.DefaultSavedRequestMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.web.jackson2.WebAuthenticationDetailsMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.jackson2.UsernamePasswordAuthenticationTokenMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.jackson2.UserMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.jackson2.SimpleGrantedAuthorityMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationRequestMixin"));
+			this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+					loadClass("org.springframework.security.oauth2.server.authorization.jackson2.OAuth2TokenFormatMixin"));
+
+			// Check if Spring Security OAuth2 Client is on classpath
+			if (ClassUtils.isPresent("org.springframework.security.oauth2.client.registration.ClientRegistration",
+					ClassUtils.getDefaultClassLoader())) {
+
+				// Jackson Module (and required types) - Spring Security OAuth2 Client
+				hints.reflection().registerTypes(
+						Arrays.asList(
+								TypeReference.of("org.springframework.security.oauth2.client.jackson2.OAuth2ClientJackson2Module"),
+								TypeReference.of("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken")
+						), builder ->
+								builder.withMembers(MemberCategory.DECLARED_FIELDS,
+										MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)
+				);
+
+				// Jackson Mixins - Spring Security OAuth2 Client
+				this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+						loadClass("org.springframework.security.oauth2.client.jackson2.OAuth2AuthenticationTokenMixin"));
+				this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+						loadClass("org.springframework.security.oauth2.client.jackson2.DefaultOidcUserMixin"));
+				this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+						loadClass("org.springframework.security.oauth2.client.jackson2.DefaultOAuth2UserMixin"));
+				this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+						loadClass("org.springframework.security.oauth2.client.jackson2.OidcUserAuthorityMixin"));
+				this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+						loadClass("org.springframework.security.oauth2.client.jackson2.OAuth2UserAuthorityMixin"));
+				this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+						loadClass("org.springframework.security.oauth2.client.jackson2.OidcIdTokenMixin"));
+				this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
+						loadClass("org.springframework.security.oauth2.client.jackson2.OidcUserInfoMixin"));
+			}
+		}
+
+		private static Class<?> loadClass(String className) {
+			try {
+				return Class.forName(className);
+			} catch (ClassNotFoundException ex) {
+				throw new RuntimeException(ex);
+			}
+		}
+
+	}
+
+}

+ 81 - 100
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/JdbcRegisteredClientRepository.java

@@ -15,14 +15,31 @@
  */
  */
 package org.springframework.security.oauth2.server.authorization.client;
 package org.springframework.security.oauth2.server.authorization.client;
 
 
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.Module;
 import com.fasterxml.jackson.databind.Module;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectMapper;
+
 import org.springframework.aot.hint.RuntimeHints;
 import org.springframework.aot.hint.RuntimeHints;
 import org.springframework.aot.hint.RuntimeHintsRegistrar;
 import org.springframework.aot.hint.RuntimeHintsRegistrar;
 import org.springframework.context.annotation.ImportRuntimeHints;
 import org.springframework.context.annotation.ImportRuntimeHints;
 import org.springframework.core.io.ClassPathResource;
 import org.springframework.core.io.ClassPathResource;
-import org.springframework.jdbc.core.*;
+import org.springframework.jdbc.core.ArgumentPreparedStatementSetter;
+import org.springframework.jdbc.core.JdbcOperations;
+import org.springframework.jdbc.core.PreparedStatementSetter;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.SqlParameterValue;
 import org.springframework.security.jackson2.SecurityJackson2Modules;
 import org.springframework.security.jackson2.SecurityJackson2Modules;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
@@ -34,33 +51,24 @@ import org.springframework.security.oauth2.server.authorization.settings.TokenSe
 import org.springframework.util.Assert;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 import org.springframework.util.StringUtils;
 
 
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.sql.Types;
-import java.time.Instant;
-import java.util.*;
-import java.util.function.Function;
-
 /**
 /**
  * A JDBC implementation of a {@link RegisteredClientRepository} that uses a
  * A JDBC implementation of a {@link RegisteredClientRepository} that uses a
  * {@link JdbcOperations} for {@link RegisteredClient} persistence.
  * {@link JdbcOperations} for {@link RegisteredClient} persistence.
  *
  *
  * <p>
  * <p>
- * <b>NOTE:</b> This {@code RegisteredClientRepository} depends on the table definition
- * described in
- * "classpath:org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql"
- * and therefore MUST be defined in the database schema.
+ * <b>NOTE:</b> This {@code RegisteredClientRepository} depends on the table definition described in
+ * "classpath:org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql" and
+ * therefore MUST be defined in the database schema.
  *
  *
  * @author Rafal Lewczuk
  * @author Rafal Lewczuk
  * @author Joe Grandja
  * @author Joe Grandja
  * @author Ovidiu Popa
  * @author Ovidiu Popa
  * @author Josh Long
  * @author Josh Long
+ * @since 0.1.2
  * @see RegisteredClientRepository
  * @see RegisteredClientRepository
  * @see RegisteredClient
  * @see RegisteredClient
  * @see JdbcOperations
  * @see JdbcOperations
  * @see RowMapper
  * @see RowMapper
- * @since 0.1.2
  */
  */
 @ImportRuntimeHints(JdbcRegisteredClientRepository.JdbcRegisteredClientRepositoryRuntimeHintsRegistrar.class)
 @ImportRuntimeHints(JdbcRegisteredClientRepository.JdbcRegisteredClientRepositoryRuntimeHintsRegistrar.class)
 public class JdbcRegisteredClientRepository implements RegisteredClientRepository {
 public class JdbcRegisteredClientRepository implements RegisteredClientRepository {
@@ -95,8 +103,7 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 
 
 	private static final String PK_FILTER = "id = ?";
 	private static final String PK_FILTER = "id = ?";
 
 
-	private static final String LOAD_REGISTERED_CLIENT_SQL = "SELECT " + COLUMN_NAMES + " FROM " + TABLE_NAME
-			+ " WHERE ";
+	private static final String LOAD_REGISTERED_CLIENT_SQL = "SELECT " + COLUMN_NAMES + " FROM " + TABLE_NAME + " WHERE ";
 
 
 	// @formatter:off
 	// @formatter:off
 	private static final String INSERT_REGISTERED_CLIENT_SQL = "INSERT INTO " + TABLE_NAME
 	private static final String INSERT_REGISTERED_CLIENT_SQL = "INSERT INTO " + TABLE_NAME
@@ -114,13 +121,12 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 	private static final String COUNT_REGISTERED_CLIENT_SQL = "SELECT COUNT(*) FROM " + TABLE_NAME + " WHERE ";
 	private static final String COUNT_REGISTERED_CLIENT_SQL = "SELECT COUNT(*) FROM " + TABLE_NAME + " WHERE ";
 
 
 	private final JdbcOperations jdbcOperations;
 	private final JdbcOperations jdbcOperations;
-
 	private RowMapper<RegisteredClient> registeredClientRowMapper;
 	private RowMapper<RegisteredClient> registeredClientRowMapper;
-
 	private Function<RegisteredClient, List<SqlParameterValue>> registeredClientParametersMapper;
 	private Function<RegisteredClient, List<SqlParameterValue>> registeredClientParametersMapper;
 
 
 	/**
 	/**
 	 * Constructs a {@code JdbcRegisteredClientRepository} using the provided parameters.
 	 * Constructs a {@code JdbcRegisteredClientRepository} using the provided parameters.
+	 *
 	 * @param jdbcOperations the JDBC operations
 	 * @param jdbcOperations the JDBC operations
 	 */
 	 */
 	public JdbcRegisteredClientRepository(JdbcOperations jdbcOperations) {
 	public JdbcRegisteredClientRepository(JdbcOperations jdbcOperations) {
@@ -133,18 +139,17 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 	@Override
 	@Override
 	public void save(RegisteredClient registeredClient) {
 	public void save(RegisteredClient registeredClient) {
 		Assert.notNull(registeredClient, "registeredClient cannot be null");
 		Assert.notNull(registeredClient, "registeredClient cannot be null");
-		RegisteredClient existingRegisteredClient = findBy(PK_FILTER, registeredClient.getId());
+		RegisteredClient existingRegisteredClient = findBy(PK_FILTER,
+				registeredClient.getId());
 		if (existingRegisteredClient != null) {
 		if (existingRegisteredClient != null) {
 			updateRegisteredClient(registeredClient);
 			updateRegisteredClient(registeredClient);
-		}
-		else {
+		} else {
 			insertRegisteredClient(registeredClient);
 			insertRegisteredClient(registeredClient);
 		}
 		}
 	}
 	}
 
 
 	private void updateRegisteredClient(RegisteredClient registeredClient) {
 	private void updateRegisteredClient(RegisteredClient registeredClient) {
-		List<SqlParameterValue> parameters = new ArrayList<>(
-				this.registeredClientParametersMapper.apply(registeredClient));
+		List<SqlParameterValue> parameters = new ArrayList<>(this.registeredClientParametersMapper.apply(registeredClient));
 		SqlParameterValue id = parameters.remove(0);
 		SqlParameterValue id = parameters.remove(0);
 		parameters.remove(0); // remove client_id
 		parameters.remove(0); // remove client_id
 		parameters.remove(0); // remove client_id_issued_at
 		parameters.remove(0); // remove client_id_issued_at
@@ -161,17 +166,21 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 	}
 	}
 
 
 	private void assertUniqueIdentifiers(RegisteredClient registeredClient) {
 	private void assertUniqueIdentifiers(RegisteredClient registeredClient) {
-		Integer count = this.jdbcOperations.queryForObject(COUNT_REGISTERED_CLIENT_SQL + "client_id = ?", Integer.class,
+		Integer count = this.jdbcOperations.queryForObject(
+				COUNT_REGISTERED_CLIENT_SQL + "client_id = ?",
+				Integer.class,
 				registeredClient.getClientId());
 				registeredClient.getClientId());
 		if (count != null && count > 0) {
 		if (count != null && count > 0) {
-			throw new IllegalArgumentException("Registered client must be unique. "
-					+ "Found duplicate client identifier: " + registeredClient.getClientId());
+			throw new IllegalArgumentException("Registered client must be unique. " +
+					"Found duplicate client identifier: " + registeredClient.getClientId());
 		}
 		}
-		count = this.jdbcOperations.queryForObject(COUNT_REGISTERED_CLIENT_SQL + "client_secret = ?", Integer.class,
+		count = this.jdbcOperations.queryForObject(
+				COUNT_REGISTERED_CLIENT_SQL + "client_secret = ?",
+				Integer.class,
 				registeredClient.getClientSecret());
 				registeredClient.getClientSecret());
 		if (count != null && count > 0) {
 		if (count != null && count > 0) {
-			throw new IllegalArgumentException("Registered client must be unique. "
-					+ "Found duplicate client secret for identifier: " + registeredClient.getId());
+			throw new IllegalArgumentException("Registered client must be unique. " +
+					"Found duplicate client secret for identifier: " + registeredClient.getId());
 		}
 		}
 	}
 	}
 
 
@@ -188,17 +197,16 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 	}
 	}
 
 
 	private RegisteredClient findBy(String filter, Object... args) {
 	private RegisteredClient findBy(String filter, Object... args) {
-		List<RegisteredClient> result = this.jdbcOperations.query(LOAD_REGISTERED_CLIENT_SQL + filter,
-				this.registeredClientRowMapper, args);
+		List<RegisteredClient> result = this.jdbcOperations.query(
+				LOAD_REGISTERED_CLIENT_SQL + filter, this.registeredClientRowMapper, args);
 		return !result.isEmpty() ? result.get(0) : null;
 		return !result.isEmpty() ? result.get(0) : null;
 	}
 	}
 
 
 	/**
 	/**
-	 * Sets the {@link RowMapper} used for mapping the current row in
-	 * {@code java.sql.ResultSet} to {@link RegisteredClient}. The default is
-	 * {@link RegisteredClientRowMapper}.
-	 * @param registeredClientRowMapper the {@link RowMapper} used for mapping the current
-	 * row in {@code ResultSet} to {@link RegisteredClient}
+	 * Sets the {@link RowMapper} used for mapping the current row in {@code java.sql.ResultSet} to {@link RegisteredClient}.
+	 * The default is {@link RegisteredClientRowMapper}.
+	 *
+	 * @param registeredClientRowMapper the {@link RowMapper} used for mapping the current row in {@code ResultSet} to {@link RegisteredClient}
 	 */
 	 */
 	public final void setRegisteredClientRowMapper(RowMapper<RegisteredClient> registeredClientRowMapper) {
 	public final void setRegisteredClientRowMapper(RowMapper<RegisteredClient> registeredClientRowMapper) {
 		Assert.notNull(registeredClientRowMapper, "registeredClientRowMapper cannot be null");
 		Assert.notNull(registeredClientRowMapper, "registeredClientRowMapper cannot be null");
@@ -206,14 +214,12 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 	}
 	}
 
 
 	/**
 	/**
-	 * Sets the {@code Function} used for mapping {@link RegisteredClient} to a
-	 * {@code List} of {@link SqlParameterValue}. The default is
-	 * {@link RegisteredClientParametersMapper}.
-	 * @param registeredClientParametersMapper the {@code Function} used for mapping
-	 * {@link RegisteredClient} to a {@code List} of {@link SqlParameterValue}
+	 * Sets the {@code Function} used for mapping {@link RegisteredClient} to a {@code List} of {@link SqlParameterValue}.
+	 * The default is {@link RegisteredClientParametersMapper}.
+	 *
+	 * @param registeredClientParametersMapper the {@code Function} used for mapping {@link RegisteredClient} to a {@code List} of {@link SqlParameterValue}
 	 */
 	 */
-	public final void setRegisteredClientParametersMapper(
-			Function<RegisteredClient, List<SqlParameterValue>> registeredClientParametersMapper) {
+	public final void setRegisteredClientParametersMapper(Function<RegisteredClient, List<SqlParameterValue>> registeredClientParametersMapper) {
 		Assert.notNull(registeredClientParametersMapper, "registeredClientParametersMapper cannot be null");
 		Assert.notNull(registeredClientParametersMapper, "registeredClientParametersMapper cannot be null");
 		this.registeredClientParametersMapper = registeredClientParametersMapper;
 		this.registeredClientParametersMapper = registeredClientParametersMapper;
 	}
 	}
@@ -235,7 +241,6 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 	 * {@code java.sql.ResultSet} to {@link RegisteredClient}.
 	 * {@code java.sql.ResultSet} to {@link RegisteredClient}.
 	 */
 	 */
 	public static class RegisteredClientRowMapper implements RowMapper<RegisteredClient> {
 	public static class RegisteredClientRowMapper implements RowMapper<RegisteredClient> {
-
 		private ObjectMapper objectMapper = new ObjectMapper();
 		private ObjectMapper objectMapper = new ObjectMapper();
 
 
 		public RegisteredClientRowMapper() {
 		public RegisteredClientRowMapper() {
@@ -249,13 +254,10 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 		public RegisteredClient mapRow(ResultSet rs, int rowNum) throws SQLException {
 		public RegisteredClient mapRow(ResultSet rs, int rowNum) throws SQLException {
 			Timestamp clientIdIssuedAt = rs.getTimestamp("client_id_issued_at");
 			Timestamp clientIdIssuedAt = rs.getTimestamp("client_id_issued_at");
 			Timestamp clientSecretExpiresAt = rs.getTimestamp("client_secret_expires_at");
 			Timestamp clientSecretExpiresAt = rs.getTimestamp("client_secret_expires_at");
-			Set<String> clientAuthenticationMethods = StringUtils
-					.commaDelimitedListToSet(rs.getString("client_authentication_methods"));
-			Set<String> authorizationGrantTypes = StringUtils
-					.commaDelimitedListToSet(rs.getString("authorization_grant_types"));
+			Set<String> clientAuthenticationMethods = StringUtils.commaDelimitedListToSet(rs.getString("client_authentication_methods"));
+			Set<String> authorizationGrantTypes = StringUtils.commaDelimitedListToSet(rs.getString("authorization_grant_types"));
 			Set<String> redirectUris = StringUtils.commaDelimitedListToSet(rs.getString("redirect_uris"));
 			Set<String> redirectUris = StringUtils.commaDelimitedListToSet(rs.getString("redirect_uris"));
-			Set<String> postLogoutRedirectUris = StringUtils
-					.commaDelimitedListToSet(rs.getString("post_logout_redirect_uris"));
+			Set<String> postLogoutRedirectUris = StringUtils.commaDelimitedListToSet(rs.getString("post_logout_redirect_uris"));
 			Set<String> clientScopes = StringUtils.commaDelimitedListToSet(rs.getString("scopes"));
 			Set<String> clientScopes = StringUtils.commaDelimitedListToSet(rs.getString("scopes"));
 
 
 			// @formatter:off
 			// @formatter:off
@@ -300,10 +302,8 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 
 
 		private Map<String, Object> parseMap(String data) {
 		private Map<String, Object> parseMap(String data) {
 			try {
 			try {
-				return this.objectMapper.readValue(data, new TypeReference<Map<String, Object>>() {
-				});
-			}
-			catch (Exception ex) {
+				return this.objectMapper.readValue(data, new TypeReference<Map<String, Object>>() {});
+			} catch (Exception ex) {
 				throw new IllegalArgumentException(ex.getMessage(), ex);
 				throw new IllegalArgumentException(ex.getMessage(), ex);
 			}
 			}
 		}
 		}
@@ -311,43 +311,32 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 		private static AuthorizationGrantType resolveAuthorizationGrantType(String authorizationGrantType) {
 		private static AuthorizationGrantType resolveAuthorizationGrantType(String authorizationGrantType) {
 			if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(authorizationGrantType)) {
 			if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(authorizationGrantType)) {
 				return AuthorizationGrantType.AUTHORIZATION_CODE;
 				return AuthorizationGrantType.AUTHORIZATION_CODE;
-			}
-			else if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(authorizationGrantType)) {
+			} else if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(authorizationGrantType)) {
 				return AuthorizationGrantType.CLIENT_CREDENTIALS;
 				return AuthorizationGrantType.CLIENT_CREDENTIALS;
-			}
-			else if (AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(authorizationGrantType)) {
+			} else if (AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(authorizationGrantType)) {
 				return AuthorizationGrantType.REFRESH_TOKEN;
 				return AuthorizationGrantType.REFRESH_TOKEN;
 			}
 			}
-			return new AuthorizationGrantType(authorizationGrantType); // Custom
-																		// authorization
-																		// grant type
+			return new AuthorizationGrantType(authorizationGrantType);		// Custom authorization grant type
 		}
 		}
 
 
 		private static ClientAuthenticationMethod resolveClientAuthenticationMethod(String clientAuthenticationMethod) {
 		private static ClientAuthenticationMethod resolveClientAuthenticationMethod(String clientAuthenticationMethod) {
 			if (ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue().equals(clientAuthenticationMethod)) {
 			if (ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue().equals(clientAuthenticationMethod)) {
 				return ClientAuthenticationMethod.CLIENT_SECRET_BASIC;
 				return ClientAuthenticationMethod.CLIENT_SECRET_BASIC;
-			}
-			else if (ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue().equals(clientAuthenticationMethod)) {
+			} else if (ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue().equals(clientAuthenticationMethod)) {
 				return ClientAuthenticationMethod.CLIENT_SECRET_POST;
 				return ClientAuthenticationMethod.CLIENT_SECRET_POST;
-			}
-			else if (ClientAuthenticationMethod.NONE.getValue().equals(clientAuthenticationMethod)) {
+			} else if (ClientAuthenticationMethod.NONE.getValue().equals(clientAuthenticationMethod)) {
 				return ClientAuthenticationMethod.NONE;
 				return ClientAuthenticationMethod.NONE;
 			}
 			}
-			return new ClientAuthenticationMethod(clientAuthenticationMethod); // Custom
-																				// client
-																				// authentication
-																				// method
+			return new ClientAuthenticationMethod(clientAuthenticationMethod);		// Custom client authentication method
 		}
 		}
 
 
 	}
 	}
 
 
 	/**
 	/**
-	 * The default {@code Function} that maps {@link RegisteredClient} to a {@code List}
-	 * of {@link SqlParameterValue}.
+	 * The default {@code Function} that maps {@link RegisteredClient} to a
+	 * {@code List} of {@link SqlParameterValue}.
 	 */
 	 */
-	public static class RegisteredClientParametersMapper
-			implements Function<RegisteredClient, List<SqlParameterValue>> {
-
+	public static class RegisteredClientParametersMapper implements Function<RegisteredClient, List<SqlParameterValue>> {
 		private ObjectMapper objectMapper = new ObjectMapper();
 		private ObjectMapper objectMapper = new ObjectMapper();
 
 
 		public RegisteredClientParametersMapper() {
 		public RegisteredClientParametersMapper() {
@@ -359,39 +348,32 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 
 
 		@Override
 		@Override
 		public List<SqlParameterValue> apply(RegisteredClient registeredClient) {
 		public List<SqlParameterValue> apply(RegisteredClient registeredClient) {
-			Timestamp clientIdIssuedAt = registeredClient.getClientIdIssuedAt() != null
-					? Timestamp.from(registeredClient.getClientIdIssuedAt()) : Timestamp.from(Instant.now());
+			Timestamp clientIdIssuedAt = registeredClient.getClientIdIssuedAt() != null ?
+					Timestamp.from(registeredClient.getClientIdIssuedAt()) : Timestamp.from(Instant.now());
 
 
-			Timestamp clientSecretExpiresAt = registeredClient.getClientSecretExpiresAt() != null
-					? Timestamp.from(registeredClient.getClientSecretExpiresAt()) : null;
+			Timestamp clientSecretExpiresAt = registeredClient.getClientSecretExpiresAt() != null ?
+					Timestamp.from(registeredClient.getClientSecretExpiresAt()) : null;
 
 
-			List<String> clientAuthenticationMethods = new ArrayList<>(
-					registeredClient.getClientAuthenticationMethods().size());
-			registeredClient.getClientAuthenticationMethods()
-					.forEach(clientAuthenticationMethod -> clientAuthenticationMethods
-							.add(clientAuthenticationMethod.getValue()));
+			List<String> clientAuthenticationMethods = new ArrayList<>(registeredClient.getClientAuthenticationMethods().size());
+			registeredClient.getClientAuthenticationMethods().forEach(clientAuthenticationMethod ->
+					clientAuthenticationMethods.add(clientAuthenticationMethod.getValue()));
 
 
-			List<String> authorizationGrantTypes = new ArrayList<>(
-					registeredClient.getAuthorizationGrantTypes().size());
-			registeredClient.getAuthorizationGrantTypes()
-					.forEach(authorizationGrantType -> authorizationGrantTypes.add(authorizationGrantType.getValue()));
+			List<String> authorizationGrantTypes = new ArrayList<>(registeredClient.getAuthorizationGrantTypes().size());
+			registeredClient.getAuthorizationGrantTypes().forEach(authorizationGrantType ->
+					authorizationGrantTypes.add(authorizationGrantType.getValue()));
 
 
-			return Arrays.asList(new SqlParameterValue(Types.VARCHAR, registeredClient.getId()),
+			return Arrays.asList(
+					new SqlParameterValue(Types.VARCHAR, registeredClient.getId()),
 					new SqlParameterValue(Types.VARCHAR, registeredClient.getClientId()),
 					new SqlParameterValue(Types.VARCHAR, registeredClient.getClientId()),
 					new SqlParameterValue(Types.TIMESTAMP, clientIdIssuedAt),
 					new SqlParameterValue(Types.TIMESTAMP, clientIdIssuedAt),
 					new SqlParameterValue(Types.VARCHAR, registeredClient.getClientSecret()),
 					new SqlParameterValue(Types.VARCHAR, registeredClient.getClientSecret()),
 					new SqlParameterValue(Types.TIMESTAMP, clientSecretExpiresAt),
 					new SqlParameterValue(Types.TIMESTAMP, clientSecretExpiresAt),
 					new SqlParameterValue(Types.VARCHAR, registeredClient.getClientName()),
 					new SqlParameterValue(Types.VARCHAR, registeredClient.getClientName()),
-					new SqlParameterValue(Types.VARCHAR,
-							StringUtils.collectionToCommaDelimitedString(clientAuthenticationMethods)),
-					new SqlParameterValue(Types.VARCHAR,
-							StringUtils.collectionToCommaDelimitedString(authorizationGrantTypes)),
-					new SqlParameterValue(Types.VARCHAR,
-							StringUtils.collectionToCommaDelimitedString(registeredClient.getRedirectUris())),
-					new SqlParameterValue(Types.VARCHAR,
-							StringUtils.collectionToCommaDelimitedString(registeredClient.getPostLogoutRedirectUris())),
-					new SqlParameterValue(Types.VARCHAR,
-							StringUtils.collectionToCommaDelimitedString(registeredClient.getScopes())),
+					new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToCommaDelimitedString(clientAuthenticationMethods)),
+					new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToCommaDelimitedString(authorizationGrantTypes)),
+					new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToCommaDelimitedString(registeredClient.getRedirectUris())),
+					new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToCommaDelimitedString(registeredClient.getPostLogoutRedirectUris())),
+					new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToCommaDelimitedString(registeredClient.getScopes())),
 					new SqlParameterValue(Types.VARCHAR, writeMap(registeredClient.getClientSettings().getSettings())),
 					new SqlParameterValue(Types.VARCHAR, writeMap(registeredClient.getClientSettings().getSettings())),
 					new SqlParameterValue(Types.VARCHAR, writeMap(registeredClient.getTokenSettings().getSettings())));
 					new SqlParameterValue(Types.VARCHAR, writeMap(registeredClient.getTokenSettings().getSettings())));
 		}
 		}
@@ -408,8 +390,7 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 		private String writeMap(Map<String, Object> data) {
 		private String writeMap(Map<String, Object> data) {
 			try {
 			try {
 				return this.objectMapper.writeValueAsString(data);
 				return this.objectMapper.writeValueAsString(data);
-			}
-			catch (Exception ex) {
+			} catch (Exception ex) {
 				throw new IllegalArgumentException(ex.getMessage(), ex);
 				throw new IllegalArgumentException(ex.getMessage(), ex);
 			}
 			}
 		}
 		}

+ 2 - 2
oauth2-authorization-server/src/main/resources/META-INF/spring/aot.factories

@@ -1,2 +1,2 @@
-org.springframework.aot.hint.RuntimeHintsRegistrar=\
- org.springframework.security.oauth2.server.authorization.AuthorizationServerRuntimeHintsRegistrar
+org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
+ org.springframework.security.oauth2.server.authorization.aot.hint.OAuth2AuthorizationServerBeanRegistrationAotProcessor

+ 0 - 1
samples/demo-authorizationserver/samples-demo-authorizationserver.gradle

@@ -2,7 +2,6 @@ plugins {
 	id "org.springframework.boot" version "3.1.0"
 	id "org.springframework.boot" version "3.1.0"
 	id "io.spring.dependency-management" version "1.1.0"
 	id "io.spring.dependency-management" version "1.1.0"
 	id "java"
 	id "java"
-	id 'org.graalvm.buildtools.native' version '0.9.27'
 }
 }
 
 
 group = project.rootProject.group
 group = project.rootProject.group

+ 28 - 3
samples/demo-authorizationserver/src/main/java/sample/DemoAuthorizationServerApplication.java

@@ -15,20 +15,45 @@
  */
  */
 package sample;
 package sample;
 
 
-import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
+import java.util.Arrays;
+
+import org.thymeleaf.expression.Lists;
+import sample.web.AuthorizationConsentController;
+
+import org.springframework.aot.hint.MemberCategory;
+import org.springframework.aot.hint.RuntimeHints;
+import org.springframework.aot.hint.RuntimeHintsRegistrar;
+import org.springframework.aot.hint.TypeReference;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import sample.web.AuthorizationConsentController;
+import org.springframework.context.annotation.ImportRuntimeHints;
 
 
 /**
 /**
  * @author Joe Grandja
  * @author Joe Grandja
  * @author Josh Long
  * @author Josh Long
  * @since 1.1
  * @since 1.1
  */
  */
-@RegisterReflectionForBinding(AuthorizationConsentController.ScopeWithDescription.class)
 @SpringBootApplication
 @SpringBootApplication
+@ImportRuntimeHints(DemoAuthorizationServerApplication.DemoAuthorizationServerApplicationRuntimeHintsRegistrar.class)
 public class DemoAuthorizationServerApplication {
 public class DemoAuthorizationServerApplication {
 
 
+	static class DemoAuthorizationServerApplicationRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
+
+		@Override
+		public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
+			// Thymeleaf
+			hints.reflection().registerTypes(
+					Arrays.asList(
+							TypeReference.of(AuthorizationConsentController.ScopeWithDescription.class),
+							TypeReference.of(Lists.class)
+					), builder ->
+							builder.withMembers(MemberCategory.DECLARED_FIELDS,
+									MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)
+			);
+		}
+
+	}
+
 	public static void main(String[] args) {
 	public static void main(String[] args) {
 		SpringApplication.run(DemoAuthorizationServerApplication.class, args);
 		SpringApplication.run(DemoAuthorizationServerApplication.class, args);
 	}
 	}

+ 3 - 3
samples/demo-authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java

@@ -132,7 +132,7 @@ public class AuthorizationServerConfig {
 
 
 	// @formatter:off
 	// @formatter:off
 	@Bean
 	@Bean
-	public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
+	public JdbcRegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
 		RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
 		RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
 				.clientId("messaging-client")
 				.clientId("messaging-client")
 				.clientSecret("{noop}secret")
 				.clientSecret("{noop}secret")
@@ -169,13 +169,13 @@ public class AuthorizationServerConfig {
 	// @formatter:on
 	// @formatter:on
 
 
 	@Bean
 	@Bean
-	public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate,
+	public JdbcOAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate,
 			RegisteredClientRepository registeredClientRepository) {
 			RegisteredClientRepository registeredClientRepository) {
 		return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
 		return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
 	}
 	}
 
 
 	@Bean
 	@Bean
-	public OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate,
+	public JdbcOAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate,
 			RegisteredClientRepository registeredClientRepository) {
 			RegisteredClientRepository registeredClientRepository) {
 		// Will be used by the ConsentController
 		// Will be used by the ConsentController
 		return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);
 		return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);