Code: Select all
if (!providedDeviceId.equals(storedDeviceId)) {
String errorMessage = "Provided device ID '" + providedDeviceId
+ "' did not match stored device ID '" + storedDeviceId
+ "' for refresh token '" + refreshTokenValue + "'";
log.warn(errorMessage);
throw new OAuth2AuthenticationException(
new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT, errorMessage, null)
);
}
< /code>
Diese Logik funktioniert einwandfrei. In der Framework -Klasse org.springframework.security.authentication.providermanager
Code: Select all
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
[...]
for (AuthenticationProvider provider : getProviders()) {
if (!provider.supports(toTest)) {
continue;
}
[...]
try {
result = provider.authenticate(authentication);
if (result != null) {
copyDetails(authentication, result);
break;
}
}
catch (AccountStatusException | InternalAuthenticationServiceException ex) {
prepareException(ex, authentication);
// SEC-546: Avoid polling additional providers if auth failure is due to
// invalid account status
throw ex;
}
catch (AuthenticationException ex) {
lastException = ex;
}
}
< /code>
Das heißt, es iteriert alle Authentifizierungsantrieber, die einen Authentifizierungstyp unterstützen, und bricht nur, wenn er erfolgreich ist, oder eine AccountStatusexception oder interneAuthenticationServiceException wird geworfen. Beachten Sie, dass es keine Authentifizierungspflicht bittet. So hätte ich erwartet, dass es funktioniert. Stattdessen wird es weiterhin über die verbleibenden Authentifizierungspfieber iteriert, die einen Authentifizierungstyp unterstützen. Und das führt mich zu meinem Problem: < /p>
getProviders()
Code: Select all
java.lang.IllegalArgumentException: value cannot be null
at org.springframework.util.Assert.notNull(Assert.java:181)
at org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext$AbstractBuilder.put(OAuth2TokenContext.java:219)
at org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext$AbstractBuilder.principal(OAuth2TokenContext.java:152)
at org.springframework.security.oauth2.server.authorization.authentication.OAuth2RefreshTokenAuthenticationProvider.authenticate(OAuth2RefreshTokenAuthenticationProvider.java:171)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
at org.springframework.security.authentication.ObservationAuthenticationManager.lambda$authenticate$1(ObservationAuthenticationManager.java:54)
at io.micrometer.observation.Observation.observe(Observation.java:564)
at org.springframework.security.authentication.ObservationAuthenticationManager.authenticate(ObservationAuthenticationManager.java:53)
< /code>
Ich könnte detailliert eingehen, warum diese Behauptung .Notnull fehlschlägt. Die Kurzversion ist, dass die Spring OAuth2ReFreshTokenAuthenticationProvider das Geräte_ID nicht überprüfen kann, da es sich um ein benutzerdefiniertes Feld handelt, und das verursacht Probleme weiter unten. Aber wirklich, das ist nicht der Punkt. Das Hauptproblem in meinen Augen ist hier, dass der Frühling OAuth2RefreshTokenAuthenticationProvider überhaupt aufgerufen wird. Was ich möchte, ist, dass mein benutzerdefinierter oAuth2RefreshtokenAuthProvider stattdessen und nicht zusätzlich zum Standardanbieter aufgerufen wird, da ich es geschrieben habe. /> Mein OAuth2Config sieht so aus: < /p>
@Configuration
public class OAuth2Config {
@Bean
public SecurityFilterChain oAuth2FilterChain(
HttpSecurity http,
OAuth2PasswordGrantAuthProvider passwordAuthProvider,
OAuth2RefreshTokenAuthProvider refreshTokenAuthProvider,
PasswordGrantAuthenticationConverter passwordGrantAuthenticationConverter,
RefreshTokenAuthenticationConverter refreshTokenAuthenticationConverter
) throws Exception {
OAuth2AuthorizationServerConfigurer configurer =
new OAuth2AuthorizationServerConfigurer();
configurer.tokenEndpoint(token -> token
.accessTokenRequestConverter(
new DelegatingAuthenticationConverter(List.of(
passwordGrantAuthenticationConverter,
refreshTokenAuthenticationConverter
)))
.authenticationProvider(passwordAuthProvider)
.authenticationProvider(refreshTokenAuthProvider)
);
http
.securityMatcher("/oauth2/**")
.with(configurer, (authorizationServer) ->
authorizationServer.oidc(Customizer.withDefaults()))
.authorizeHttpRequests(
auth -> auth
.requestMatchers("/oauth2/token").permitAll()
.anyRequest().authenticated())
.csrf(csrf -> csrf.ignoringRequestMatchers("/oauth2/**"));
return http.build();
}
@Bean
public RegisteredClientRepository registeredClientRepository(
OAuth2Properties oAuth2Properties
) {
TokenSettings tokenSettings = TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofMinutes(
oAuth2Properties.getFirstScope().getAccessTokenTimeToLiveInMinutes()))
.refreshTokenTimeToLive(Duration.ofDays(
oAuth2Properties.getFirstScope().getRefreshTokenTimeToLiveInDays()))
.reuseRefreshTokens(false)
.build();
RegisteredClient firstClient = RegisteredClient.withId(
UUID.randomUUID().toString())
.clientId(MyOAuth2.FIRST_CLIENT_ID)
.clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.scope(MyOAuth2.FIRST_SCOPE)
.tokenSettings(tokenSettings)
.build();
return new InMemoryRegisteredClientRepository(firstClient);
}
@Bean
public OAuth2AuthorizationService authorizationService(
JdbcTemplate jdbcTemplate,
RegisteredClientRepository registeredClientRepository
) {
return new JdbcOAuth2AuthorizationService(
jdbcTemplate, registeredClientRepository);
}
}