Skip to content

Commit

Permalink
Allow to totally disable all caching mechanisms (#778)
Browse files Browse the repository at this point in the history
  • Loading branch information
federicaagostini authored Aug 7, 2024
1 parent e8fe9be commit 621570f
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.oauth2.provider.OAuth2RequestValidator;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -42,7 +40,6 @@

@Service
@Transactional
@SuppressWarnings("deprecation")
public class DefaultClientService implements ClientService {

private final Clock clock;
Expand All @@ -55,10 +52,8 @@ public class DefaultClientService implements ClientService {

private OAuth2TokenEntityService tokenService;

@Autowired
public DefaultClientService(Clock clock, IamClientRepository clientRepo,
IamAccountClientRepository accountClientRepo, ApplicationEventPublisher eventPublisher,
OAuth2RequestValidator requestValidator, OAuth2TokenEntityService tokenService) {
IamAccountClientRepository accountClientRepo, ApplicationEventPublisher eventPublisher, OAuth2TokenEntityService tokenService) {
this.clock = clock;
this.clientRepo = clientRepo;
this.accountClientRepo = accountClientRepo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
package it.infn.mw.iam.config;

import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.support.NoOpCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
Expand All @@ -30,26 +31,31 @@
public class CacheConfig {

@Bean
@ConditionalOnProperty(name = "redis-cache.enabled", havingValue = "false")
public CacheManager localCacheManager() {
@ConditionalOnExpression("${cache.enabled} == false")
CacheManager fakeCacheManager(CacheProperties props) {
return new NoOpCacheManager();
}

@Bean
@ConditionalOnExpression("${cache.enabled} == true and ${cache.redis.enabled} == false")
CacheManager localCacheManager(CacheProperties props) {
return new ConcurrentMapCacheManager(IamWellKnownInfoProvider.CACHE_KEY,
DefaultScopeMatcherRegistry.SCOPE_CACHE_KEY);
}

@Bean
@ConditionalOnProperty(name = "redis-cache.enabled", havingValue = "true")
public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
@ConditionalOnExpression("${cache.enabled} == true and ${cache.redis.enabled} == true")
RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
return builder -> builder
.withCacheConfiguration(IamWellKnownInfoProvider.CACHE_KEY,
RedisCacheConfiguration.defaultCacheConfig())
.withCacheConfiguration(DefaultScopeMatcherRegistry.SCOPE_CACHE_KEY,
RedisCacheConfiguration.defaultCacheConfig());

}

@Bean
@ConditionalOnProperty(name = "redis-cache.enabled", havingValue = "true")
public RedisCacheConfiguration redisCacheConfiguration() {
@ConditionalOnExpression("${cache.enabled} == true and ${cache.redis.enabled} == true")
RedisCacheConfiguration redisCacheConfiguration() {

return RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,27 @@
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@ConfigurationProperties("redis-cache")
@ConfigurationProperties("cache")
@Configuration
public class RedisCacheProperties {
public class CacheProperties {

private boolean enabled = false;
public class RedisProperties {

private boolean enabled = false;

public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean enable) {
this.enabled = enable;
}

}

private boolean enabled = true;

private RedisProperties redis = new RedisProperties();

public boolean isEnabled() {
return enabled;
Expand All @@ -32,4 +48,13 @@ public void setEnabled(boolean enable) {
this.enabled = enable;
}

public RedisProperties getRedis() {
return redis;
}

public void setRedis(RedisProperties redis) {
this.redis = redis;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ private String getIssuerWithTrailingSlash() {
}

@Override
@Cacheable(CACHE_KEY)
@Cacheable(value = CACHE_KEY)
public Map<String, Object> getWellKnownInfo() {

Map<String, Object> result = newHashMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ spring:
flush-mode: immediate
namespace: iam:session

redis-cache:
enabled: true
cache:
redis:
enabled: true
6 changes: 4 additions & 2 deletions iam-login-service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,10 @@ iam:
client:
track-last-used: ${IAM_CLIENT_TRACK_LAST_USED:false}

redis-cache:
enabled: ${IAM_REDIS_CACHE_ENABLED:false}
cache:
enabled: ${IAM_CACHE_ENABLED:true}
redis:
enabled: ${IAM_CACHE_REDIS_ENABLED:false}

x509:
trustAnchorsDir: ${IAM_X509_TRUST_ANCHORS_DIR:/etc/grid-security/certificates}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;

import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down Expand Up @@ -103,7 +104,14 @@ public AccessTokenGetter audience(String audience) {
return this;
}

public String performTokenRequest() throws Exception {
public String performSuccessfulTokenRequest() throws Exception {

return performTokenRequest(200)
.getResponse()
.getContentAsString();
}

public MvcResult performTokenRequest(int statusCode) throws Exception {
MockHttpServletRequestBuilder req = post("/token").param("grant_type", grantType)
.param("client_id", clientId)
.param("client_secret", clientSecret);
Expand All @@ -120,18 +128,14 @@ public String performTokenRequest() throws Exception {
req.param("aud", audience);
}

String response = mvc.perform(req)
.andExpect(status().isOk())
.andReturn()
.getResponse()
.getContentAsString();

return response;
return mvc.perform(req)
.andExpect(status().is(statusCode))
.andReturn();
}

public DefaultOAuth2AccessToken getTokenResponseObject() throws Exception {

String response = performTokenRequest();
String response = performSuccessfulTokenRequest();

// This is incorrectly named in spring security OAuth, what they call OAuth2AccessToken
// is a TokenResponse object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;

Expand All @@ -36,8 +37,8 @@
import com.nimbusds.jwt.JWTParser;

import it.infn.mw.iam.api.client.service.ClientService;
import it.infn.mw.iam.config.CacheConfig;
import it.infn.mw.iam.config.RedisCacheProperties;
import it.infn.mw.iam.config.CacheProperties;
import it.infn.mw.iam.persistence.repository.client.IamClientRepository;
import it.infn.mw.iam.test.oauth.EndpointsTestUtils;
import it.infn.mw.iam.test.util.annotation.IamMockMvcIntegrationTest;

Expand All @@ -53,10 +54,13 @@ public class ScopeMatcherCacheTests extends EndpointsTestUtils {
private ClientService clientService;

@Autowired
private CacheConfig cacheConfig;

private IamClientRepository clientRepository;

@Autowired
private CacheManager localCacheManager;

@Autowired
private RedisCacheProperties redisCacheProperties;
private CacheProperties cacheProperties;

private String getAccessTokenForClient(String scopes) throws Exception {

Expand All @@ -67,10 +71,19 @@ private String getAccessTokenForClient(String scopes) throws Exception {
.getAccessTokenValue();
}

private void getAccessTokenForClientFailWithStatusCode(String scopes, int statusCode) throws Exception {

new AccessTokenGetter().grantType("client_credentials")
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
.scope(scopes)
.performTokenRequest(statusCode);
}

@Test
public void ensureRedisCashIsDisabled() {
assertFalse(redisCacheProperties.isEnabled());
assertThat(cacheConfig.localCacheManager(), instanceOf(CacheManager.class));
public void ensureRedisCacheIsDisabled() {
assertFalse(cacheProperties.getRedis().isEnabled());
assertThat(localCacheManager, instanceOf(ConcurrentMapCacheManager.class));
}

@Test
Expand All @@ -87,11 +100,14 @@ public void updatingClientScopesInvalidatesCache() throws ParseException, Except
assertThat("scim:read",
not(in(token.getJWTClaimsSet().getClaim("scope").toString().split(" "))));
client.setScope(Sets.newHashSet("openid", "profile", "email", "scim:read"));
clientRepository.save(client);
getAccessTokenForClientFailWithStatusCode("openid profile email scim:read", 400);
clientService.updateClient(client);
token = JWTParser.parse(getAccessTokenForClient("openid profile email scim:read"));
assertThat("scim:read", in(token.getJWTClaimsSet().getClaim("scope").toString().split(" ")));
} finally {
clientService.deleteClient(client);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
import org.junit.jupiter.api.Test;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.junit.jupiter.Container;
Expand All @@ -44,8 +44,7 @@

import io.restassured.RestAssured;
import it.infn.mw.iam.api.client.service.ClientService;
import it.infn.mw.iam.config.CacheConfig;
import it.infn.mw.iam.config.RedisCacheProperties;
import it.infn.mw.iam.config.CacheProperties;
import it.infn.mw.iam.test.TestUtils;
import it.infn.mw.iam.test.oauth.EndpointsTestUtils;
import it.infn.mw.iam.test.util.annotation.IamMockMvcIntegrationTest;
Expand All @@ -54,7 +53,7 @@
@Testcontainers
@IamMockMvcIntegrationTest
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = {"iam.access_token.include_scope=true", "redis-cache.enabled=true"})
properties = {"iam.access_token.include_scope=true", "cache.redis.enabled=true"})
public class ScopeMatcherExternalCacheTests extends EndpointsTestUtils {

private static final String CLIENT_ID = "cache-client";
Expand All @@ -68,17 +67,17 @@ public class ScopeMatcherExternalCacheTests extends EndpointsTestUtils {
private ClientService clientService;

@Autowired
private CacheConfig cacheConfig;

@Autowired
private RedisCacheProperties redisCacheProperties;
private CacheProperties redisCacheProperties;

@LocalServerPort
private Integer iamPort;

@Autowired
ObjectMapper mapper;

@Autowired
CacheManager cacheManager;

@Container
private static final RedisContainer REDIS = new RedisContainer();

Expand All @@ -93,10 +92,7 @@ public void setup() {
TestUtils.initRestAssured();
RestAssured.port = iamPort;
assertTrue(redisCacheProperties.isEnabled());
assertThat(cacheConfig.redisCacheConfiguration(), instanceOf(RedisCacheConfiguration.class));
assertThat(cacheConfig.redisCacheManagerBuilderCustomizer(),
instanceOf(RedisCacheManagerBuilderCustomizer.class));

assertThat(cacheManager, instanceOf(RedisCacheManager.class));
}

private String getAccessTokenForClient(String scopes) throws Exception {
Expand All @@ -106,7 +102,6 @@ private String getAccessTokenForClient(String scopes) throws Exception {
.clientSecret(CLIENT_SECRET)
.scope(scopes)
.getAccessTokenValue();

}

@Test
Expand Down
Loading

0 comments on commit 621570f

Please sign in to comment.