Skip to content

Commit

Permalink
Merge pull request jenkinsci#24 from iwarapter/token-lifetime
Browse files Browse the repository at this point in the history
Allow id token lifetime to be configurable
  • Loading branch information
jglick committed Nov 21, 2022
2 parents 3eace9d + b30776b commit 182a02f
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String, String> env;
if (build != null) {
Expand All @@ -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<List<ClaimTemplate>> addClaims = claimTemplates -> {
for (ClaimTemplate t : claimTemplates) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
return ExtensionList.lookupSingleton(IdTokenConfiguration.class);
}

private int tokenLifetime = 3600;

private @CheckForNull List<ClaimTemplate> claimTemplates;
private @CheckForNull List<ClaimTemplate> buildClaimTemplates;
private @CheckForNull List<ClaimTemplate> globalClaimTemplates;
Expand All @@ -80,6 +82,14 @@ public IdTokenConfiguration() {
}
}

public int getTokenLifetime() {
return tokenLifetime;
}

@DataBoundSetter public void setTokenLifetime(final int lifetime) {
this.tokenLifetime = lifetime;
}

public @NonNull List<ClaimTemplate> getClaimTemplates() {
return claimTemplates != null ? claimTemplates : DEFAULT_CLAIM_TEMPLATES;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ THE SOFTWARE.
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:section title="OpenID Connect">
<f:entry field="tokenLifetime" title="${%Token Lifetime}">
<f:number clazz="positive-number-required"/>
</f:entry>

<f:advanced title="${%Claim templates}" align="left">
<f:entry field="claimTemplates" title="${%General claim templates}">
<f:repeatableProperty field="claimTemplates">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
The time in seconds the issued id_token is valid for.
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -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()))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
security:
idToken:
tokenLifetime: 60
claimTemplates:
- name: ok
format: "true"
Expand Down

0 comments on commit 182a02f

Please sign in to comment.