I wanted to make sure only admins get into the /settings page.
The problem is that when a normal members access it, it shows error 404.
Shouldn't it be error 403?? The page exists but a member doesn't have authorization to enter it.
What's wrong??
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/settings").hasAuthority("Administrator")
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/dashboard")
.failureUrl("/login?error")
.successHandler(authenticationSuccessHandler)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.exceptionHandling().accessDeniedPage("/errors/error403")
.and()
.csrf().disable();
}
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 trying to implement CSRF token security in my Spring Boot API to learn how to deal with that.
I've followed this tutorial (server side part) and this is my security config:
private static final String[] CSRF_IGNORE = {"/api/login"};
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.ignoringAntMatchers(CSRF_IGNORE)
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(new CustomCsrfFilter(), CsrfFilter.class)
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint() {
})
.and()
.authenticationProvider(getProvider())
.formLogin()
.loginProcessingUrl("/api/login")
.successHandler(new AuthentificationLoginSuccessHandler())
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
.invalidateHttpSession(true)
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
Others things are the same as in the tutorial.
I'm testing with Postman.
When i add the endpoint i want in CSRF_IGNORE, i can see with logger/debug that token stocked, and token from cookie are the same, because the security config's part CustomCsrfFilter.java in .addFilterAfter() is used, but when i remove the endpoint from this CSRF_IGNORE, what i get is a 403, and, logger/debug in the CustomCsrfFilter.java isn't used, so i'm thinking that tokens aren't compared.
I think I missed something and I would like to understand.
If you want to use CSRF with a http only false cookie, why not use Spring Security's built in CookieCsrfTokenRepository? Should simplify your config that way. CustomCsrfFilter seems to be adding a XSRF-TOKEN cookie to the HttpServletResponse, which CookieCsrfTokenRepository does for you.
The default CSRF cookie name when using CookieCsrfTokenRepository is X-CSRF-TOKEN, which is conveniently the default name Angular's HttpClientXsrfModule uses. Of course you can customize that if you need.
So your security config becomes:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and()
.authenticationProvider(getProvider())
.formLogin()
.loginProcessingUrl("/api/login")
.successHandler(new AuthentificationLoginSuccessHandler())
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
.invalidateHttpSession(true)
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
And with Angular, your app module has HttpClientXsrfModule as
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule,
HttpClientXsrfModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
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
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 have a spring security config method. I want a particular method to be chained antMatchers("/**/**").permitAll() only if a condition matches. something like this {dev == true ? .antMatchers("/**/**").permitAll(): ()->{}} . Ofcourse it's not a valid syntax , what is the MOST CONSISE way of doing it . Looking for a menimum coding .
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().disable()
.authorizeRequests()
{dev == true ? .antMatchers("/**/**").permitAll(): ()->{}} //dev only. NEVER enable on prod
.antMatchers("/", "/signup", "/static/**", "/api/sigin", "/api/signup", "**/favicon.ico").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/api/signin")
.successHandler(authSuccessHandler())
.failureHandler(authFailureHandler())
.permitAll()
.and()
.logout()
.permitAll();
}
The only way is to assign the intermediate object to a variable.
WhateverAuthorizeRequestsReturns partial = http
.csrf().disable()
.cors().disable()
.authorizeRequests();
if (dev) // note: you don't need 'dev == true' like you had
{
partial.someOptionalThing();
// if the type is immutable then you need to reassign e.g.:
// partial = partial.someOptionalThing()
}
partial.something()
.somethingElse()
.andTheRest();
if all you want to do is to allow access to certain path based on a boolean value, you can try this :
http
.csrf().disable()
.cors().disable()
.authorizeRequests()
.antMatchers(dev ? "/**/**":"invalid-path").permitAll()
.antMatchers("/", "/signup", "/static/**", "/api/sigin", "/api/signup", "**/favicon.ico").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/api/signin")
.successHandler(authSuccessHandler())
.failureHandler(authFailureHandler())
.permitAll()
.and()
.logout()
.permitAll();