Allowing static resources without spring security authentication - spring

Hi I integrated spring security in my web application. My configure() method is overriden as,
#Override
protected void configure( HttpSecurity http ) throws Exception
{
http.cors().and().csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, "/rest/auth/**").permitAll()
.antMatchers("/resources/static/**")
.permitAll().antMatchers("/").permitAll().anyRequest().authenticated().and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
my project structure is as in the image. But spring security is not actually allowing the resource without authentication. In WebSecurityConfig.java if I remove .anyRequest().authenticated(), it is allowing css and js for the browser to render. How to solve this?

Related

SecurityContextHolder.getContext().getAuthentication() returns null

I'm developing Spring boot and security web application with authorization and resource servers enabled. I have defined a set of users with roles assigned to them and have implemented roles based access to rest endpoints. Besides that my application has straightforward UI with web pages. Those pages display the same data that is on rest. I'm trying to implement the same roles based access to pages with ResourceServerConfig#configure and my current code:
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/rest/products/add").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin()
.loginPage("/login.jsf").permitAll()
.loginProcessingUrl("/login")
.defaultSuccessUrl("/login-successful", true)
.and().logout().permitAll();
}
This configuration works perfectly for REST controllers access with bearer token, but authorization with the login form leads to the redirect to the /login-successful and the message
Full authentication is required to access this resourceunauthorized is displayed.
The reason is that SecurityContextHolder.getContext().getAuthentication() for /login-successful request in spite it was correctly initialized in AbstractAuthenticationProcessingFilter#successfulAuthentication at the point of login form post. The same issue with other web pages in my app as well.
What should be added to the above configuration so that make it work for the REST and form login bought ?
Here is indicted that HttpSecurity configuration provided above is enough for authorization with form login to work correctly as far as .anyRequest().authenticated() should pass security context for all the resources in the application.
A similar case is described here but the reason over there is that an url was explicitly ignored in WebSecurity configurer.
The problem was in the fact that I was using deprecated #EnableResourceServer annotation that adds OAuth2AuthenticationProcessingFilter. For the form login authorization flow this is incorrect and that filter was removing authentication object from the SecurityContext. Here is indicated that OAuth2AuthenticationProcessingFilter shouldn't present in the filter chain for the form login authorization flow.
The reason why I was needed #EnableResourceServer annotation is that there are there is the bearer authentication flow in my application alongside with form login.
I replaced #EnableResourceServer annotation and ResourceServerConfigurerAdapter for the bearer authentication flow with Spring Security 5 resource server as http.oauth2ResourceServer() that is in WebSecurityConfigurerAdapter ( see here ). Finally the solution is with the following two WebSecurityConfigurerAdapter-s:
For bearer authorization flow:
#Configuration
#Order(2)
public class SecurityConfigRest extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
NimbusJwtDecoder jwtDecoder = Build custom JWT decoder;
http.csrf().disable()
.requestMatcher(new AntPathRequestMatcher("/rest/**"))
.authorizeRequests()
.mvcMatchers("/products/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.oauth2ResourceServer().jwt().decoder(jwtDecoder);
}`
and for the form login authorization flow:
#Configuration
#Order(1)
#EnableWebSecurity
public class SecurityConfigFormLogin extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http .requestMatcher(new AntPathRequestMatcher("/view/**"))
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/view/login").permitAll()
.defaultSuccessUrl("/view/login-successful", true)
.and().logout()
.logoutUrl("/view/perform_logout")
.logoutSuccessUrl("/view/login");
}
These two WebSecurityConfigurerAdapter-s make it possible to separate those two authorization flows.
As far as Spring Security 5 resource server supports only JWT or Opaque tokens ( see here ) it requires additional configuration. Here is a detailed description of such a configuration for Spring Security 5 resource server.

Spring security redirect to static resources after authentication

Good morning,
I am writing an application using Spring security (latest version) and Spring MVC (latest version).
After securying everything was ok, the form and the controller, together with Spring security configuration worked well and the login was always successful.
Then I added a custom css and some images to display a better graphic, here it came the problem:
everytime I login I am first redirected to the login.css file rather than the homepage, although the login is successful I first see a blank page with the url of the css.
Spring Security configuration
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests()
//configure security for pages
.antMatchers(new String[]{"/login", "/accessDenied"}).permitAll()
.antMatchers("/**").access("hasAnyRole('admin', 'operatore')")
.anyRequest().authenticated()
//creates login form
.and().formLogin().loginPage("/login").loginProcessingUrl("/login")
.defaultSuccessUrl("/home").failureUrl("/accessDenied")
.usernameParameter("id_utente").passwordParameter("password")
//catches exceptions http 403 response
.and().exceptionHandling().accessDeniedPage("/accessDenied");
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
Static resources are under the path /static/css and /static/images.
I read this problem comes from the fact that Spring security redirects you to the last requested url after login, as to resolve the issue I tried using
#Override
public void configure(WebSecurity web)
{
web.ignoring().antMatchers("/static/**");
}
but it didn't work.
Are there any way to solve this problem?
EDIT
I already tried using
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests()
//configure security for pages
.antMatchers("/static/**").permitAll()
.antMatchers(new String[]{"/login", "/accessDenied"}).permitAll()
.antMatchers("/**").access("hasAnyRole('admin', 'operatore')")
.anyRequest().authenticated()
//creates login form
.and().formLogin().loginPage("/login").loginProcessingUrl("/login")
.defaultSuccessUrl("/home").failureUrl("/accessDenied")
.usernameParameter("id_utente").passwordParameter("password")
//catches exceptions http 403 response
.and().exceptionHandling().accessDeniedPage("/accessDenied");
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
But I am anyhow redirected after a successufl login to a 404 page with url "http://localhost:8080/static/css/login.css". In the login page the static resources are corretcly served as the style is how I expect it to be.
EDIT #2
I Edited as Eleftheria Stein-Kousathana said, but it keeps redirecting to the css (showing the code inside this time) instead of the homepage.
The project structure is:
Resource handler is added this way:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
and updated configuration is:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests()
//configure security for pages
.antMatchers("/css/**", "/images/**").permitAll()
.antMatchers(new String[]{"/login", "/accessDenied"}).permitAll()
.antMatchers("/**").access("hasAnyRole('admin', 'operatore')")
.anyRequest().authenticated()
//creates login form
.and().formLogin().loginPage("/login").loginProcessingUrl("/login")
.defaultSuccessUrl("/home").failureUrl("/accessDenied")
.usernameParameter("id_utente").passwordParameter("password")
//catches exceptions http 403 response
.and().exceptionHandling().accessDeniedPage("/accessDenied");
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
Inside login page the css is linked this way:
<link rel="stylesheet" href="<c:url value="/static/css/login.css" />">
With the new antMatchers the result is not a 404 but the code inside the css. By the way, the linked css is not served anymore as style is not displayed correctly if I use the new configuration and "/static/css/login.css" or "/css/login.css", none of the two link work.
Since static/css and static/images are under the static directory, they will be served at /css and /images respectively.
You can permit all requests to those resources in your HTTP security configuration.
http.authorizeRequests()
.antMatchers("/css/**", "/images/**").permitAll()
// ...

Spring security antMatcher not working as expected

I have my custom controller "/my-endpoint" and spring app with the following configuration:
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/my-endpoint", "/health")
.permitAll()
.antMatchers(DENY_RESOURCE_PATTERNS)
.denyAll()
.anyRequest()
.authenticated()
}
It seems that for a unanimous user it working fine. But if I already authorized (using oauth2) and my session(or token) is expired -> spring trying to redirect me to the login page.
I don't want this, I want to allow any user to connect to "/my-endpoint" endpoint.
What I forgot to configure?
The interesting thing, that built-in endpoint "/health" working as expected, even if session is expired.
you can use configure(WebSecurity web). It will bypass the Spring Security Filters and will allow any user to access the endpoint. see HttpSecurity vs WebSecurity
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers(HttpMethod.yourMethod, "/health")
.antMatchers(HttpMethod.yourMethod, "/my-endpoint");
}

Spring's WebSecurity 'ignore' still creating sessions

I want to avoid creating a session when a user requests static resources like css files. Howerver, even after telling WebSecurity to ignore this static resource path, I noticed that all of the responses from my SpringBoot application still have the JSESSIONID cookie. Why?
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/login", "/error").permitAll()
.anyRequest().authenticated(); //all other pages require users to be authenticated
}
I'm using Spring Security to protect my application.... but for requests to these static resources, I don't want a session created or validated.
I found the issue. It was my fault. I'm using Spring Security and extended RequestHeaderAuthenticationFilter. While web.ignoring()... does avoid all Spring Security authentication/authorization checks, it still does run through the custom filters.
In one of my filters I had the following line:
HttpServletRequest req = ((HttpServletRequest) request);
HttpSession session = req.getSession();
I use it to check if a session already exists and if I need to refresh it (too complicated to explain here). But that method, req.getSession() will create a new session if it doesn't already exist. I didn't realize it had that side effect.
Instead, I should be calling: req.getSession(false). This will return a session if it already exists and return null if it doesn't.

Spring Security Unexpected Behaviour for Public Endpoints

I have a Spring HttpSecurity configuration as
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.csrf().disable().httpBasic().and()
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.antMatchers("/secure/**").authenticated()
.antMatchers("/backend/**").authenticated()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
}
It might be stupid for the client to set the Authorization Header for '/public/**' endpoints.
However, I noticed Spring Security attempts to authenticate tries to create an authenticated session for even public requests because the Authorization Header was provided.
Should the HttpSecurity config not override this behaviour?
Answered in the comments:
No it shouldn't... Permit all is something different as not secured at all. For the latter override the 'configure(WebSecurity)' and use the 'ignoring' for no security at all.

Resources