Spring Security : Who passes the AuthenticationManagerBuilder to the WebSecurityConfigurerAdapter configure method? - java

So I am studying Spring Security for a implementation. I came across a piece of code I cannot get my head around. So as per documentation the following method needs to be overridden when we want to customize the AuthenticationManager used by Spring.
protected void configure(AuthenticationManagerBuilder auth) throws java.lang.Exception
My question is who is calling this method and passing the AuthenticationManagerBuilder instance here.
The working examples I see do not create/expose any AuthenticationManagerBuilder bean.
Also , i see the following in the documentation,
protected AuthenticationManager authenticationManager()
throws java.lang.Exception Gets the AuthenticationManager to use.
The default
strategy is if configure(AuthenticationManagerBuilder) method is
overridden to use the AuthenticationManagerBuilder that was passed in.
Otherwise, autowire the AuthenticationManager by type.
The overridden method is a void method and probably that is why I am getting confused more w.r.t what it is doing/should be doing.
Any help/pointers are highly appreciated. I know it works I just cant seem to figure out how.
Much thanks.

Assuming following is the code you came across
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(MyAuthenticationProvider);
}
}
Note that
The WebSecurityConfigurerAdapter provides a convenient base
class for creating a WebSecurityConfigurer instance.
The WebSecurityConfigurerAdapter implementation is a
Configuration as it is annotated with #EnableWebSecurity
Here
#EnableWebSecurity is meta-annotated with #EnableGlobalAuthentication
#Retention(value=RUNTIME)
#Target(value=TYPE)
#Documented
#Import(value={WebSecurityConfiguration.class,org.springframework.security.config.annotation.web.configuration.SpringWebMvcImportSelector.class,org.springframework.security.config.annotation.web.configuration.OAuth2ImportSelector.class})
#EnableGlobalAuthentication
#Configuration
public #interface EnableWebSecurity
and #EnableGlobalAuthentication imports AuthenticationConfiguration
#Retention(value=RUNTIME)
#Target(value=TYPE)
#Documented
#Import(value=AuthenticationConfiguration.class)
#Configuration
public #interface EnableGlobalAuthentication
AuthenticationConfiguration has the following piece of code that registers AuthenticationManagerBuilder as a bean
#Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(
ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {
...
}

Related

How to solve the problem, related to the lack of visibility of the bean?

I'm writing an api in which I wanted to check the performance of the registration, while the application does not want to start because it does not see Bean -> PasswordEncoder.
Do you have any idea what I can do to make it work?
Problem:
Parameter 0 of constructor in com.example.socialplatform.service.AuthorizationService required a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' that could not be found.
Consider defining a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' in your configuration.`
My classes:
SecuritySettings
#EnableWebSecurity
public class SecuritySettings extends WebSecurityConfigurerAdapter {
/* base class security, provides all the default security configuration
which i can override and customize */
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests()
.antMatchers("/api/authorization/**")
.permitAll()
.anyRequest()
.authenticated();
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
}
I tried rebuilding the project, and maven.
If this is a Spring Boot project, one easy way to fix the issue is to put this class under the same package as your main class. It works because the #SpringBootApplication implies the #Configuration and #ComponentScan annotations.
If this is not a SpringBoot project, you have to put the bean in the configuration class. This is a class annotated with #Configuration.

How to overwrite default AccessDeniedHandler in org.springframework.security properly

I have in a given project the circumstance that I need to extend or overwrite the default AccessDeniedHandler of spring.security. The reason is not important, but I need this to be able to implement custom behaviour whenever a MissingCsrfTokenException or InvalidCsrfTokenException is thrown.
My question is: How to override the org.springframework.security.web.access.AccessDeniedHandler class properly?
Meanwhile I figured out 3 ways which seem to be promising:
Set my custom version of AccessDeniedHandlerImpl when configuring spring.security as instance of my class
Set my custom accessDeniedHandler when configuring spring.security and get it as a bean
Override AccessDeniedHandlerImpl with #Component named AccessDeniedHandler and set it as #Primary
I am new to spring framework and unsure how to solve this the best way.
From my understanding as a technician, I would prefer setting my custom AccessDeniedHandler through spring.security configuration (independent of the way I configure it there). Because using a component will require any other developer to look up for the annotations (but maybe I am wrong with this).
Implementing it through spring security configuration
// in the spring security configuration class
protected void configure(final HttpSecurity http) throws Exception {
http
.exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler());
}
or
// in the spring security configuration class
#Bean
public AccessDeniedHandler accessDeniedHandler(){
return new CustomAccessDeniedHandler();
}
protected void configure(final HttpSecurity http) throws Exception {
http
.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
}
As a component override
// in custom AccessDeniedHandler class
#Component
#Primary
public CustomAccessDeniedHandler implements AccessDeniedHandler {
// custom implementation
}
Which will automatically fetch my custom AccessDeniedHandler instead of the default AccessDeniedHandlerImpl defined in org.springframework.security.
Finally the point for me is to figure out, what is the better way to implement this, through configuration or #Component and #Primary.

Why classes extending WebSecurityConfigurerAdapter and not declaring any bean are annotated with configuration?

According to #Configuration documentation:
Indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime, for example:
#Configuration
public class AppConfig {
#Bean
public MyBean myBean() {
//instantiate, configure and return bean ...
}
}
As I remember always I came across classes extending WebSecurityConfigurerAdapter which didn't contain any #Bean methods and were annotated with #Configuration.
It is even in official blog and some examples, see:
https://spring.io/blog/2013/07/03/spring-security-java-config-preview-web-security
#Configuration
#EnableWebSecurity
public class HelloWebSecurityConfiguration
extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
or here: https://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html
#Order(1) 2
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**") 3
.authorizeRequests(authorizeRequests ->
authorizeRequests
.anyRequest().hasRole("ADMIN")
)
.httpBasic(withDefaults());
}
}
Why this classes are annotated with #Configuration even though there are no #Bean methods?
Beans are imported using the secondary "#Enable" annotation
Spring features such as asynchronous method execution, scheduled task execution, annotation driven transaction management, and even Spring MVC can be enabled and configured from #Configuration classes using their respective "#Enable" annotations. See #EnableAsync, #EnableScheduling, #EnableTransactionManagement, #EnableAspectJAutoProxy, and #EnableWebMvc for details.
from EnableWebSecurity:
Add this annotation to an #Configuration class to have the Spring Security configuration defined in any WebSecurityConfigurer or more likely by extending the WebSecurityConfigurerAdapter base class and overriding individual methods:

how #bean and #Autowired actually works?

My configuration:
#Autowired
private PasswordEncoder passwordEncoder;
#Bean
public PasswordEncoder passwordEncoderBean() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
// #Autowired
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(jwtUserDetailsService)
.passwordEncoder(passwordEncoder);
}
this code works fine. But if I remove #Autowired from passwordEncoder, then I must add #Autowired on the configure method. But this rules not apply on authenticationManagerBean() method. Can anyone explain ?
Look at this URL https://spring.io/guides/topicals/spring-security-architecture/
It seems that you Autowire AuthenticationManagerBuilder auth as a #Bean here.
Configure(AuthenticationManagerBuilder auth) so it will work in this case and passwordEncoder is also Autowired.
It seems you use Spring annotations configuration,
If you don't add Spring annotations to method or field, Spring doesn't know it need to be initiated and therefore when used in Spring context ( also without initialize it outside Spring), objects will be null
For security reasons you need to avoid storing the password in plaintext. based on this principle you have this option to encode your password.
In your example, you are using the PasswordEncoder interface:
.passwordEncoder(passwordEncoder);
Using this approach you must inform one implementation. In Spring you can inject this implementation using #Autowired (in the declaration or like your code on the method that use your PasswordEncoder interface).
Just a question... Why you created one implementation?
public PasswordEncoder passwordEncoderBean(){...
I think that this method can be replaced for your Autowired encode interface.

Is #Autowired required on configureGlobal(..) when using #EnableWebSecurity?

In this example there is an #Autowired annotation on the configureGlobal method:
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
Is that necessary or does Spring automatically inject the AuthenticationBuilder on methods annotated with #EnableWebSecurity??
The code snippet is pulled from when-to-use-spring-securitys-antmatcher
According to Spring documentation #EnableWebSecurity is an annotation that only switches off the default web application security configuration in order to let you add some custom features like the configureGlobal.
configureGlobal should be #Autowired in order to get the AuthenticationManagerBuilder bean and define the authentication type for the application.
In conclusion #EnableWebSecurity doesn't inject beans, it only provides a way to customize the web security application.
#EnableWebSecurity

Categories

Resources