Reputation: 51
for some reason the authenticationManager is not being added to the context, that's what I imagine, because I'm getting an error: "Factory method 'authorizationServerSecurityFilterChain' threw exception with message: authenticationManager cannot be null"
I've tried to add the line, but I get that authenticationManager as a parameter cannot be resolved symbol.
http.authenticationManager(authenticationManager);
I don't know if I'm forgetting to do something in this spring security oauth configuration. The Authorization server version (1.4.1) spring boot (3.4.2) and Java 17. I appreciate any help.
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService(UserRepository userRepository) {
return new CustomUserDetailsService(userRepository);
}
@Bean
public AuthenticationManager authenticationManager(
UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder);
return new ProviderManager(authProvider);
}
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer();
http.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.csrf(AbstractHttpConfigurer::disable)
.formLogin(Customizer.withDefaults());
authorizationServerConfigurer.configure(http);
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/api/auth/register").permitAll()
.anyRequest().authenticated()
)
.csrf(csrf -> csrf.ignoringRequestMatchers("/api/auth/register"))
.formLogin(AbstractHttpConfigurer::disable)
.httpBasic(AbstractHttpConfigurer::disable);
return http.build();
}
... more code
Upvotes: 0
Views: 105
Reputation: 51
Indeed, as @RoarS. said, I was loading unnecessary things, probably mixing setups from previous versions and my own confusion. This is a setup that worked for me:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final DataSource dataSource;
private final PasswordEncoder passwordEncoder;
public SecurityConfig(DataSource dataSource) {
this.dataSource = dataSource;
this.passwordEncoder = new BCryptPasswordEncoder();
}
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, authorizationServer ->
authorizationServer.oidc(Customizer.withDefaults()) // Habilitar OpenID Connect
)
.authorizeHttpRequests(authorize ->
authorize.anyRequest().authenticated()
)
.exceptionHandling(exceptions ->
exceptions.defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint("/login"),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
)
);
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize ->
authorize.requestMatchers("/api/auth/register").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
return new JdbcUserDetailsManager(dataSource);
}
@Bean
public PasswordEncoder passwordEncoder() {
return passwordEncoder;
}
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("oidc-client")
.clientSecret("{bcrypt}" + passwordEncoder.encode("secret")) // Usar BCrypt
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/oidc-client")
.postLogoutRedirectUri("http://127.0.0.1:8080/")
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.build();
return new InMemoryRegisteredClientRepository(oidcClient);
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
private static KeyPair generateRsaKey() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().build();
}
}
Upvotes: 0
Reputation: 11144
I can't see that I have a custom AuthenticationManager
bean in my authorization server.
I suspect there might be several issues here, but let's start with what I have and see if you can use that as a base. Code is based on this part of Spring Authorization Server docs.
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
var authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, authorizationServer ->
authorizationServer.oidc(Customizer.withDefaults())
)
.authorizeHttpRequests(authorize ->
authorize.anyRequest().authenticated()
)
// Redirect to the login page when not authenticated from the
// authorization endpoint
.exceptionHandling(exceptions -> exceptions
.defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint("/login"),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
)
);
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
// remove this if you don't have actuator endpoints
.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll()
.anyRequest().authenticated()
)
// replace this with your URL
.logout(logout -> logout.logoutSuccessUrl("http://localhost:3000/"))
.formLogin(Customizer.withDefaults());
return http.build();
}
}
Upvotes: 1