Authorization doesn't work when using Spring boot rest api using oauth2 , Keycloak - spring-boot

I am trying to use oauth2 to do authentication and authorization for rest api.
with the rest api url as "/users" and the role "userrole" is defined in keycloak.
I have used used keycloak for jwt access token. Authentication is working fine but Authorization is not working.
If I specify hasRole I always get forbidden error.
But if I will remove hasRole authentication works as expected.
#Configuration
#EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
#Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
private String jwtSetUri;
#Override
public void configure(final HttpSecurity http) throws Exception {
http.cors().and()
.csrf()
.disable()
.authorizeRequests().
antMatchers("/users").hasRole("userrole").antMatchers("/users").authenticated()
.and().oauth2ResourceServer().jwt() ;
}
}

Related

401 error with jwt token using newest okta-spring-boot-starter 2.1.2 with spring boot 2.5.6

using these dependency versions in an api for jwt access validation:
<okta-spring-boot-starter.version>2.1.2</okta-spring-boot-starter.version>
<spring-boot.version>2.5.6</spring-boot.version>
<spring-cloud.version>2020.0.4</spring-cloud.version>
I am getting problems with jwt tokens. the gui we are using is react with #okta/okta-react 6. it throws errors (401) authenticating jwt tokens when calling api that uses the above versions.
If we change back to okta-spring-boot-starter 2.0.0, it works. any ideas?
our security config looks like this for the jwt part:
#Configuration
#EnableWebSecurity
public class SecurityConfig {
...
#Order(2)
#Configuration
public static class NormalSecurity extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(ANT).permitAll()
.antMatchers(withApi(ANT)).permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer().jwt();
Okta.configureResourceServer401ResponseBody(http);
}

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.

How to access endpoint without token in spring boot?

I am using an actuator for getting server health, also I am doing validation on the token on each request, now I need to put a token to access actuator health but I want to access actuator health without using the token and without affecting API endpoint with token!
Note: My Actuator working fine with the token.
also, I implement the OncePerRequestFilter class for validating the firebase token for each request.
You can create a custom SecurityConfiguration where you permit access to actuator requests:
#Configuration
#EnableWebSecurity
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers("/actuator/**").permitAll()
.anyRequest().authenticated();
}
}
You may want to read the spring-boot-docs for more information.
EDIT:
When using OncePerRequestFilter you could implement the shouldNotFilter method and check for actuator paths there:
#Override
protected boolean shouldNotFilter(HttpServletRequest request)
throws ServletException {
String path = request.getRequestURI();
return path.startsWith("/actuator");
}

How to support basic authentication and bearer authentication for the REST API project

I am new to Spring Security & still learning it so my question can be naive please bear with it.
I have Sprint Boot Rest API project which exposes certain APIs. I have already implemented the bearer token based authentication for all the APIs.
e.g /user , /resource, /appointment
Now for few apis for a particular controller I would like to have the basic authentication implemented. These Apis will be consumed by another service which is not exposed to public.
In order to have the security for the APIs I would like to have basic authentication in place for these apis.
e.g /internal/api1 , internal/api2 .. and so on
I am not able to distinguished between urls in the ResourceServerConfigurerAdapter & WebSecurityConfigurerAdapter. Also not sure which should be used for adding basicAuth() using the antmatchers
What you want, by reading your problem, is to have two authentication types (token and httpBasic) for two diffetent endpoints. It can be achieved by creating two different WebSecurityConfigurerAdapter beans. Spring Boot enables this and can be done like bellow:
#Order(1) - /resource|user|appointment/** protected by bearer token authentication.
#Order(2) - /internal/** protected by basic auth.
View docs for Spring Boot and sample code here.
#EnableWebSecurity
public class SecurityConfig {
#Configuration
#Order(1)
public class ApiSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/resource/**")
.antMatcher("/user/**")
.antMatcher("/appointment/**")
.authorizeRequests()
.anyRequest().authenticated()
.and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
#Configuration
#Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/internal/**")
.and()
.httpBasic();
}
}
}

Spring Boot 2.0 OAuth2 Client - Getting bearer token across sessions

I have a basic OAuth2 App set up:
#Configuration
#EnableOAuth2Sso
#Order(0)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/actuator/health", "/", "/noauth", "/login").permitAll()
.anyRequest().authenticated().and()
.oauth2Login().defaultSuccessUrl("/auth");
}
}
It works well for a single instance and I can request OAuth2AuthorizedClient details:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(), oauthToken.getName());
// Gets an OAuth2 token
client.getAccessToken().getTokenValue()
However, if I run this in a microservices environment (>1 instance) then client will always be null. Authentication also doesn't work correctly in this case.
I am using the org.springframework.security:spring-security-oauth2-jose library and authenticating with Google.
Any hints on how to persist the bearer token between sessions (or refresh it if it's not there)?

Resources