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/**");
}
Related
In the configuration below I think I have not done anything wrong. The Urls that I have allowed for all are redirecting me to login page. Same problem with users having role USER.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/**").hasRole("ADMIN")
.antMatchers("/new/**", "/edit/**", "/create/**", "/save/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/", "/registration/**", "/view/**",).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/")
.and()
.logout().invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/loggingOut").permitAll();
}
If you can provide any resource which can help to understand better. I am new to spring, any help would be much appreciated.
I think the problem is with your Role Hierarchy. Try this.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/new/**", "/edit/**", "/create/**", "/save/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/", "/registration/**", "/view/**",).permitAll()
.antMatchers("/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/")
.and()
.logout().invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/loggingOut").permitAll();
}
If this did not work please try with different combinations.
This article explains the Role Hierarchy, It can help you.
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 am using spring boot application with spring security using jwt.
login user is having the admin access, and he is trying to delete the user, it is accepting with the following code
angular:-
delete(userId: number) {
debugger;
return this.http.delete(`/api/v1/admin/deleteUser/${userId}`);
}
SpringSecurityConfig.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.headers()
.frameOptions().sameOrigin()
.and()
.authorizeRequests()
.antMatchers("/api/v1/authenticate", "/api/v1/register","/api/v1/basicauth").permitAll()
.antMatchers("/").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")//only admin can access this
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/home")
.failureUrl("/login?error")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.deleteCookies("my-remember-me-cookie")
.permitAll()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
controller.java
#DeleteMapping(path = "/admin/deleteUser/{userId}")
public ResponseEntity<?> deleteUser(HttpServletRequest request,#PathVariable int userId) {
authenticationService.deleteUser(userId);
return ResponseEntity.ok((""));
}
but in my application user login with ROLE_USER, he is also able to access that method, how to restrict access upto ROLE_ADMIN only.
Modify the ant matchers to match the expected URL.
.antMatchers("/api/v1/admin/**").hasRole("ADMIN") //only admin can access this
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
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();
}