spring oauth2 how to get a new refresh token every time - spring

When I call refresh token the web service returns a new access token and the old refresh token because the access token has not yet expired. Is there any configuration that when I call refresh token this web service return me a new access token and a new refresh token?

Spring can be configured not to reuse refresh tokens - by default it reuses -, this should solve the issue.
#Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception {
configurer.reuseRefreshTokens(false);
}
}

You can use AOP to invalidate token by removing old one, or change its validity time, before generate new one,but if you do so then you are going to invalidate all refresh tokens used by other clients.

Related

How can I implement access tokens for a public Spring Boot API?

I have a public facing API created with Spring Boot. I want users of the API to include a token with requests so that I can ensure they are allowed to access it and also track how many requests are made within a certain period of time.
I'm a little confused on how to approach this because everything I am reading online is where a user sends their user/password and the application returns a token. This is not what I'm looking for.
I want something similar to when you use Google APIs or similar APIs where your token never changes unless you want it to change and you do not send Google API your user/pass on the first request.
Maybe I'm not using the correct terminology. Can someone point me in the right direction?
If you want to authenticate using a static token for each user you will have to create a custom AuthenticationManager that gets your request header and tries to match it aginst known keys.
Example using single key, you'd have to add a lookup to user table if needed
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception
{
http.authorizeRequests(auth -> auth
.anyRequest().authenticated());
http.addFilter(tokenFilter());
http.csrf().disable();
return http.build();
}
public Filter tokenFilter()
{
AuthenticationTokenFilter filter = new AuthenticationTokenFilter(authenticationTokenHeader);
filter.setAuthenticationManager(authenticationManager());
return filter;
}
protected AuthenticationManager authenticationManager()
{
final AuthenticationManager authenticationManager = new AuthenticationManager()
{
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
String principal = (String) authentication.getPrincipal();
if (!authenticationTokenValue.equals(principal))
{
throw new BadCredentialsException("The API key was not found or not the expected value.");
}
authentication.setAuthenticated(true);
return authentication;
}
};
return authenticationManager;
}
Do keep in mind that this approach is not the most secure, and if you'r application is public facing I would not recommend using this. And would recommend either using Authorization header with username/password or JWT
As a side note, I think you'r mistaken on how the google API authenticates. To the best of my knowledge all google APIs use Oauth2 for authentication, the static key/file you have does not provide access to the API it is only good for retrieving a short lived access token, in essence this would be not much different from standard JWT where you use some form of credentials to get a token with which you access the API.
for more info on JWT authentication:
https://www.baeldung.com/spring-security-oauth-jwt
https://blog.softtek.com/en/token-based-api-authentication-with-spring-and-jwt

How to secure a Spring Boot REST API

How do I secure my Spring REST API? I would like clients (On other domains/apps) to login/register to my API via google OAuth2 or simple username & password in a POST request and for my API to then return something they can use to authenticate following requests to secured endpoints.
I'm having a hard time finding solutions, I have kinda improvised a registration/login
with the following class.
My problems are 2:
I'm returning a cookie JSESSIONID which is going to a client on another domain, or a mobile app, what else could I return and how do I configure that?
Spring auto-generates login and logout pages, I don't need them since the app is just a REST API web service
#Order(2)
#Configuration
static class ResourceSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Autowired
UserService userService
#Autowired
PasswordEncoder passwordEncoder
DaoAuthenticationProvider authProvider
/**
* Initialize the daoAuthenticationProvider
*/
#PostConstruct
void init() {
authProvider = new DaoAuthenticationProvider()
authProvider.setUserDetailsService(userService)
authProvider.setPasswordEncoder(passwordEncoder)
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// Disable auto config
http.httpBasic().disable()
// Authentication Provider
http.authenticationProvider(authProvider)
http.csrf().disable()
http.authorizeRequests().antMatchers('/api/users/auth/**').permitAll()
http.authorizeRequests().antMatchers("/login").denyAll()
http.authorizeRequests().anyRequest().authenticated()
http.formLogin().loginProcessingUrl('/api/users/auth/login')
http.logout().logoutUrl('/api/users/logout').invalidateHttpSession(true)
// Session Management
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
// Cors Configuration
CorsConfiguration corsConfiguration = new CorsConfiguration()
corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"))
corsConfiguration.setAllowedOrigins(List.of("*"))
corsConfiguration.setAllowedMethods(List.of("GET", "POST", 'OPTIONS'))
corsConfiguration.setExposedHeaders(List.of("Authorization"))
http.cors().configurationSource(request -> corsConfiguration)
}
}
I'm okay with users sending POST requests to /login and /register, but I need to configure something better than a JSESSIONID cookie in my response.
Is there a way to do everything with Google OAuth2? (That'd be optimal, a frontend can just login to Google with the google login react-component and then send me some kind of 'token' I can send to back to Google to verify their identity)

is there any way to "reset" the csrf token after successful login?

I just enabled the csrf token protection on my spring security (with xml) by adding the csrf tag.
It works great but I noticed when I hit the login form I am sending a csrf token, after a successful login the csrf token is still the same, is there anyway I can reset it after hit the login form?
After checking the docs I found no clue how to do this or if is due my repository? (Im not using any custom csrf repository)
Ideas?
The official documentation states that the CSRF token is stored in the HttpSession by default. Since the token is stored in the session, it will continue to get reused after the user has logged in.
If you really want to reset the token on a successful login, you will have to handle successful login events.
public class AuthenticationSuccessCsrfTokenResetHandler
extends SimpleUrlAuthenticationSuccessHandler {
private final CsrfTokenRepository repository;
public AuthenticationSuccessCsrfTokenResetHandler(final CsrfTokenRepository repository) {
this.repository = repository;
}
#Override
public void onAuthenticationSuccess(final HttpServletRequest request
, final HttpServletResponse response
, final Authentication authentication)
throws ServletException, IOException {
repository.saveToken(repository.generateToken(request), request, response)
}
}
Then, configure this handler in your Spring Security configuration.

Spring OAuth - Reload resourceIds and authorities of authentication

I just apply Spring Boot and Spring Cloud to build a microservice system. And I also apply Spring Oauth to it. Honestly, everything is perfect. Spring does a great job in it.
In this system, I have a microservice project does the job of an OAuth server, using JDBC datasource, and I using Permission based for UserDetails authorities (1 User has several Permissions). There are several microservice project does the jobs of Resource server (expose Rest api using Jersey), access security is based on Permissions of Authentication of OAuth bearer token.
Resource Server OAuth config class is something like this
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/restservice/object/list")
.hasAuthority("PERMISSION_VIEW_OBJECT_LIST");
// ...
}
#Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
resources.resourceId("abc-resource-id")
.tokenStore(new JdbcTokenStore(dataSource()));
}
#Bean
#ConfigurationProperties(prefix = "oauth2.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
Everything is great! But I encounter 2 problems:
If I add a new microservice project as a new resourceId, and I append resourceId value to RESOURCE_IDS in table OAUTH_CLIENT_DETAILS of the OAuth client, all requests to Rest API of new resource service return error something like this
{"error":"access_denied","error_description":"Invalid token does not contain resource id (xyz-resource-id)"}
This happens even when user logout and re-login to obtain new access token. It only works if I go to delete records of the Access token and Refresh token int table OAUTH_ACCESS_TOKEN and OAUTH_REFRESH_TOKEN in database.
If at runtime, Permission of a User is changed, the authorities of authentication is not reloaded, I see that AUTHENTICATION value of the Access Token in table OAUTH_ACCESS_TOKEN still contains old Authorities before Permission is changed. In this case, User must logout and re-login to obtain new Access Token with changed authorities.
So, are there any ways to fix these 2 problems.
I'm using Spring Cloud Brixton.SR4 and Spring Boot 1.3.5.RELEASE.
If you are using the default Spring JdbcTokenStore, then the users authentication is serialised and stored with the access/refresh token when the user authenticates and retrieves their token for the first time.
Each time the token is used to authenticate, it is this stored authentication that is loaded which is why changes to the user permissions or the addition of extra resources is not reflected in the users permissions.
In order to add in some checking on this, you can extend DefaultTokenServices and override the loadAuthentication(String accessTokenValue) method to perform your own checks once the users authentication is loaded from the token store.
This may not be the ideal way of doing this, but it is the only way we've found of doing it so far.
To override DefaultTokenServices, add the follwoing bean method to you AuthorizationServerConfigurerAdapter config class:
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Bean
public AuthorizationServerTokenServices authorizationServerTokenServices() throws Exception {
// Where YourTokenServices extends DefaultTokenServices
YourTokenServices tokenServices = new YourTokenServices();
tokenServices.setTokenStore(tokenStore);
tokenServices.setClientDetailsService(clientDetailsService);
return tokenServices;
}
}
I resolved reload problem this way.
#Bean
public ClientDetailsService jdbcClientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}

Why to invalidate a session in a security filter, CSRF token is not updated

In a Spring Security application, a user is making a GET call to a private /secure url with activated csrf.
The user sends a credential cookie and then the user is authenticated and JSESSIONID is generated.
In the same browser becomes to make a GET call to /secure, with the JSESSIONID cookie and a credential cookie by another user.
In this case an owner security filter produces a change of user, invalid session of the first user, generate a
new session and authenticates the new credential.
This works until the new authenticated user sends a POST with the new JSESSIONID, but the CSRF token is getting to the old.
CsrfFilter is before my authentication filter, and CsrfAuthenticationStrategy not regenerate the CSRF token.
What is the right way to invalidate a session and the token csrf be updated?
The invalidation of session in spring security is automatic once you relogin as new user using the old JSESSION ID.
Basically you just have to bind the token generated on the new session generated by the authentication filter.
Try this solution, another filter after authentication
https://github.com/aditzel/spring-security-csrf-filter/blob/master/src/main/java/com/allanditzel/springframework/security/web/csrf/CsrfTokenResponseHeaderBindingFilter.java
Same issue reported via this thread,
https://github.com/aditzel/spring-security-csrf-token-interceptor/issues/1
I created a HttpSessionCsrfTokenRepository bean type, which is the default implementation of CsrfTokenRepository, and use both to configure spring security repository csrf as my filter, so the two sites use the same bean.
Config Bean
#Bean
public void CsrfTokenRepository dafaultCsrfTokenRepository() {
return new HttpSessionCsrfTokenRepository();
}
Spring Security
#Autowired
private CsrfTokenRepository csrfTokenRepository;
private static HttpSecurity addCSRF(HttpSecurity http, CsrfTokenRepository csrfTokenRepository) throws Exception {
http.csrf().csrfTokenRepository(csrfTokenRepository);
return http;
}
Invalidate session in filter
private void invalidateCurrentSession(HttpServletRequest request, HttpServletResponse response) {
SecurityContextHolder.clearContext();
HttpSession session = request.getSession(false);
if (session != null) {
CsrfToken csrfToken=csrfTokenRepository.loadToken(request);
session.invalidate();
request.getSession();
csrfTokenRepository.saveToken(csrfToken, request, response);
}
}
If someone wanted to override the default behavior, you could define a bean that implements CsrfTokenRepository as #Primary

Resources