diff --git a/src/main/java/io/jenkins/plugins/oidc_provider/IdTokenCredentials.java b/src/main/java/io/jenkins/plugins/oidc_provider/IdTokenCredentials.java index 0948644..1de0a65 100644 --- a/src/main/java/io/jenkins/plugins/oidc_provider/IdTokenCredentials.java +++ b/src/main/java/io/jenkins/plugins/oidc_provider/IdTokenCredentials.java @@ -51,6 +51,7 @@ import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.RSAPublicKeySpec; +import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Base64; @@ -181,11 +182,12 @@ RSAPublicKey publicKey() { ))); protected final @NonNull String token() { + IdTokenConfiguration cfg = IdTokenConfiguration.get(); JwtBuilder builder = Jwts.builder(). setHeaderParam("kid", getId()). setIssuer(issuer != null ? issuer : findIssuer().url()). setAudience(audience). - setExpiration(Date.from(new Date().toInstant().plus(1, ChronoUnit.HOURS))). + setExpiration(Date.from(Instant.now().plus(cfg.getTokenLifetime(), ChronoUnit.SECONDS))). setIssuedAt(new Date()); Map env; if (build != null) { @@ -198,7 +200,6 @@ RSAPublicKey publicKey() { // EnvVars.masterEnvVars might not be safe to expose env = Collections.singletonMap("JENKINS_URL", Jenkins.get().getRootUrl()); } - IdTokenConfiguration cfg = IdTokenConfiguration.get(); AtomicBoolean definedSub = new AtomicBoolean(); Consumer> addClaims = claimTemplates -> { for (ClaimTemplate t : claimTemplates) { diff --git a/src/main/java/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration.java b/src/main/java/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration.java index 5d0f66e..af73211 100644 --- a/src/main/java/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration.java +++ b/src/main/java/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration.java @@ -57,6 +57,8 @@ return ExtensionList.lookupSingleton(IdTokenConfiguration.class); } + private int tokenLifetime = 3600; + private @CheckForNull List claimTemplates; private @CheckForNull List buildClaimTemplates; private @CheckForNull List globalClaimTemplates; @@ -80,6 +82,14 @@ public IdTokenConfiguration() { } } + public int getTokenLifetime() { + return tokenLifetime; + } + + @DataBoundSetter public void setTokenLifetime(final int lifetime) { + this.tokenLifetime = lifetime; + } + public @NonNull List getClaimTemplates() { return claimTemplates != null ? claimTemplates : DEFAULT_CLAIM_TEMPLATES; } diff --git a/src/main/resources/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration/config.jelly b/src/main/resources/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration/config.jelly index d7d2f7e..1a905ef 100644 --- a/src/main/resources/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration/config.jelly +++ b/src/main/resources/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration/config.jelly @@ -26,6 +26,10 @@ THE SOFTWARE. + + + + diff --git a/src/main/resources/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration/help-tokenLifetime.html b/src/main/resources/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration/help-tokenLifetime.html new file mode 100644 index 0000000..d5b7f14 --- /dev/null +++ b/src/main/resources/io/jenkins/plugins/oidc_provider/config/IdTokenConfiguration/help-tokenLifetime.html @@ -0,0 +1,3 @@ +
+ The time in seconds the issued id_token is valid for. +
diff --git a/src/test/java/io/jenkins/plugins/oidc_provider/ConfigurationAsCodeTest.java b/src/test/java/io/jenkins/plugins/oidc_provider/ConfigurationAsCodeTest.java index 33b83ba..24504a1 100644 --- a/src/test/java/io/jenkins/plugins/oidc_provider/ConfigurationAsCodeTest.java +++ b/src/test/java/io/jenkins/plugins/oidc_provider/ConfigurationAsCodeTest.java @@ -59,6 +59,7 @@ public class ConfigurationAsCodeTest { @ConfiguredWithCode("global.yaml") @Test public void globalConfiguration() throws Exception { IdTokenConfiguration cfg = IdTokenConfiguration.get(); + assertEquals(60, cfg.getTokenLifetime()); assertEquals(ClaimTemplate.xmlForm(Collections.singletonList(new ClaimTemplate("ok", "true", new BooleanClaimType()))), ClaimTemplate.xmlForm(cfg.getClaimTemplates())); assertEquals(ClaimTemplate.xmlForm(Collections.singletonList(new ClaimTemplate("sub", "jenkins", new StringClaimType()))), diff --git a/src/test/java/io/jenkins/plugins/oidc_provider/IdTokenCredentialsTest.java b/src/test/java/io/jenkins/plugins/oidc_provider/IdTokenCredentialsTest.java index cc4bbb0..090c313 100644 --- a/src/test/java/io/jenkins/plugins/oidc_provider/IdTokenCredentialsTest.java +++ b/src/test/java/io/jenkins/plugins/oidc_provider/IdTokenCredentialsTest.java @@ -40,6 +40,8 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import java.math.BigInteger; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -132,6 +134,24 @@ public class IdTokenCredentialsTest { }); } + @Test public void tokenLifetime() throws Throwable { + rr.then(r -> { + IdTokenStringCredentials c = new IdTokenStringCredentials(CredentialsScope.GLOBAL, "test", null); + CredentialsProvider.lookupStores(r.jenkins).iterator().next().addCredentials(Domain.global(), c); + IdTokenConfiguration cfg = IdTokenConfiguration.get(); + cfg.setTokenLifetime(60); + String idToken = c.getSecret().getPlainText(); + System.out.println(idToken); + Claims claims = Jwts.parserBuilder(). + setSigningKey(c.publicKey()). + build(). + parseClaimsJws(idToken). + getBody(); + + assertTrue(Instant.now().plus(61, ChronoUnit.SECONDS).isAfter(claims.getExpiration().toInstant())); + }); + } + @Test public void customClaims() throws Throwable { rr.then(r -> { IdTokenStringCredentials c = new IdTokenStringCredentials(CredentialsScope.GLOBAL, "test", null); diff --git a/src/test/resources/io/jenkins/plugins/oidc_provider/global.yaml b/src/test/resources/io/jenkins/plugins/oidc_provider/global.yaml index 026a9c8..861cc0b 100644 --- a/src/test/resources/io/jenkins/plugins/oidc_provider/global.yaml +++ b/src/test/resources/io/jenkins/plugins/oidc_provider/global.yaml @@ -1,5 +1,6 @@ security: idToken: + tokenLifetime: 60 claimTemplates: - name: ok format: "true"