How to use use `with(user(` when using Spring Session/Security in REST environment - spring

Is it possible to pouplate a Test User with SecurityMockMvcRequestPostProcessors.user when using Spring Session with HeaderHttpSessionStrategy.
I tried something like:
mockMvc.perform(
get(URL)
.with(user("user").password("pwd").roles("USER", "ADMIN")))
.andExpect(status().isOk())
But it returns a 403.
Without the with(user( I get the a 401 so there is a difference.
I've a faily simple SecurityConfig containing:
http
.anonymous()
.and()
.authorizeRequests()
.antMatchers("/api/**").hasAuthority("USER")
.and()
.csrf()
.disable()
.httpBasic()
.and()
.requestCache()
.requestCache(new NullRequestCache());
I's very similar like https://github.com/spring-projects/spring-session/tree/1.0.1.RELEASE/samples/rest as I have an endpoint with I authenticate to with http basic. It returns the authentication token via the header which is then used in other REST calls.
So I was hoping that I just could use the with(user( in this scenario to make my tests easier.

Yes you should be able to do this. The problem is that
.with(user("user").password("pwd").roles("USER", "ADMIN")))
is applying roles which means the ROLE_ prefix is automatically added.
In contrast, your configuration is using:
.antMatchers("/api/**").hasAuthority("USER")
which does not automatically add the ROLE_ prefix. Instead, try using:
.antMatchers("/api/**").hasRole("USER")
NOTE: I have also updated the tests to include an example of with(user("user")).

Related

Spring Boot Security: How to run authentication filter before CSRF in Spring Boot?

I am always getting unauthorize on Login.
On Login i need to authenticate user as well as generate CSRF token based on JWT token generated from user credentials.
I have CsrfCookieGeneratorFilter but i need to pass JWT generated after sucessfull authentication. My current code always execute CsrfFilterfirst and after that run authentication thing.
So Authentication First and then CsrfCookieGeneraterFilter.
Could anyone guide how to achieve using following builder (I am quite new to this Spring security thing implementation)
Following is code i am trying:
httpSecurity
.authorizeRequests().antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.csrf()
.requireCsrfProtectionMatcher(csrfRequestMatcher)
.csrfTokenRepository(customCsrfTokenRepository)
.and()
.cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(this.jwtAuthenticationEntryPoint);
httpSecurity.addFilterAt(new CsrfCookieGeneratorFilter(customCsrfTokenRepository), CsrfFilter.class);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

Receive Authorization header on anonymous url using Spring Boot

How can an Authorization header be accessed on anonymous urls?
My security configuration looks like:
http
.authorizeRequests()
.antMatchers("/login", "/legacy-login").anonymous()
.antMatchers("/things/*").authenticated()
.anyRequest().permitAll()
.and()
.httpBasic()
Authentication in general works fine. However, on /legacy-login I need to do some migration and need to access the authorization header without spring boot managing the authorization. Although /legacy-login is marked anonymous as soon as there are requests, spring intercepts the request and tries to authorize itself (what then results into 401).
How can I make Spring let the auth header through on that single url?
I foudn one solution myself. Instead of fiddleing around with .anonymous() and .permitAll() I added /legacy-login as ignore rule:
override fun configure(web: WebSecurity) {
super.configure(web)
web.ignoring()
.antMatchers("/legacy-login")
}

How to allow certain endpoint in spring security to be allowed without authentication?

I have Spring Boot Rest API web app in which I am using spring security to have most endpoints to require authentication.
This is part of code:
public class SecurityConfig extends WebSecurityConfigurerAdapter {
....
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requestMatchers()
.antMatchers("/oauth/token")
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated();
}
Can some one explain what each line begining with http.csrf means?
How can I modify above code so that enpoint /bars/pk can be allowed to be accessed without requiring authentication just as if there was no Spring Security ?
By default, Spring Boot activates protection against CSRF attack (Cross Site Request Forgery attack). The attack consists of a malicious site taking advantage of a user being alredy authenticated to a site (e.g. bank) in order to trick the user to do actions on that site (e.g. fund transfer).
The protection against the attack consists of the Spring Boot application sending a token with every response and expecting the token to be sent by the client on subsequent request. If the token is not received, Spring Boot returns an error.
Sometimes, you want to disable this behavior (at your own risks), so you use csrf.disable. You might find it convenient to disable csrf protection if you develop a Stateless API, and you have no way to link a POST request to any previous requests or session. But again, you need to consider this and reason about it carefully.
Please note that CSRF protection has not effect on GET requests. It only affects state chaning requests (e.g. POST, DELETE)
In order to allow your endoints to anyone, without requiring any authentication, you need to use
http.authorizeRequests().antMatchers("/**").permitAll();
EDIT
To specifically allow unauthorized requests to /bars/pk and keep the other elements unchanged, modify your code as follows :
http.csrf().disable()
.requestMatchers()
.antMatchers("/oauth/token")
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/bars/pk").permitAll()
.anyRequest().authenticated();
Here is a complete example:
httpSecurity.authorizeRequests()
.antMatchers(HttpMethod.GET)
.permitAll() // Allow all GET requests to go unauthenticated
.antMatchers(allowedResources)
.permitAll() // Allow all requests to go unauthenticated for the specified paths
.antMatchers(protectedResources).hasRole(USER)
.antMatchers(adminResources).hasRole(ADMIN)
.anyRequest().authenticated(); // Authenticate all other request paths

Custom .formLogin() Spring Security

I am trying to use my page created to authenticate, it is the login.jsf. I use in .loginPage / login.jsf with 2 inputs and 1 button to authenticate. However, by filling in the logins and password fields, and clicking the button, nothing happens. Unlike Spring Security own .formLogin() itself, which already does all the processing by clicking the button.
My method
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login.jsf").anonymous()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.jsf")
.defaultSuccessUrl("/homepage.jsf")
.failureUrl("/login.jsf?error=true")
.and()
.logout().logoutSuccessUrl("/login.jsf");
}
Anyone have any suggestions?
Print screen default .formLogin()
Take a look at the following article from spring security documentation.
https://docs.spring.io/spring-security/site/docs/current/guides/html5/form-javaconfig.html#creating-a-login-view
Quoting the article,
The URL we submit our username and password to is the same URL as our
login form (i.e. /login), but a POST instead of a GET.
So I believe you have to make a POST call to the /login endpoint with your authentication details for it to work.
Don't use file extensions when specifying pages in the configuration. The ViewResolver will take care of it. Simply specify
.loginPage("/login").defaultSuccessUrl("/homepage")
.failureUrl("/login?error=true")
.and()
.logout().logoutSuccessUrl("/login");`
And make sure a ViewResolver is configured to append .jsf to the url. The DispatcherServlet will take care of locating the appropriate page.
Also, not to mention, you should have controllers with the appropriate #RequestMappings defined to handle your requests.

405 Method Not Allowed for POST

I have a very simple spring boot application, which is secured by the following code:
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.and()
.formLogin().loginPage("/login").failureUrl("/login?error")
.usernameParameter("username").passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/login?logout")
.and()
.exceptionHandling().accessDeniedPage("/403");
the idea is to secure "admin" portion. It exposes a REST API.
The problem is all the POSTS returns
405 Method Not Allowed
If I remove the security starter from the application, it works. This makes me believe that the security configuration is the problem. But I cannot find out how.
This should be easy.
POSTs and PUT requests would not be allowed if CSRF is enabled,and spring boot enables those by default.
Just add this to your configuration code :
.csrf().disable()
that is :
http.
.csrf().disable().
authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.and()
.formLogin().loginPage("/login").failureUrl("/login?error")
.usernameParameter("username").passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/login?logout")
.and()
.exceptionHandling().accessDeniedPage("/403");
Refer docs ,if you need to enable CSRF :
http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#csrf-configure
This can also happen if using Spring Security SAML extension and your SAMLUserDetailsService returns a UsernameNotFoundException. Seems pretty counter-intuitive, but that's what it does by default (in my experience).

Resources