Spring 2 WebSecurity different Authentifications not working as intended - java

I'm currently struggling with the WebSecurityConfig from Spring. I do have a service which is protected with an IPAuthProvider (only whitelisted IPs can access the service). For monitoring reasons I exposed a /prometheus endpoint and I don't want the IPAuth there but only Basic Auth. However, the following code adds IPAuth AND Basic Auth to the /prometheus endpoint.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig {
#Order(2)
#Configuration
public static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final IpAuth ipAuth;
private final CustomAuthenticationFailureHandler failureHandler;
private final CustomAuthenticationSuccessHandler successHandler;
public WebSecurityConfig(IpAuth ipAuth,
CustomAuthenticationFailureHandler failureHandler, CustomAuthenticationSuccessHandler successHandler) {
this.ipAuth = ipAuth;
this.failureHandler = failureHandler;
this.successHandler = successHandler;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/refresh")
.permitAll()
.antMatchers("/css/*.css", "/js/*.js")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/loginPage")
.failureHandler(failureHandler)
.successHandler(successHandler)
.and()
.logout()
.logoutUrl("/logoutPage")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.csrf()
.disable();
}
#Override
public void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(ipAuth);
}
}
#Order(1)
#Configuration
public static class PrometheusConfig extends WebSecurityConfigurerAdapter{
private final PrometheusEntryPoint prometheusEntryPoint;
public PrometheusConfig(SystemConfig systemConfig, PrometheusAuthEntryPoint prometheusAuthEntryPoint){
this.prometheusAuthEntryPoint=prometheusAuthEntryPoint;
this.systemConfig = systemConfig;
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.antMatcher("/prometheus")
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(prometheusAuthEntryPoint);
}
}
}
Any help or hint is highly appreciated, I
m really stuck at this point.
Thanks in advance!

You can configure your WebSecurityConfig in such way that processes all the request that do not start with /prometheus.
httpSecurity
.regexMatcher("^(?!/prometheus/).*$")
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/refresh")
.permitAll()
.antMatchers("/css/*.css", "/js/*.js")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/loginPage")
.failureHandler(failureHandler)
.successHandler(successHandler)
.and()
.logout()
.logoutUrl("/logoutPage")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.csrf()
.disable();

Related

how to ignore request parameters in spring security

I want to implement AuthenticationFailureHandler with the following configuration:
// Auth failure handler
#Bean
public AuthenticationFailureHandler appAuthenticationFailureHandler() {
ExceptionMappingAuthenticationFailureHandler failureHandler = new ExceptionMappingAuthenticationFailureHandler();
Map<String, String> failureUrlMap = new HashMap<>();
failureUrlMap.put(BadCredentialsException.class.getName(), "/login?error");
failureUrlMap.put(AccountExpiredException.class.getName(), "/login?expired");
failureUrlMap.put(LockedException.class.getName(), "/login?locked");
failureUrlMap.put(DisabledException.class.getName(), "/login?disabled");
failureHandler.setExceptionMappings(failureUrlMap);
return failureHandler;
}
and in class SecurityConfiguration extends WebSecurityConfigurerAdapter I have:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/register", "/confirm").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
// username password
.usernameParameter("username")
.passwordParameter("password")
// success and failure handlers
.successHandler(appAuthenticationSuccessHandler())
.failureHandler(appAuthenticationFailureHandler())
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.invalidateHttpSession(true)
.clearAuthentication(true)
.permitAll()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler())
;
}
with this, all mentioned above is not redirecting to relevant failure URL, but if I remove
.anyRequest()
.authenticated()
then it is being redirected to relevant failure URL, but that is not good practice now the question is how I can configure the configure() to ignore /login?request parameter and implement further logic accordingly?
As I understand, the issue is that urls like "/login?.*" are available only after authorization. According to spring examples, you can exclude paths from authorized access with the following code in Config file:
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}

Can't configure antMatchers after anyRequest (Multiple antMatcher)

I am trying to configure Spring Security and get this following error:
Caused by: java.lang.IllegalStateException: Can't configure antMatchers after anyRequest
This is my SecurityConfig class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encodePWD());
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.csrf().disable();
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/rest/**").permitAll()
.anyRequest().authenticated()
.and()
.authorizeRequests()
.antMatchers("/secure/**").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
http
.authorizeRequests()
.antMatchers("/login").permitAll();
}
#Bean
public BCryptPasswordEncoder encodePWD(){
return new BCryptPasswordEncoder();
}
}
I already tried call httpSecurityauthorizeRequests().anyRequest().authenticated() as mentioned here,
still didn't work
...any suggestion would be helpfull.
Modify the rule as follows . .anyRequest().authenticated() to be used only once .
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/rest/**").permitAll()
.and()
.authorizeRequests()
.antMatchers("/secure/**").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
It might help someone for same kind of Exception
Here is my code:-
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/**")
.hasAnyRole()
.and()
.formLogin();
}
I just removed the call to super class :- super.configure(http); It worked for me. Just remove that line.
Authenticated should come last
httpSecurity.csrf().disable()
.cors()
.and().authorizeRequests()
.antMatchers("xyz").permitAll()
.antMatchers("abc")
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.cors()
.disable()
.authorizeRequests()
.antMatchers("/login", "/user/createUser")
.permitAll()
.antMatchers(HttpMethod.OPTIONS)
.permitAll()
.anyRequest()
.authenticated()
.and().exceptionHandling()
.authenticationEntryPoint(unautorizeHandler)
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}

Override Spring Security configure(HttpSecurity) when overridden in a Maven dependency

I have a Maven Spring Boot 2 with Spring Security project. One of the maven dependencies extends WebSecurityConfigurerAdapter. e.g.,
public class MyConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.and()
.csrf()
.and()
.formLogin()
.permitAll()
.successHandler(myLoginHandler)
.failureHandler(formAuthFailureHandler)
.and()
.logout()
.permitAll()
.logoutRequestMatcher(new AntPathRequestMatcher(logoutUrl()))
.logoutSuccessUrl(logoutSuccessUrl())
.and()
.authorizeRequests()
.antMatchers(publicRoutes())
.permitAll()
.antMatchers(HttpMethod.POST).authenticated()
.antMatchers(HttpMethod.PUT).authenticated()
.antMatchers(HttpMethod.PATCH).authenticated()
.antMatchers(HttpMethod.DELETE).denyAll()
.anyRequest()
.authenticated();
}
}
The problem is in this application I need to override successHandler() and add a logout handler like this logout().addLogoutHandler(myLogoutHandler).
Is it possible to just update these bits, or will I need to define the whole chain again? Maybe something like this,
public class AnotherConfig extends MyConfig {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.and()
.csrf()
.and()
.formLogin()
.permitAll()
.successHandler(myLoginHandler)
.failureHandler(formAuthFailureHandler)
.and()
.logout()
.addLogoutHandler(myLogoutHandler)
.permitAll()
.logoutRequestMatcher(new AntPathRequestMatcher(logoutUrl()))
.logoutSuccessUrl(logoutSuccessUrl())
.and()
.authorizeRequests()
.antMatchers(publicRoutes())
.permitAll()
.antMatchers(HttpMethod.POST).authenticated()
.antMatchers(HttpMethod.PUT).authenticated()
.antMatchers(HttpMethod.PATCH).authenticated()
.antMatchers(HttpMethod.DELETE).denyAll()
.anyRequest()
.authenticated();
}
}
I was hoping there might be a single setter for these two values somewhere.
Thanks
You need to set order of overriding one to higher that overridden one.
#Order(Ordered.LOWEST_PRECEDENCE - 1)
public class AnotherConfig extends MyConfig {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.and()
.csrf()
.and()
.formLogin()
.permitAll()
.successHandler(myLoginHandler)
.failureHandler(formAuthFailureHandler)
.and()
.logout()
.addLogoutHandler(myLogoutHandler)
.permitAll()
.logoutRequestMatcher(new AntPathRequestMatcher(logoutUrl()))
.logoutSuccessUrl(logoutSuccessUrl())
.and()
.authorizeRequests()
.antMatchers(publicRoutes())
.permitAll()
.antMatchers(HttpMethod.POST).authenticated()
.antMatchers(HttpMethod.PUT).authenticated()
.antMatchers(HttpMethod.PATCH).authenticated()
.antMatchers(HttpMethod.DELETE).denyAll()
.anyRequest()
.authenticated();
}
}
Why Ordered.LOWEST_PRECEDENCE - 1?
Because the default order is Ordered.LOWEST_PRECEDENCE as set for overridden class.
Or you can set it a specific number for overridden.

Spring Security not serving static content

I'm trying to get spring security to allow the serving of static files like .css .js etc. without need to login first.
I've tried creating MVC config with resource handler and changing rules in spring security config, but nothing seems to be working.
MvcConfig.java:
#Configuration
#EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**")
.addResourceLocations("/assets/");
}
}
SecurityConfig.java:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/assets/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/assets/**");
}
}
When I go to http://localhost:8080/assets/js/particles.min.js I'm expecting it to return the file contents but every time I try links like localhost:8080/assets/* it returns the content of login.html
My assets files
My project files
Supposing that your static files are under src/main/resources:
There are two main pieces to configure:
Implement the WebMvcConfigurer interface to discover your static resources:
#Configuration
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern("/assets/**")) {
registry.addResourceHandler("/assets/**")
.addResourceLocations("/assets/");
}
}
}
Setup your security configuration to allow static resources (such as CSS, JavaScripts and images) to be publicly accessible:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// Your settings
#Override
protected void configure(HttpSecurity http) throws Exception {
// Your AuthN handlers and filter chain...
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers("/img/**").permitAll()
.antMatchers("/js/**").permitAll()
.anyRequest().authenticated();
// Logout handler...
}
}
Supposing that you have a CSS file as follows:
src/main/resources/assets/css/layout.css
The web server will make it accessible at:
http://<root_url>:<port>/css/layout.css
Try to change to:
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/assets/").permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
web.ignoring().antMatchers("/assets/**");
The statement above will tell spring security to Ignore any request that starts with “/assets/”. So if i were you, i will remove all the following configuration:
.antMatchers("/", "/assets/**")
.permitAll()
fom the configure(HttpSecurity http) method.

Spring security configuration: enable/disable authentication

my question is like this:
I want to disable and enable authentication through configuration in class which extends WebSecurityConfigurerAdapter. I have test which expects that status is unauthroized if there is no login info provided. This is configuration class:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
public static final String USER = "workshop-user";
public static final String ADMIN = "workshop-admin";
#Value("${WORKSHOP_USER_PASSWORD:user}")
private String userPassword;
#Value("${WORKSHOP_ADMIN_PASSWORD:admin}")
private String administratorPassword;
#Value("${features.security.disable}")
private boolean securityDisable;
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder(9);
}
#Override
#Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser(USER)
.password(encoder().encode(userPassword))
.roles("CLIENT_APP")
.and()
.withUser(ADMIN)
.password(encoder().encode(administratorPassword))
.roles("CLIENT_APP", "ADMINISTRATOR");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
if(!securityDisable) {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**/import").hasRole("ADMINISTRATOR")
.antMatchers("/api-docs/**", "/swagger-resources/**", "/v2/api-docs", "/**/favicon.ico", "/webjars/**", "/api/admin/health").permitAll()
.anyRequest().permitAll()
//replace .permitAll() with .authenticated() for authentiaction
//replace .authenticated() with .permitAll() for disabling security
.and()
.csrf().disable()
.headers().disable()
.httpBasic();
}
else{
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**/import").hasRole("ADMINISTRATOR")
.antMatchers("/api-docs/**", "/swagger-resources/**", "/v2/api-docs", "/**/favicon.ico", "/webjars/**", "/api/admin/health").permitAll()
.anyRequest().authenticated()
//replace .permitAll() with .authenticated() for authentiaction
//replace .authenticated() with .permitAll() for disabling security
.and()
.csrf().disable()
.headers().disable()
.httpBasic();
}
}
and this is my flag from application.properties
features.security.disable = true
I have tried to find another way to do it through configuration but couldn't come to another answer. The thing is that i know it is very simple becaues of if/else statement. One is authenticated and the other permitAll entries. Do you know is there a way that uses "better aproach" which does not pollute code with duplication like this? I tried to look in documentation and other posts but couldn't find any relevant information for me.
You can create two security configurations
#Configuration
#Profile("prod")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**/import").hasRole("ADMINISTRATOR")
.antMatchers("/api-docs/**", "/swagger-resources/**", "/v2/api-docs", "/**/favicon.ico", "/webjars/**", "/api/admin/health").permitAll()
.anyRequest().authenticated()
//replace .permitAll() with .authenticated() for authentiaction
//replace .authenticated() with .permitAll() for disabling security
.and()
.csrf().disable()
.headers().disable()
.httpBasic();
}
}
#Configuration
#Profile("test")
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**/import").hasRole("ADMINISTRATOR")
.antMatchers("/api-docs/**", "/swagger-resources/**", "/v2/api-docs", "/**/favicon.ico", "/webjars/**", "/api/admin/health").permitAll()
.anyRequest().permitAll()
//replace .permitAll() with .authenticated() for authentiaction
//replace .authenticated() with .permitAll() for disabling security
.and()
.csrf().disable()
.headers().disable()
.httpBasic();
}
}
Run based on your requirement
-Dspring.profiles.active=prod
-Dspring.profiles.active=test

Categories