Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show unrestricted scopes into well-known endpoint #628

Merged
merged 12 commits into from
Apr 10, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"it.infn.mw.iam.authn",
"it.infn.mw.iam.persistence",
"it.infn.mw.iam.core",
"it.infn.mw.iam.core.web.wellknown",
"it.infn.mw.iam.core.oauth.scope",
"it.infn.mw.iam.core.time",
"it.infn.mw.iam.api",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,13 @@
@Configuration
public class CacheConfig {


@Bean
@ConditionalOnProperty(name = "redis-cache.enabled", havingValue = "false")
public CacheManager localCacheManager() {
return new ConcurrentMapCacheManager(IamWellKnownInfoProvider.CACHE_KEY,
DefaultScopeMatcherRegistry.SCOPE_CACHE_KEY);
}


@Bean
@ConditionalOnProperty(name = "redis-cache.enabled", havingValue = "true")
public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
Expand All @@ -49,13 +47,11 @@ public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {

}

federicaagostini marked this conversation as resolved.
Show resolved Hide resolved

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

return RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues();

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import java.time.Clock;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import org.h2.server.web.WebServlet;
import org.mitre.oauth2.repository.SystemScopeRepository;
Expand Down Expand Up @@ -306,4 +308,9 @@ UsernameValidator usernameRegExpValidator() {
return new UsernameValidator();
}

@Bean(destroyMethod = "shutdown")
public ScheduledExecutorService taskScheduler() {
return Executors.newSingleThreadScheduledExecutor();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
*/
package it.infn.mw.iam.config;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

import org.mitre.oauth2.service.DeviceCodeService;
Expand All @@ -26,7 +25,8 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.EnableScheduling;
Expand All @@ -37,6 +37,7 @@
import it.infn.mw.iam.config.lifecycle.LifecycleProperties;
import it.infn.mw.iam.core.lifecycle.ExpiredAccountsHandler;
import it.infn.mw.iam.core.user.IamAccountService;
import it.infn.mw.iam.core.web.wellknown.IamWellKnownInfoProvider;
import it.infn.mw.iam.notification.NotificationDelivery;
import it.infn.mw.iam.notification.NotificationDeliveryTask;
import it.infn.mw.iam.notification.service.NotificationStoreService;
Expand Down Expand Up @@ -83,16 +84,23 @@ public class TaskConfig implements SchedulingConfigurer {
@Autowired
ExpiredAccountsHandler expiredAccountsHandler;

@Autowired
CacheManager cacheManager;

@Autowired
ExecutorService taskScheduler;

@Value("${notification.disable}")
boolean notificationDisabled;

@Value("${notification.taskDelay}")
long notificationTaskPeriodMsec;


@Bean(destroyMethod = "shutdown")
public ScheduledExecutorService taskScheduler() {
return Executors.newSingleThreadScheduledExecutor();
@Scheduled(fixedRateString = "${task.wellKnownCacheCleanupPeriodSecs:300}",
timeUnit = TimeUnit.SECONDS)
@CacheEvict(allEntries = true, cacheNames = IamWellKnownInfoProvider.CACHE_KEY)
public void logWellKnownCacheEviction() {
LOG.debug("well-known config cache evicted");
}

@Scheduled(fixedDelayString = "${task.tokenCleanupPeriodMsec}", initialDelay = TEN_MINUTES_MSEC)
Expand Down Expand Up @@ -146,7 +154,7 @@ public void scheduledExpiredAccountsTask(final ScheduledTaskRegistrar taskRegist

@Override
public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
taskRegistrar.setScheduler(taskScheduler);
schedulePendingNotificationsDelivery(taskRegistrar);
scheduledExpiredAccountsTask(taskRegistrar);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService;
import org.mitre.oauth2.model.PKCEAlgorithm;
Expand All @@ -31,11 +30,7 @@
import org.mitre.oauth2.web.IntrospectionEndpoint;
import org.mitre.oauth2.web.RevocationEndpoint;
import org.mitre.openid.connect.web.UserInfoEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import com.nimbusds.jose.Algorithm;
Expand All @@ -50,8 +45,6 @@
@Service
public class IamWellKnownInfoProvider implements WellKnownInfoProvider {

private static final Logger LOG = LoggerFactory.getLogger(IamWellKnownInfoProvider.class);

public static final String CACHE_KEY = "well-known-config";

public static final String AUTHORIZE_ENDPOINT = "authorize";
Expand Down Expand Up @@ -225,15 +218,10 @@ public Map<String, Object> getWellKnownInfo() {

result.put("code_challenge_methods_supported", CODE_CHALLENGE_METHODS);

updateSupportedScopes();
result.put("scopes_supported", supportedScopes);

return result;
}

@Scheduled(fixedDelay = 5, timeUnit = TimeUnit.MINUTES)
@CacheEvict(allEntries = true, cacheNames = CACHE_KEY)
protected void evictCacheAndUpdateSupportedScopes() {
updateSupportedScopes();
LOG.debug("well-known config cache evicted");
}
}
1 change: 1 addition & 0 deletions iam-login-service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ task:
tokenCleanupPeriodMsec: ${IAM_TOKEN_CLEANUP_PERIOD_MSEC:300000}
approvalCleanupPeriodMsec: ${IAM_APPROVAL_CLEANUP_PERIOD_MSEC:300000}
deviceCodeCleanupPeriodMsec: ${IAM_DEVICE_CODE_CLEANUP_PERIOD_MSEC:300000}
wellKnownCacheCleanupPeriodSecs: ${IAM_WELL_KNOWN_CACHE_CLEANUP_PERIOD_SECS:300}

client-registration:
allow-for: ${IAM_CLIENT_REGISTRATION_ALLOW_FOR:ANYONE}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package it.infn.mw.iam.test.oauth;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasItem;
Expand All @@ -36,6 +37,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

Expand All @@ -52,6 +55,8 @@
@RunWith(SpringRunner.class)
@IamMockMvcIntegrationTest
@SpringBootTest(classes = {IamLoginService.class}, webEnvironment = WebEnvironment.MOCK)
@TestPropertySource(properties = "task.wellKnownCacheCleanupPeriodSecs=1")
@ActiveProfiles({"h2-test", "dev"})
public class WellKnownConfigurationEndpointTests {

private String endpoint = "/" + IamDiscoveryEndpoint.OPENID_CONFIGURATION_URL;
Expand All @@ -65,6 +70,9 @@ public class WellKnownConfigurationEndpointTests {
private static final String IAM_GROUPS_CLAIM = "groups";
private static final String IAM_EXTERNAL_AUTHN_CLAIM = "external_authn";

private static final String SYSTEM_SCOPE_0 = "new-scope0";
private static final String SYSTEM_SCOPE_1 = "new-scope1";

@Autowired
private MockMvc mvc;

Expand Down Expand Up @@ -155,4 +163,38 @@ public void testScopes() throws Exception {

}

@Test
public void testWellKnownCacheEviction() throws Exception {

SystemScope scope = new SystemScope(SYSTEM_SCOPE_0);
scopeService.save(scope);

mvc.perform(get(endpoint))
.andExpect(status().isOk())
.andExpect(jsonPath("$.scopes_supported", notNullValue()))
.andExpect(jsonPath("$.scopes_supported").isArray())
.andExpect(jsonPath("$.scopes_supported", hasItem(SYSTEM_SCOPE_0)));

scope = new SystemScope(SYSTEM_SCOPE_1);
scopeService.save(scope);

mvc.perform(get(endpoint))
.andExpect(status().isOk())
.andExpect(jsonPath("$.scopes_supported", notNullValue()))
.andExpect(jsonPath("$.scopes_supported").isArray())
.andExpect(jsonPath("$.scopes_supported", not(SYSTEM_SCOPE_1)));

try {
Thread.sleep(1100);
} catch (InterruptedException e) {
}

mvc.perform(get(endpoint))
.andExpect(status().isOk())
.andExpect(jsonPath("$.scopes_supported", notNullValue()))
.andExpect(jsonPath("$.scopes_supported").isArray())
.andExpect(jsonPath("$.scopes_supported", hasItem(SYSTEM_SCOPE_1)));

}

}
Loading