I have a project that uses this scheme:
Spring Boot
Spring Security
Redis
Everything works fine except the session time.
I want to keep the token in Redis permanent. The token must have no expiration how should I do?
This and configuration of my HttpSessionConfig:
#Configuration
#EnableRedisHttpSession
public class HttpSessionConfig {
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
}
It was suggested by Mr Rwinch to use this command:
EnableRedisHttpSession (MaxInactiveIntervalInSeconds = Integer.MAX_VALUE)
In this way, the session will expire in 68 years :)
Related
Has anyone tried using both the newly release Spring Authorization Server 0.1.0 and the regular Spring Resource Server in 1 project and in 1 server such as:
The resource server is at http://localhost:8080 and the authorization server is also at http://localhost:8080? Any ideas on how to do it?
The problem is that at start up, the resource server checks the authorization server's /.well-known/openid-configuration which is obviously not yet avaialble.
Instead of issuer-uri, you can instead specify the jwk-set-uri, which isn't pinged at startup.
Or, since the authorization server and resource server will use the memory space for keys, you might construct your own Nimbus JWTProcessor instead so that you skip the internal HTTP request:
#Bean
JwtDecoder jwtDecoder() {
JWKSource<SecurityContext> source = // ... some internal store for the public keys, e.g. not RemoteJWKSet
ConfigurableJWTProcessor<SecurityContext> processor = new DefaultJWTProcessor<>();
JWSKeySelector<SecurityContext> selector = new JWSVerificationKeySelector(
JWSAlgorithm.RS256, source);
processor.setJWSKeySelector(selector);
NimbusJwtDecoder decoder = new NimbusJwtDecoder(processor);
decoder.setJwtValidator(... add any validation rules ...);
return decoder;
}
I believe you can just set your jwtDecoder as follows:
#Bean
JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
As you probably already have that defined as a Bean elsewhere when setting up your auth server
#Bean
public JWKSource<SecurityContext> jwkSource() {
// implementation ...
}
I was working on getting a client credential flow with Auth0 to work using Spring Security 5.4.1. I created a little demo application for reference: https://github.com/mathias-ewald/spring-security-auth0-clientcredentials-demo
Everything works fine, but I was wondering how to handle multiple OAuth2 clients. As far as I understand, the configuration made in OAuth2ClientSecurityConfig is valid for all client credential flows to any provider, correct?
What if I have another provider and don't want to convert RequestEntity in the same way?
There's usually no perfect answer for multi-tenancy since a lot depends on how early in the request you want to fork the behavior.
In Spring Security's OAuth 2.0 Client support, the ClientRegistration is the tenant, and that tenant information is available in most of the client APIs.
For example, your Auth0RequestEntityConverter could have different behavior based on the ClientRegistration in the request:
public RequestEntity<?> convert(
OAuth2ClientCredentialsGrantRequest request) {
ClientRegistration client = request.getClientRegistration();
if (client ...) {
} else if (client ...) {
} ...
}
Or, if you need to configure more things than the request entity converter, you could instead fork the behavior earlier by constructing a OAuth2AuthorizedClientManager for each provider:
public class ClientsOAuth2AuthorizedClientManager implements OAuth2AuthorizedClientManager {
private final Map<String, OAuth2AuthorizedClientManager> managers;
// ...
public OAuth2AuthorizedClient authorize(OAuth2AuthorizeRequest request) {
String clientRegistrationId = request.getClientRegistrationId();
return this.managers.get(clientRegistrationId).authorize(request);
}
}
Spring Boot 2 with Spring Security 5 can be configured to use an openID connect ID provider for authentication.
I managed to setup up my project just by configuring Spring Security - that works fine with all kinds of perfectly preconfigured security mechanisms like mitigation of session fixation.
But it seems that Spring Security does not refresh the tokens (which are stored in the session) by itself when they are expired.
Is there a setting for that or do I have to care for the refresh myself?
Update: Spring Boot 2.1 has been released, so it is time to revisit this problem. I still have no clue if the accessToken can now be automatically refreshed or if I have to write code for doing so...
According to the documentation,
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#webclient
When using a WebClient configured correctly, as given in the documentation it will automatically be refreshed.
Spring Security will automatically refresh expired tokens (if a refresh token is present)
This is also supported by the features matrix that refresh tokens are supported.
https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Features-Matrix
There was an older blog on Spring Security 5 that gives you access to beans that you could do this manually,
Authentication authentication =
SecurityContextHolder
.getContext()
.getAuthentication();
OAuth2AuthenticationToken oauthToken =
(OAuth2AuthenticationToken) authentication;
There will be an OAuth2AuthorizedClientService automatically configured as a bean in the Spring application context, so you’ll only need to inject it into wherever you’ll use it.
OAuth2AuthorizedClient client =
clientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(),
oauthToken.getName());
String refreshToken = client.getRefreshToken();
And, failing to find it right now, but I assume as part of the OAuth2AuthorizedClientExchangeFilterFunction has the calls to do a refresh.
According to https://github.com/spring-projects/spring-security/issues/6742 it seems that the token is intentionally not refreshed:
An ID Token typically comes with an expiration date. The RP MAY
rely on it to expire the RP session.
Spring does not. There are two enhancements mentioned at the end which should solve some of the refresh issues - both are still open.
As a workaround, I implemented a GenericFilterBean which checks the token and clears the authentication in the current security context. Thus a new token is needed.
#Configuration
public class RefreshTokenFilterConfig {
#Bean
GenericFilterBean refreshTokenFilter(OAuth2AuthorizedClientService clientService) {
return new GenericFilterBean() {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication instanceof OAuth2AuthenticationToken) {
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient client =
clientService.loadAuthorizedClient(
token.getAuthorizedClientRegistrationId(),
token.getName());
OAuth2AccessToken accessToken = client.getAccessToken();
if (accessToken.getExpiresAt().isBefore(Instant.now())) {
SecurityContextHolder.getContext().setAuthentication(null);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
};
}
}
Additionally I had to add the filter to the security config:
#Bean
public WebSecurityConfigurerAdapter webSecurityConfigurer(GenericFilterBean refreshTokenFilter) {
return new WebSecurityConfigurerAdapter() {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(refreshTokenFilter, AnonymousAuthenticationFilter.class)
Implemented with spring-boot-starter-parent and dependencies in version 2.2.7.RELEASE:
spring-boot-starter-web
spring-boot-starter-security
spring-boot-starter-oauth2-client
I appreciate opinions about this workaround since I'm still not sure if such an overhead is really needed in Spring Boot.
even a bounty of 100 rep points did not yield an answer. So I guess there is currently no mechanism implemented to automatically refresh the access token with Spring Security.
A valid alternative seems to use the spring boot keycloak adapter which is capable of refreshing the token.
I am trying to build a web service using WebFlux. When I tried to configure Spring Security with Spring WebFlux, the requests are not intercepted by Spring Security. My Spring Security config is:
#EnableWebFlux
#EnableWebFluxSecurity
#Configuration
public class WebConfig {
#Bean
public MapUserDetailsRepository userDetailsRepository() {
UserDetails cust =
User.withUsername("user1").password("password")
.roles("USER").build();
UserDetails admin =
User.withUsername("admin1").password("password")
.roles("ADMIN").build();
return new MapUserDetailsRepository(cust, admin);
}
#Bean
public SecurityWebFilterChain springWebFilterChain(
HttpSecurity httpSecurity) {
return httpSecurity.authorizeExchange().anyExchange().
authenticated().and().build();
}
}
One way is to use method security. You need to add #EnableReactiveMethodSecurity to your configuration class and then secure handler component methods with annotations, such as #PreAuthorize("isAuthenticated()")
This is how I managed to get this working with Spring Boot 2.0.0.M4, but again this may depend on what kind of request handling you are doing.
This is an issue when using Spring Security with WebFlux. The workaround is posted here: https://jira.spring.io/browse/SPR-16144
In our Muhuru-Bay-Microgrid-Dashboad project we're using code from https://github.com/xpoft/spring-vaadin in an attempt to get Spring Boot and Vaadin to play nicely. The problem - with this approach we can't access many of the other rest service Spring Boot registers at startup such as
/configprops
/health
/dump
/info
/trace
/mappings
/error
/autoconfig
Our startup code looks like:
#Bean
public ServletRegistrationBean servletRegistrationBean() {
final ServletRegistrationBean servletRegistrationBean
= new ServletRegistrationBean(
new ru.xpoft.vaadin.SpringVaadinServlet(),
"/*", "/VAADIN/*");
return servletRegistrationBean;
}
When we try to access Spring Boot's registered REST services we get redirected to /error - which also doesn't work correctly. Any hints greatly appreciated.
Try to use this addon to integrate Spring Boot and Vaadin:
https://github.com/peholmst/vaadin4spring
It's still in beta, but in my opinion it works much better than the Xpoft addon.
Using https://github.com/peholmst/vaadin4spring with Spring Boot, I had the same problem of getting HTTP 404 when accessing the application's other REST services.
What worked for me was to set VaadinServletConfiguration.SERVLET_URL_MAPPING_PARAMETER_NAME in the spring environment to send the Vaadin UI to a different context path (/ui/*):
#SpringBootApplication
public class AppSpringConfig {
public static void main(String[] args) {
new SpringApplicationBuilder(AppSpringConfig.class).initializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
public void initialize(ConfigurableApplicationContext applicationContext)
{
ConfigurableEnvironment appEnvironment = applicationContext.getEnvironment();
Properties props = new Properties();
props.put(VaadinServletConfiguration.SERVLET_URL_MAPPING_PARAMETER_NAME, "/ui/*");
PropertySource< ? > source = new PropertiesPropertySource("vaadin", props);
appEnvironment.getPropertySources().addFirst(source);
}
}).run(args);
}
}