Thymeleaf hasAuthority() not correct after logout - spring-mvc

I'm having a bit of a fight with Theymleaf's security implementation.
I have the following spring security configuration:
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login*").permitAll()
.antMatchers("/admin/*").hasAuthority("ADMIN"))
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
// ...
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/home")
.invalidateHttpSession(true);
}
In my HTML I've got something simple set up:
<div sec:authorize="hasAuthority('ADMIN')">You're cool bro!</div>
Which, after logging in works perfectly fine.
Logging out also works perfectly fine and hides the div.
However when I login after which I re-start the server (and thus my session is destroyed) and just reload the page(homepage, base url, without logging in) the div is back and thymeleaf seems to 'cache' the authorities.
Another effect is that I'm still able to visit pages like: /admin/page/
Am I missing something magically here? I'm confused as to what the Thymeleaf hasAuthority() method calls.
I'm thinking about just adding the following, which I feel is rather unclean:
#PreDestroy
private void destroySecurityContext() {
SecurityContextHolder.clearContext();
}

Related

Why got 404 while add project name in entry point url

If run project with Spring security, the entry point URL is:
http://localhost:8099/login
Meanwhile I need to put global project name in entry point URL as follows:
http://localhost:8099/pojoname/login
Here down is my Spring Security Configuration file:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/register", "/registration", "/editProfile").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.usernameParameter("email")
.and()
.logout()
.permitAll();
}
The requested feature is what is know as web context (or formerly Servlet context in a Servlet container work).
This is supported out of the box within Spring Boot and can be switched / activated using the configuration property server.servlet.contextPath with the desired value.
Inside your application.properties file, add below line:
For a version < Spring Boot 2.0:
server.contextPath=/pojoname
For a version > Spring Boot 2.0:
server.servlet.contextPath=/pojoname

hasAuthority method for only POST and PUT httpmethods

Here is my configure code snippet
#Override
public void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/api/user/**").hasAnyAuthority("ROLE_ADMIN")
.antMatchers("/api/status/**").hasAuthority("ROLE_ADMIN").anyRequest()
.authenticated()
.and()
.exceptionHandling()
.accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
In this I need to make ROLE_ADMIN to access only POST and PUT httpmethods. He should not be able to access GET or DELETE httpmethod. I need this to be done in a single .antMatchers() method.
How can I do this?
Have a look at this Spring example project. You can define matchers per path and HTTP verb.
http
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/employees").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/employees/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PATCH, "/employees/**").hasRole("ADMIN")

why spring security makes spring mvc 's postmapping controllder do not work

when I config spring security like this
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Bean
public UserDetailsService userDetailsService(){
return new MyUserDetailsService();
}
#Bean
public MyAuthenticationProvider myAuthenticationProvider(){
MyAuthenticationProvider provider = new MyAuthenticationProvider();
provider.setUserDetailsService(userDetailsService());
return provider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll();
}
}
and then I config my controller like this
#GetMapping("/login")
public String showLoginPage(){
System.out.println("GetMapping");
return "login";
}
#PostMapping("/login")
public void authUser(#RequestParam String username,#RequestParam String password){
// just for testing
System.out.println("PostMapping");
}
and then I visit my login page and enter my username and password, but the console doesn't print "PostMapping", which means the program doesn't go into my method "authUser" with #PostMapping.
Though my program runs successfully, but it makes me quite confuse.I suppose spring security doing some work automatically, but now I have no idea where to add my Authentications to the SecurityContextHolder.
I hope somebody can help and thanks very much
It has done by UsernamePasswordAuthenticationFilter, and the default processing path is Post /login, and the Authentication already exist in SecurityContextHolder, you can get it in controller.
If you want to disable form login, change to this.
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated().and()
.formLogin().disable();
Normally, POST mappings are filtered by CSRFfilters. Although it is not recommended in the production environment, you can disable CSRF filter simply using for learning cases:
http.authorizeRequests().anyRequest().authenticated().and().httpBasic()
.and().logout()
.and().csrf().disable();

Spring MVC 4 Global Basic HTTP Authentication

I need to set up global basic HTTP authentication for a staging server. Nothing fancy. I just want to require username/password to access anything. I also would like to use only Java config. I've experimented with a lot of different solutions, but none of them working. I'm always able to access all resources on the server. This is what I'm doing now:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("Configuring HttpSecurity");
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("Configuring global AuthenticationManagerBuilder");
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
I can see in the logs that these snippets are being executed. As you can see, in the first method, I am requiring that all requests are authenticated. In the second method, I am specifying in memory authentication.
Your SOP statements are getting printed (while container instantiation) because of #Configuration (which is again not required as it is also declared by #EnableWebSecurity). You still need to register the spring security filter chain in your web.xml or MVC initializer class that extends WebMvcConfigurerAdapter or implements WebApplicationInitializer if you wish to use it with the application filter chain. For example (java config as you are looking for the same):
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(
DispatcherType.REQUEST, DispatcherType.ERROR);
container.addFilter("springSecurityFilterChain",
DelegatingFilterProxy.class).addMappingForUrlPatterns(
dispatcherTypes, false, "/*");
where container is an instance of ServletContext.

Spring Security Not Working After Upgrading to 3.2.0.RC2

I just upgraded from Spring Security 3.2.0.RC1 to 3.2.0.RC2. Everything worked fine under RC1. Under RC2, my custom login page no longer works. The login page is just redislayed after clicking the Login button. If invalid credentials (or no credentials) are submitted, it also redisplays without any error message. Before it would correctly display an error message if the credentials were incorrect.
What is interesting is if I change from:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
httpSecurity
.authorizeRequests()
.antMatchers("/restricted/**").hasRole("admin"))
// all requests must be authenticated
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/myLoginUrl.request")
.failureUrl("/myLoginUrl.request?error")
.permitAll()
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/myLoginUrl.request")
;
// #formatter:on
}
to:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
httpSecurity
.authorizeRequests()
.antMatchers("/restricted/**").hasRole("admin"))
// all requests must be authenticated
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/myLoginUrl.request")
;
// #formatter:on
}
The default Spring Security login page is displayed and works. I've looked at the source of the default page and compared it to my custom page and it seems to call the same action with fields with the same names.
If I step through the debugger, I find that in AntPathMatcher.java, public boolean matches(HttpServletRequest request):
String url = getRequestPath(request)
The url returned is "/error" when using my custom login page. getRequestPath() just returns request.getServletPath() appended to request.getPathInfo(). I'm not sure why upgrading to RC2 would cause this to return "/error".
There were three things that I changed that made this work.
1) Added a CSRF hidden field to the form:
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
2) Capitalized POST for the form method:
<form action="login" method="POST">
3) Explicitly added loginProcessingUrl to the configuration:
.formLogin()
.loginPage("/myLoginUrl.request")
.loginProcessingUrl("/login")
.failureUrl("/myLoginUrl.request?error")
.permitAll()

Resources