Spring Security - Filter Ordering and Multiple HttpSecurity - spring

I want two diffrent http configurations to come in depending on the url i am entering. For example, when i type in "localhost:8080/HQ/test_web" i want this configuration to come in.
#Configuration
#Order(1)
public static class FirstWaveFilters extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/HQ/test_web/**").anonymous().and().addFilterBefore(new CustomFilter(),BasicAuthenticationFilter.class);
}
}
But, if its anything else, i want this configuration to come in:
#Configuration
#Order(2)
public static class SecondWaveFilters extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/**").permitAll();
http.csrf().disable();
http.headers().frameOptions().disable();
}
}
I have them set up in the same class as the Spring Security doc suggested:
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailsServiceImpl userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#Configuration
#Order(1)
public static class FirstWaveFilters extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/HQ/test_web/**").anonymous().and().addFilterBefore(new CustomFilter(),BasicAuthenticationFilter.class);
}
}
#Configuration
#Order(2)
public static class SecondWaveFilters extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/**").permitAll();
http.csrf().disable();
http.headers().frameOptions().disable();
}
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
But it does not seem to work. Whatever url i enter, only the CUSTOMFILTER() gets called, so only the first configuration. Basically what i am trying to achieve is, if the user enters the first url i want that customfilter() to be the filter the request has to go through, if its any other url, i want it to go the second configuration and the two filters defined there to be the ones the request must go through. Why is this not working ?

http.antMatcher(...) - means, apply this http and all what is configured here when pattern in antMatcher is met.
http.authorizeRequests()... - defines your permissions, if user hit that endpoint he should has "ADMIN", "logged" etc.
In your FirstWaveFilters you have to start your http with http.antMatcher():
http.antMatcher("/HQ/test_web/**");
http.authorizeRequests().antMatchers("/HQ/test_web/**").anonymous()
.and()
.addFilterBefore(new CustomFilter(),BasicAuthenticationFilter.class);
If you are not add http.antMatcher(...); than that http will intercept all urls and SecondWaveFilters never will be reached.
http.authorizeRequests().antMatchers("/HQ/test_web/**").anonymous() - means that any anonymous user may hit /HQ/test_web/**, but it doesn't say "apply FirstWaveFilters when /HQ/test_web/**" it just mean anyone who hists /HQ/test_web/** may be anonymous.

Related

Spring boot security add custom filter in which chain?

I create a custom filter and use addFilterBefore add the filter in configure method.
#Component
public class JsonWebTokenFilter extends OncePerRequestFilter { ... }
configure method in SecurityConfig which extends WebSecurityConfigurerAdapter
#Autowired
private JsonWebTokenFilter jsonWebTokenFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.antMatcher("/api/**")
.addFilterBefore(jsonWebTokenFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated();
}
Above setting add the jsonWebTokenFilter in both springSecurityChain(internal, additionFilter) and originalChain, is it the correct way or I should add FilterRegistrationBean to avoid the filter add in originalChain?
I need to handler different authication filters with different urls. Without FilterRegistrationBean, all custom filters add in originalChain. I set the different configuration with #Order and separate the url path, but still the requests should pass all custom filters.
#Configuration
#Order(1)
public static class PrivateSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired private PrivateTokenFilter privateTokenFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
//...
.antMatcher("/api/private/**")
.addFilterBefore(privateTokenFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest().authenticated();
}
}
#Configuration
#Order(2)
public static class PublicSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired private JsonWebTokenFilter jsonWebTokenFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
//...
.antMatcher("/api/**")
.addFilterBefore(jsonWebTokenFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest().authenticated();
}
}
To solve the problem, I should add FilterRegistrationBean setting for both custom filters, is that the right way?
spring-boot version: 2.6.6
spring-security : 5.6.2

configure(HttpSecurity http) and configure(AuthenticationManagerBuilder) get ignored with certain annotations in WebSecurityConfigurerAdapter

I'm trying to secure my spring application that has different user roles. While the Authentication part is set and works flawlessly, I realised during the implementation of the Authorisation part that with certain annotations, one of the two overrides methods inside my SecurityConfiguration extends WebSecurityConfigurerAdapter class, gets ignored.
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private WebApplicationContext applicationContext;
private CredentialsService userDetailsService;
#Autowired
private DataSource dataSource;
#PostConstruct
public void completeSetup() {
userDetailsService = applicationContext.getBean(CredentialsService.class);
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login")
.permitAll()
.and()
.formLogin()
.permitAll()
.and()
.httpBasic()
.disable()
.authorizeRequests()
.antMatchers("/admin", "/admin/**")
.hasRole("ADMIN")
.and()
.authorizeRequests()
.antMatchers("/employee", "/employee/**")
.hasRole("EMPLOYEE")
.and()
.authorizeRequests()
.antMatchers("/customer", "/customer/**")
.hasRole("CUSTOMER");
}
#Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(encoder())
.and()
.authenticationProvider(authenticationProvider())
.jdbcAuthentication()
.dataSource(dataSource);
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder(12);
}
}
Now the problem is the following, as it is, this class authenticate my users but has one major drawback: the
configure(final HttpSecurity http) throws Exception {
gets completely ignored.
On the other side though, if I add the #Configuration annotation on top of my class, the
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
gets completely ignored, hence will break the authorisation as it won't be able to call the getUsername() and getPassword on my custom UserDetailsService implementation.
As you can see, I've used a DaoAuthenticationProvider instance as authenticationProvider, since my application retrieve the users/password from an external database.
The quick fix I adopted right now it's the addition of the following method on my main class
#EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
and the use of the #Secured annotation on my restricted controllers. That works, but I'd like to understand why Spring has such strange behaviour and what step can I take to address these problems.
Since you are assigning roles to your users, use the syntax
.antMatchers("/admin", "/admin/**")
.hasRole("ADMIN")
OR
.antMatchers("/admin", "/admin/**")
.hasAuthority("ROLE_ADMIN")
Roles are just stored as authorities with the "ROLE_" prefix.
So the role "ADMIN" is equivalent to the authority "ROLE_ADMIN".
EDIT 1
You can also simplify your configuration to make it clear where everything is coming from.
Since you UserDetailsService (CredentialsService) is already a bean, it will be picked up automatically by Spring Security.
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// The password encoder should be a bean
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder(12);
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login")
.permitAll()
.and()
.formLogin()
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/admin", "/admin/**")
.hasRole("ADMIN")
.and()
.authorizeRequests()
.antMatchers("/manager", "/manager/**")
.hasRole("MANAGER")
.and()
.authorizeRequests()
.antMatchers("/customer", "/customer/**")
.hasRole("CUSTOMER");
}
}

Spring Boot Security Configuration is not working

I have two types of urls one are secured and one are not secured like registration and SignIn
I want "registration" and "SignIn" to byPass security and filters while all the other urls must pass through filters and security.
Following is my Security Configuration code but it is not working.
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
#Configuration
public class AppSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService userDetailsService;
#Autowired
TempTokenGenerator tempTokenGenerator;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(getPasswordEncoder());
}
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("notsecured/signin");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
.antMatchers("/", "**secured/**").authenticated()
.and().logout().permitAll()
.and()
.apply(new TempConfigurer(tempTokenGenerator));
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
what am I missing? What should I do to include "secured" urls in authentication and filters while excluding "unsecured" from authentication and filter.
web.ignoring().antMatchers("notsecured/signin");
seems not working if I put
.anyRequest().authenticated()
with
http.authorizeRequests() to make secured urls work.
and if I put
.antMatchers("/","**/secured/**").authenticated()
with
.anyRequest().permitAll()
it is also not working.
use configure(HttpSecurity http) method to secure your request-endpoints
http.csrf().disable()
.cors().and()
.authorizeRequests()
.antMatchers("/notsecured/**").permitAll()
.antMatchers("/secured/**").fullyAuthenticated()
.and().sessionManagement...
.and().formLogin()
...
use configure(WebSecurity web) method to ignore static resources like images, css,...

Authorization roles Spring-boot Oauth2 ~ Restful API

i'm needing help with this problem...
i can't secure my controllers in my security configuration files. but i can do it in my controller using
#PreAuthorize("hasAuthority('ROLE_ADMIN')")
but this is really annoying, i want to do it from my security conf. files
this is my WebSecurityconfigurerAdapter:
#Configuration
//#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = false)
//#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
//#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
CustomAuthenticationProvider customAuthenticationProvider;
#Autowired
CustomUserDetailsService cuds;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(cuds)
.passwordEncoder(passwordEncoder())
.and()
.authenticationProvider(customAuthenticationProvider);
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").authenticated()
.antMatchers("/test").authenticated()
.antMatchers("/usuarios/**").hasRole("ADMIN");
}
}
and this is my Oauth2Configuration:
#Configuration
public class Oauth2Configuration {
private static final String RESOURCE_ID = "restservice";
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
// Logout
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
//Session management
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
//URI's to verify
.authorizeRequests()
.antMatchers("/oauth/logout").permitAll()
.antMatchers("/**").authenticated()
.antMatchers("/usuarios/**").hasRole("ADMIN");
}
}
i've tried to use authority and roles, but nothings works. some idea what i'm doing wrong?
Well thanks to Yannic Klem i got the answer, was a problem with the order
First on my WebSecurityConfigurerAdapter i set my authentication on "usuarios"
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/usuarios").authenticated();
}
after that in my Oauth2Configuration set my authorizarion with my rol.
#Override
public void configure(HttpSecurity http) throws Exception {
http
// Logout
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
//Session management
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
//URI's to verify
.authorizeRequests()
.antMatchers("/oauth/logout").permitAll()
.antMatchers("/usuarios/**").hasRole("ADMIN");
}
and now all works pretty fine. thank you all!

What is implication of adding #Component to custom Spring Security filter

I have a custom Spring Security filter extending GenericFilterBean.
To do automatic dependency and bean creation I added a #Component annotation.
In my Security config I also register the filter like:
#Autowired
private RestAuthenticationFilter restAuthenticationFilter;
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.addFilterBefore(restAuthenticationFilter, LogoutFilter.class)
Everything works well except that my filter is called twice...
It seems Spring adds filters also automatically to standard filters.
What should be the best approach here?
UPDATE
#Dave is this what you mean? It seems to work.
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application extends WebMvcConfigurerAdapter {
#Autowired
private RestAuthenticationFilter restAuthenticationFilter;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ApplicationSecurity applicationSecurity() {
return new ApplicationSecurity();
}
#Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setEnabled(false);
filterRegistrationBean.setFilter(restAuthenticationFilter);
return filterRegistrationBean;
}
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthenticationFilter restAuthenticationFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.addFilterBefore(restAuthenticationFilter, LogoutFilter.class)
.authorizeRequests()
.anyRequest().authenticated()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// #formatter:on
}
}
}
You need to explicitly register the filter and mark it as "enabled=false" using the FilterRegistrationBean API. Then Spring Security will use it in its chain, but Boot will not try and register it as well.

Resources