How to disable for GET and PUT in spring security? - spring

I have GET,POST,PUT and DELETE mappings in spring boot app, I have added spring security and disabled the csrf for POST like below
httpSecurity.csrf().disable().authorizeRequests().
antMatchers(HttpMethod.POST, "/users/post").
permitAll().anyRequest().authenticated();
how can I disable it for GET and PUT methods like above?

#Bean
public CsrfTokenRepository csrfTokenRepository() {
return new HttpSessionCsrfTokenRepository();
}
Then add your paths that you want to disable CSRF token to the ignoringAntMatchers method.
httpSecurity
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.ignoringAntMatchers("/users/post" , "/admin/post");

You are probably confusing the functionality of authorizeRequests().
You can break down your code in two separate blocks and have the same functionality.
http
.csrf()
.disable();
http
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/users/post")
.permitAll()
.anyRequest()
.authenticated();
So, when you disable csrf, this applies for every Http method.
The authorizeRequests does not refer to csrf, you use it to set authorization filters for your controllers.

Related

Spring Security with OAuth2 losing session

We have a Spring Boot-based Gateway using Spring Security, OAuth2 login, and Zuul routing. It is also using Spring Session to store sessions in Redis. This Gateway stores an OAuth2 token in the session and forwards the OAuth2 Bearer token to backend services.
We have an issue where users are being signed out quite often. It appears this happens roughly hourly. We are not even quite sure what is causing this with all the different tools in place.
Our session cookie in the browser expires in a longer period of time. So I suspect it is either Spring invalidating the session, or the OAuth2 token expiring.
From a quick inspection of the code, it appears that OAuth2TokenRelayFilter supports refreshing the token. Is this correct?
How can track down the cause of this and fix it?
For reference, we are using these versions:
Spring Boot 2.1.12
Spring Cloud Greenwich.SR4
Here are some relevant snippets.
Our web security config for the web pages.
#Configuration
#EnableWebSecurity
#EnableOAuth2Sso
#Order(SecurityProperties.BASIC_AUTH_ORDER - 2)
#Profile("!security-disabled")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/login", "/login/**", "/favicon.ico").permitAll()
.antMatchers("/signout").authenticated()
.anyRequest().hasAnyRole("ADMIN", "MEMBER")
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.httpBasic()
.disable()
.formLogin()
.disable()
.logout()
.logoutUrl("/signout")
.deleteCookies("SESSION")
.and()
// #formatter:on
}
Security configuration for API paths.
#Configuration
#Order(SecurityProperties.BASIC_AUTH_ORDER - 2 - 10)
#Profile("!security-disabled")
public class ApiSecurityConfig extends WebSecurityConfigurerAdapter
{
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasAnyRole("ADMIN", "MEMBER")
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.headers()
.frameOptions().sameOrigin()
.and()
.httpBasic()
.disable()
.formLogin()
.disable()
.logout()
.disable()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
// #formatter:on
}
}
Update
We have done some debugging of the Spring internals. First, we found that we were missing an OAuth2RestTemplate. Per the OAuth2 Boot documentation we found how to add it with:
#Bean
public OAuth2RestTemplate oauth2RestTemplate(
OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details)
{
return new OAuth2RestTemplate(details, oauth2ClientContext);
}
This is now throwing an exception when OAuth2TokenRelayFilter calls restTemplate.getAccessToken().getValue();.
A redirect is required to get the users approval
This exception is thrown from AuthorizationCodeAccessTokenProvider.
OAuth2TokenRelayFilter
OAuth2TokenRelayFilter is a pre type filter which set the contexts with ACCESS_TOKEN and TOKEN_TYPE which will be used for the further authentication. It validates the tokens using getAccessToken() method and responds with "Cannot obtain valid access token" with 401 status.
You may check the validity of tokens and refresh token is correctly configured with grant_type as refresh_token as The Refresh Token grant type is used by clients to exchange a refresh token for an access token when the access token has expired which allows clients to continue to have a valid access token without further interaction with the user.
In case if you want to disable OAuth2TokenRelayFilter, you may use the following
zuul.OAuth2TokenRelayFilter.pre.disable=true

Spring Security and i18n

I have problem with accessing when I change language on page.
Without .antMatchers("/login*").permitAll() doesn't work but with /login* is almost ok but when I provide in URL 'http://localhost:8080/login?lang=estest123' or sth not related with i18n after login I receive ??language.change_estest123??.
I tried add .regexMatchers("^login\\?lang=[a-zA-Z]{2}|^login\\?lang=_{1}[a-zA-Z]{2}").permitAll() but same result as /login*.
Is any possible to accessing only for i18n ? in other case providing error? Or maybe another way of configuration for i18n which allows in easy way to provide this?
My web security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/registration").permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
Does the presence of parameters affect the url parsing for Security? Just use /login and it should pass /login and /login?lang=xxx.
But if you want to use direct mapping in your config you can use both of them: .antMatchers("/login", "/login*").permitAll()

Create custom User with OAuth2 data from authorization with Spring Security

I'm trying to support both form login and Facebook authentication in my app, the goal is both to create a User object. With formLogin I can make a sign up controller and persist my User entity, but how can I intercept the OAuth2 authentication from Facebook to create (or login if it already exists) a User entity?
This is my security configuration so far:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth2/**", "/webjars/**", "/users/signup", "/users/recover", "/users/reset/**", "/img/**", "/css/**", "/js/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/users/login")
.successHandler(loginSuccessHandler())
.permitAll()
.and()
.logout()
.logoutUrl("/users/logout")
.logoutSuccessUrl("/users/login?logout")
.permitAll()
.and()
.oauth2Login()
.defaultSuccessUrl("users/facebook");
}
Is there a way to create a successHandler or similar to accomplish this?
Finally found the solution, as mentioned here you should configure your OAuth2 authorization with the spring-security-oauth2-autoconfigure package using the # EnableOAuth2Sso annotation and then creating a PrincipalExtractor to build your User entity based on the data sent by the OAuth2 provider.
This way your own model object will be accesible through getPrincipal() in further calls.

Restrict access to Swagger UI

I have swagger UI working with spring-boot. I have a stateless authentication setup for my spring rest api which is restricted based on roles for every api path.
However, I am not sure how can i put <server_url>/swagger-ui.html behind Basic authentication.
UPDATE
I have following websecurity configured via WebSecurityConfig
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/sysadmin/**").hasRole("SYSADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/siteadmin/**").hasRole("SITEADMIN")
.antMatchers("/api/**").hasRole("USER")
.anyRequest().permitAll();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
One suggestion without knowing more about your configuration is from this SO question.
https://stackoverflow.com/a/24920752/1499549
With your updated question details here is an example of what you can add:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/sysadmin/**").hasRole("SYSADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/siteadmin/**").hasRole("SITEADMIN")
.antMatchers("/api/**").hasRole("USER")
// add the specific swagger page to the security
.antMatchers("/swagger-ui.html").hasRole("USER")
.anyRequest().permitAll();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
The problem with this is it only protects the Swagger UI page and not the API specification which is loaded as a .json file from that UI page.
A better approach is to put the swagger files under a path so that you can just add antMatchers("/swagger/**").hasRole("USER")
A bit late to answer. I carried out a small POC to execute the same. I am using Keycloak and Spring Security. Below is my configuration
http
.antMatcher("/**").authorizeRequests()
.antMatchers("/swagger-resources/**","/swagger-ui.html**","/swagger-ui/").hasRole("admin")
.anyRequest().authenticated()
.and()
.exceptionHandling()
.accessDeniedHandler(new AccessDeniedHandlerImpl())
.defaultAuthenticationEntryPointFor(authenticationEntryPoint(), new CustomRequestMatcher(AUTH_LIST))
.and()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.clearAuthentication(true)
.addLogoutHandler(keycloakLogoutHandler());
I have a working example here

Spring security - Getting 404 error for REST call

I have an application that I am securing using Spring Security. I enable it using the annotations:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
I then configure it by overriding the configure() method:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.and()
.addFilterAfter(new CsrfCookieGeneratorFilter(), CsrfFilter.class)
.exceptionHandling()
.accessDeniedHandler(new CustomAccessDeniedHandler())
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.formLogin()
.loginProcessingUrl("/api/authentication")
.successHandler(ajaxAuthenticationSuccessHandler)
.failureHandler(ajaxAuthenticationFailureHandler)
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler)
.deleteCookies("JSESSIONID", "CSRF-TOKEN")
.permitAll()
.and()
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/admin/**").hasAuthority(AuthoritiesConstants.ADMIN);
}
I'm getting redirected correctly to the login page when I try to get to the home page, but once I enter my credentials and try to login, I get the 404 not found error for /api/authentication REST call.
The loginProcessingUrl() method specifies the call to make. I don't have to implement this myself do I, as Spring should do that for me? Is there anything else I'm missing?
As far as I understood the login-processing-url, you have to handle the login process by yourself if you specify a special url to process the login.
Have you tried to just remove this line?:
.loginProcessingUrl("/api/authentication")
As you use springs default login form, you should just be able to remove the line and the generated login form will also change.
Maybe there's another way to solve your problem but this should also work.
If you're looking for an example on how to use custom login forms, this link might helo you.
I figured it out, it was a couple of things I needed to change:
I didn't have an Initializer class. After I added the following class, I went from a 404 not found error, to a 403 error:
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
Note: you can also add the corresponding filter in your web.xml (read more here: http://websystique.com/spring-security/spring-security-4-hello-world-annotation-xml-example/)
The above change registers security with the Spring container. But I still needed to disable CSRF, as I wasn't sending the proper tokens from the client side. For my application, I don't need CSRF just yet so I have disabled it for now. However, this is not recommended so make sure sure you know what you are doing before making this change:
http.csrf().disable()

Resources