Spring Security exclude url - spring-boot

I added two filter like below
JwtUsernameAndPasswordAuthenticationFilter
JwtTokenVerifier
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/makestory").hasAnyRole("OLDBIE")
.and()
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter())
.addFilterAfter(new JwtTokenVerifier(), JwtUsernameAndPasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(new LoginErroHandler());
}
and but I want to exclude some of urls like /main/, /main/story/, etc
so I was expected that /main/, /main/story/ urls don't need to be censored
so I added below code
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/main/**");
}
but there's a problem. A request has been passed to JwtUsernameAndPasswordAuthenticationFilter class
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException{
log.info("JwtUsernameAndPasswordAuthenticationFilter is actived");
}
}
I don't want to a request be passed into JwtUsernameAndPasswordAuthenticationFilter
what should I do?

Update:
_____ Only to bypass Security _____
You may add matchers and permit before asking authentication for any other request
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.
.
.
.antMatchers("/main/**")
.permitAll()
.anyRequest()
.authenticated()
.
.
}
this part may not be necessary only for bypass auth.
public void configure(WebSecurity web)
______ apply filter to only matching _______
#Bean
public FilterRegistrationBean<JwtUsernameAndPasswordAuthenticationFilter> loggingFilter() {
FilterRegistrationBean<JwtUsernameAndPasswordAuthenticationFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new JwtUsernameAndPasswordAuthenticationFilter());
registrationBean.addUrlPatterns("/home**", "/test", "/sample/**");
return registrationBean;
}

Related

Hww to bind two SecurityFilterChain respectively? [duplicate]

I am trying to use Spring Security and I have a use case where I want different login pages and different set of URLs to be secured.
Here is my configuration:
#Configuration
#Order(1)
public static class ProviderSecurity extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/**").access("hasRole('BASE_USER')")
.and()
.formLogin()
.loginPage("/admin/login").permitAll()
.defaultSuccessUrl("/admin/home")
.failureUrl("/admin/login?error=true").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.and()
.csrf()
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
#Configuration
#Order(2)
public static class ConsumerSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/consumer/login").permitAll()
.antMatchers("/consumer/**").access("hasRole('BASE_USER')")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/consumer/login").permitAll()
.defaultSuccessUrl("/consumer/home")
.failureUrl("/consumer/login?error=true").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.and().csrf()
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
These classes are inner classes of another class MultipleHttpSecurityConfig that has annotation #EnableWebSecurity.
The security for admin/** is working fine, but none of the consumer/** pages are secured, no redirection is happening for login page. I've searched for other answers but none worked.
Look at the Spring Security Reference:
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) { 1
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Configuration
#Order(1) 2
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**") 3
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}
#Configuration 4
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
}
1 Configure Authentication as normal
2 Create an instance of WebSecurityConfigurerAdapter that contains #Order to specify which WebSecurityConfigurerAdapter should be considered first.
3 The http.antMatcher states that this HttpSecurity will only be applicable to URLs that start with /api/
4 Create another instance of WebSecurityConfigurerAdapter. If the URL does not start with /api/ this configuration will be used. This configuration is considered after ApiWebSecurityConfigurationAdapter since it has an #Order value after 1 (no #Order defaults to last).
Your second configuration is not used, because your first configuration matches /** (no antMatcher configured). And your first configuration restricts only /admin/**, all other URLs are permitted by default.
Your first WebSecurityConfigurerAdapter's
http
.authorizeRequests()
matches all the URLs, limit it to only URLs start with /admin by using antMatcher:
#Configuration
#Order(1)
public static class ProviderSecurity extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/admin/**")
.authorizeRequests()
.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/**").access("hasRole('BASE_USER')")
.and()
...

Spring Resource Server Multi-tenancy with BasicAuth

So I tried Resource Server Multi-tenancy using Spring docs and
everything works fine, I can pass two different token to access my resource. My question is how do I add BasicAuth functionality to this. I want my resource to be accessible by either of the oauth2 tokens or BasicAuth. I have individual solutions but I am not able to combine both for some reason.
Working solution -> Resource server Multi-tenancy
#EnableWebSecurity
#Order(1)
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.httpBasic()
.disable()
.authorizeRequests(auth -> auth
.anyRequest().authenticated()
).oauth2ResourceServer(oauth2ResourceServer -> {
oauth2ResourceServer.authenticationManagerResolver(this.authenticationManagerResolver);
});
}
//...
Working Solution -> Oauth and BasicAuth both to access same resource
I came across this solution which does this
https://stackoverflow.com/a/36243650/2188126
#EnableWebSecurity
#Order(1)
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requestMatcher(new BasicRequestMatcher())
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(new OAuth2AuthenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
//...
Here's what I have tried(and few other variations) but doesn't work. -> Multi-tenancy + Basic Auth
#EnableWebSecurity
#Order(1)
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requestMatcher(new BasicRequestMatcher())
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2ResourceServer(oauth2ResourceServer -> {
oauth2ResourceServer.authenticationManagerResolver(this.authenticationManagerResolver);
})
.httpBasic()
.authenticationEntryPoint(new OAuth2AuthenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
//...
Here's my resource server config file
#Configuration
#EnableResourceServer
public class Oauth2SecurityConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(AUTH_WHITELIST).permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated();
}
}

spring security 2 login form call one another without authenticating

I am writing a spring security code with 2 login forms and 2 login URLs. The problem is that when I pres on sign in button on any login form without even true authenticating it directs me to the other login form. When I try the other login form the same happens. If someone has any clue is welcome to comment.
My code is:
#Order(1)
#Configuration
#EnableWebSecurity
//#Order(Ordered.LOWEST_PRECEDENCE)
public class SecurityConfigurationAdmin extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/adminlogin*")
.authorizeRequests()
.antMatchers(
"/login2",
"/login",
"/registration**",
"/js/**",
"/css/**",
"/img/**").permitAll()
.antMatchers("/adminlogin*").hasRole("USER2")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login2").permitAll()
// .loginProcessingUrl("/login22")
.usernameParameter("username2")
.passwordParameter("password2")
.successForwardUrl("/adminlogin")
.defaultSuccessUrl("/adminlogin",true)
// .failureUrl("/login2")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout")
.permitAll();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("{noop}admin").roles("USER2");
}
and :
#Order(2)
#Configuration
#EnableWebSecurity
//#Order(Ordered.HIGHEST_PRECEDENCE)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/librarianlogin*")
.authorizeRequests()
.antMatchers(
"/login",
"/login2",
"/registration**",
"/js/**",
"/css/**",
"/img/**").permitAll()
.antMatchers("/librarianlogin").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
// .loginProcessingUrl("/login1")
.successForwardUrl("/librarianlogin")
.defaultSuccessUrl("/librarianlogin",true)
// .failureUrl("/login")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout")
.permitAll();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
}
I m sure that everything that is missing is in the WebSecurityConfigurerAdapter classes since when I compile the code separately from the 2 log in forms they work perfectly. When i combine them together something goes wrong.
Looking at your configuration, it appears that you want to have two separate user bases, one for administrators, and one for librarians. You are using different login pages in order to know which is which.
To do this, you need to have multiple filter chains, which is how you've already begun. I'd suggest some tweaks, though.
First, the top-level antMatcher call is for segmenting out your application. For example, it's common for all admin pages to be served under the /admin path. In that case, you can do:
#Order(1)
#Configuration
public class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/admin/**")
.authorizeRequests((authz) -> authz
.mvcMatchers("/error").permitAll()
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/admin/login").permitAll()
);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
UserDetailsService adminUsers = // ... construct
auth.userDetailsService(adminUsers);
}
}
for the admin's part of the site, and:
#Order(2)
#Configuration
public LibrarianSecurityConfig extends WebSecurityConfigurerAdatper {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests((authz) -> authz
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login").permitAll()
);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
UserDetailsService users = // ...
auth.userDetailsService(adminUsers);
}
}
for the librarian part.
Some things to keep in mind:
Order matters. When you have multiple filter chains, Spring Security will pick the first chain whose matcher matches the request path. So, /admin/** goes first since it is a smaller expression than /**
You need to configure your front end to support CSRF since Spring Security expects CSRF tokens by default for any POST request
Permitting /error is important at least while debugging your login setup since otherwise any errors will get swallowed behind the authentication wall
You can find the complete code in this sample.

Spring Security Multiple HTTPSecurity with Different User Details Services Not Working in Spring Boot

I have two types of users: Application User and End User and I have separate tables for these. Now, I want to apply security on these two tables.
I provided custom implementation of UserDetailsService for Application users:
#Component("applicationUserDetailsService")
public class ApplicationUserDetailsService implements UserDetailsService {}
And, I provided another second custom implementation of UserDetailsService for End users:
#Component("endUserDetailsService")
public class EndUserDetailsService implements UserDetailsService {}
Now, in the following code snippet, I have registered two endpoints for both type of users. I have injected both implementation of UserDetailsService and registered by #Overide configure(AuthenticationManagerBuilder auth) method for both application and end user separately.
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#Import(SecurityProblemSupport.class)
public class SecurityConfiguration {
// Injected via Constructor Injection
private final EndUserDetailsService endUserDetailsService;
private final ApplicationUserDetailsService applicationUserDetailsService;
#Configuration
#Order(1)
public class ApplicationUserSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.csrf()
.disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.antMatcher("/api/customer/**")
.authorizeRequests()
.antMatchers("/api/customer/authenticate").permitAll()
.antMatchers("/api/customer/**")
.authenticated()
.and()
.apply(securityConfigurerAdapter());
// #formatter:on
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(endUserDetailsService);
}
}
//no #Order defaults to last
#Configuration
public class EndUserSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.csrf()
.disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.apply(securityConfigurerAdapter());
// #formatter:on
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(applicationUserDetailsService);
}
}
private JWTConfigurer securityConfigurerAdapter() {
return new JWTConfigurer(tokenProvider);
}
}
And, I'm trying to authenticate the user like this:
//Injected via Constructor Injection
private final AuthenticationManagerBuilder authenticationManagerBuilder;
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword());
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
When the above code snippet is executed, I get the Null Pointer Exception because authenticationManagerBuilder.getObject() returns NULL. And when I use just when implementation of UserDetailService with #Component("userDetailsService") and not set UserDetailService in security config like auth.userDetailsService("..."), it works fine but by that way I can't achieve authentication from multiple tables.
What I want to Achieve:
In simple words, I want spring security to authenticate user from two tables.
requestMatchers() is the call that you need as it allows you to isolate adapters by URL:
#Order(1)
#EnableWebSecurity
class EndUserConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/customer/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("CUSTOMER")
.and()
.apply(yourJointConfigurations());
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(endUserDetailsService);
}
}
Regarding calling the AuthenticationManager directly, it would be ideal if you could rely on the existing filter chain to do the work for you. For example, since you are stateless, HTTP Basic might be a better fit for you, which you could apply to both configurations, instead of trying to have a dedicated /authenticate endpoint.

Spring LogoutSuccessHandler not invoked

I'm using spring-boot (1.3.5) + oauth2 (spring-cloud-starter-oauth2). I would like to test some LogoutSuccessHandler but I'm unable to invoke it.
This is my security configuration:
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private LogoutHandler logoutHandler;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.httpBasic().disable()
.authorizeRequests()
.antMatchers("/index.html", "/", "/resources/**", "/css/**").permitAll()
.anyRequest().authenticated();
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessHandler(logoutHandler);
//.invalidateHttpSession(true).deleteCookies("JSESSIONID", "SESSION");
}
}
This is my logoutHandler
#Component
public class LogoutHandler extends AbstractAuthenticationTargetUrlRequestHandler implements LogoutSuccessHandler {
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
setDefaultTargetUrl("/");
super.handle(request, response, authentication);
}
}
When I debug the application and put the breakpoint to the logoutHandler it's never invoked. Am I missing something in this configuration?
Thanks
Update your configure method a little bit. You don't have to use AntPathRequestMatcher to match logout url.
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.httpBasic().disable()
.authorizeRequests()
.antMatchers("/index.html", "/", "/resources/**", "/css/**").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(logoutHandler)
//.deleteCookies("JSESSIONID", "JSESSIONID")
//.invalidateHttpSession(true)
.permitAll();
}

Resources