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
Related
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();
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/**");
}
I am using a WebSecurityConfigurerAdapter for my app which use jwt for authentication and everything works fine (first code snippet); what I want to do now is to add another filter only for a specific URL pattern but this filter is called in any case now (second code snippet). Somebody please explain me what am I doing wrong?
This is my code:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and().csrf().disable().httpBasic().disable()
.authorizeRequests()
.antMatchers("/auth").permitAll()
.antMatchers("/v2/api-docs",
"/swagger-resources/**",
"/configuration/**",
"/swagger-ui.html",
"/webjars/**").permitAll()
.antMatchers(
"/",
"/refreshconfig",
"/launchGameForFun/**",
"/*.html",
"/*.gif",
"/favicon.ico",
"/**/*.html",
"/**/*.gif",
"/**/*.css",
"/**/*.js").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new Slf4jMDCFilter(), JwtAuthorizationFilter.class)
.addFilter(new JwtAuthorizationFilter(authenticationManager()));
}
adding this code above not work as expected:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and().csrf().disable().httpBasic().disable()
.authorizeRequests()
.antMatchers("/auth").permitAll()
.antMatchers("/v2/api-docs",
"/swagger-resources/**",
"/configuration/**",
"/swagger-ui.html",
"/webjars/**").permitAll()
.antMatchers(
"/",
"/refreshconfig",
"/launchGameForFun/**",
"/*.html",
"/*.gif",
"/favicon.ico",
"/**/*.html",
"/**/*.gif",
"/**/*.css",
"/**/*.js").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new Slf4jMDCFilter(), JwtAuthorizationFilter.class)
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.antMatcher("/*/*wager")
.addFilterAfter(new MultiReadServletFilter(), JwtAuthorizationFilter.class)
.addFilterAfter(new XauthFilter(), MultiReadServletFilter.class);
}
To be more clear: I want Slf4jMDCFilter and JwtAuthorizationFilter to be invoked for every URL (/*/*wager included) and MultiReadServletFilter and XauthFilter to be invoked only for /*/*wager. Obviously permitAll URLs are excluded in both cases.
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.
I want to disable all of the filters which Spring (or me) provide for the "/login" url. I've written this code, but Spring seems to ignore this lines of code. What am I doing wrong?
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors()
.and().exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests()
.antMatchers(HttpMethod.GET, AUTH_WHITELIST).permitAll()
.antMatchers("/admin").hasAuthority("ADMIN")
.anyRequest().authenticated()
.and().requestCache().disable()
.logout().and().rememberMe().disable()
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/login");
}
You need to specify where is your login form in httpSecurity, try something like this
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, AUTH_WHITELIST).permitAll()
.antMatchers("/admin").hasAuthority("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}