mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-02-26 16:30:50 +01:00
Add Configuration to JWT lifetime length
This commit is contained in:
@@ -57,6 +57,8 @@ public class ConfigDto extends HalRepresentation implements UpdateConfigDto {
|
||||
private String alertsUrl;
|
||||
private String releaseFeedUrl;
|
||||
private String mailDomainName;
|
||||
private int jwtExpirationInH;
|
||||
private boolean enabledJwtEndless;
|
||||
private Set<String> emergencyContacts;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -35,6 +35,7 @@ import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import sonia.scm.admin.ScmConfigurationStore;
|
||||
import sonia.scm.config.SecureKeyService;
|
||||
import sonia.scm.config.ConfigurationPermissions;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.repository.NamespaceStrategyValidator;
|
||||
@@ -57,18 +58,21 @@ public class ConfigResource {
|
||||
|
||||
private final NamespaceStrategyValidator namespaceStrategyValidator;
|
||||
private final JsonMerger jsonMerger;
|
||||
private final SecureKeyService secureKeyService;
|
||||
|
||||
|
||||
@Inject
|
||||
public ConfigResource(ScmConfigurationStore store, ConfigDtoToScmConfigurationMapper dtoToConfigMapper,
|
||||
ScmConfigurationToConfigDtoMapper configToDtoMapper,
|
||||
NamespaceStrategyValidator namespaceStrategyValidator,
|
||||
JsonMerger jsonMerger) {
|
||||
JsonMerger jsonMerger,
|
||||
SecureKeyService secureKeyService) {
|
||||
this.dtoToConfigMapper = dtoToConfigMapper;
|
||||
this.configToDtoMapper = configToDtoMapper;
|
||||
this.store = store;
|
||||
this.namespaceStrategyValidator = namespaceStrategyValidator;
|
||||
this.jsonMerger = jsonMerger;
|
||||
this.secureKeyService = secureKeyService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,6 +205,9 @@ public class ConfigResource {
|
||||
private void updateConfig(ConfigDto updatedConfigDto) {
|
||||
// ensure the namespace strategy is valid
|
||||
namespaceStrategyValidator.check(updatedConfigDto.getNamespaceStrategy());
|
||||
if (store.get().getJwtExpirationInH() > updatedConfigDto.getJwtExpirationInH()) {
|
||||
secureKeyService.clearAllTokens();
|
||||
}
|
||||
store.store(dtoToConfigMapper.map(updatedConfigDto));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2020 - present Cloudogu GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package sonia.scm.config;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import sonia.scm.security.SecureKeyResolver;
|
||||
|
||||
|
||||
public class SecureKeyService {
|
||||
|
||||
private final SecureKeyResolver secureKeyResolver;
|
||||
|
||||
@Inject
|
||||
public SecureKeyService(SecureKeyResolver secureKeyResolver) {
|
||||
this.secureKeyResolver = secureKeyResolver;
|
||||
}
|
||||
|
||||
public void clearAllTokens() {
|
||||
secureKeyResolver.deleteStore();
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
@@ -57,10 +58,11 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder {
|
||||
private final SecureKeyResolver keyResolver;
|
||||
private final JwtConfig jwtConfig;
|
||||
private final Clock clock;
|
||||
private final ScmConfiguration scmConfiguration;
|
||||
|
||||
private String subject;
|
||||
private String issuer;
|
||||
private long expiresIn = 1;
|
||||
private long expiresIn;
|
||||
private TimeUnit expiresInUnit = TimeUnit.HOURS;
|
||||
private long refreshableFor = DEFAULT_REFRESHABLE;
|
||||
private TimeUnit refreshableForUnit = DEFAULT_REFRESHABLE_UNIT;
|
||||
@@ -70,11 +72,13 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder {
|
||||
|
||||
private final Map<String,Object> custom = Maps.newHashMap();
|
||||
|
||||
JwtAccessTokenBuilder(KeyGenerator keyGenerator, SecureKeyResolver keyResolver, JwtConfig jwtConfig, Clock clock) {
|
||||
JwtAccessTokenBuilder(KeyGenerator keyGenerator, SecureKeyResolver keyResolver, JwtConfig jwtConfig, Clock clock, ScmConfiguration scmConfiguration) {
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.keyResolver = keyResolver;
|
||||
this.jwtConfig = jwtConfig;
|
||||
this.clock = clock;
|
||||
this.scmConfiguration = scmConfiguration;
|
||||
this.expiresIn = scmConfiguration.getJwtExpirationInH();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -179,6 +183,8 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder {
|
||||
|
||||
if(!jwtConfig.isEndlessJwtEnabled()) {
|
||||
claims.setExpiration(new Date(now.toEpochMilli() + expiration));
|
||||
} else {
|
||||
scmConfiguration.setEnabledJwtExpiration(true);
|
||||
}
|
||||
|
||||
if (refreshableFor > 0) {
|
||||
@@ -196,8 +202,7 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder {
|
||||
if ( issuer != null ) {
|
||||
claims.setIssuer(issuer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// sign token and create compact version
|
||||
String compact = Jwts.builder()
|
||||
.setClaims(claims)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package sonia.scm.security;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.plugin.Extension;
|
||||
|
||||
import java.time.Clock;
|
||||
@@ -35,25 +36,27 @@ public final class JwtAccessTokenBuilderFactory implements AccessTokenBuilderFac
|
||||
private final JwtConfig jwtConfig;
|
||||
private final Set<AccessTokenEnricher> enrichers;
|
||||
private final Clock clock;
|
||||
private final ScmConfiguration scmConfiguration;
|
||||
|
||||
@Inject
|
||||
public JwtAccessTokenBuilderFactory(
|
||||
KeyGenerator keyGenerator, SecureKeyResolver keyResolver, Set<AccessTokenEnricher> enrichers, JwtConfig jwtConfig) {
|
||||
this(keyGenerator, keyResolver, jwtConfig, enrichers, Clock.systemDefaultZone());
|
||||
KeyGenerator keyGenerator, SecureKeyResolver keyResolver, Set<AccessTokenEnricher> enrichers, JwtConfig jwtConfig, ScmConfiguration scmConfiguration) {
|
||||
this(keyGenerator, keyResolver, jwtConfig, enrichers, Clock.systemDefaultZone(), scmConfiguration);
|
||||
}
|
||||
|
||||
JwtAccessTokenBuilderFactory(
|
||||
KeyGenerator keyGenerator, SecureKeyResolver keyResolver, JwtConfig jwtConfig, Set<AccessTokenEnricher> enrichers, Clock clock) {
|
||||
KeyGenerator keyGenerator, SecureKeyResolver keyResolver, JwtConfig jwtConfig, Set<AccessTokenEnricher> enrichers, Clock clock, ScmConfiguration scmConfiguration) {
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.keyResolver = keyResolver;
|
||||
this.jwtConfig = jwtConfig;
|
||||
this.enrichers = enrichers;
|
||||
this.clock = clock;
|
||||
this.scmConfiguration = scmConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtAccessTokenBuilder create() {
|
||||
JwtAccessTokenBuilder builder = new JwtAccessTokenBuilder(keyGenerator, keyResolver, jwtConfig, clock);
|
||||
JwtAccessTokenBuilder builder = new JwtAccessTokenBuilder(keyGenerator, keyResolver, jwtConfig, clock, scmConfiguration);
|
||||
|
||||
// enrich access token builder
|
||||
enrichers.forEach((enricher) -> {
|
||||
|
||||
@@ -30,7 +30,7 @@ public class JwtConfig {
|
||||
@ConfigValue(
|
||||
key = "endlessJwt",
|
||||
defaultValue = "false",
|
||||
description = "The lifespan of the issued JWT tokens should be endless. Logged-in users are no longer automatically logged out.")
|
||||
description = "The lifespan of the issued JWT tokens should be endless. Logged-in users are no longer automatically logged out. Any other expiration time will be overridden")
|
||||
boolean endlessJwt) {
|
||||
this.endlessJwt = endlessJwt;
|
||||
}
|
||||
|
||||
@@ -131,4 +131,7 @@ public class SecureKeyResolver extends SigningKeyResolverAdapter
|
||||
return new SecureKey(bytes, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public void deleteStore() {
|
||||
store.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user