All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.atlassian.asap.api.JwtBuilder Maven / Gradle / Ivy

package com.atlassian.asap.api;

import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;

import com.google.common.collect.ImmutableSet;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * A fluent builder for constructing a {@link com.atlassian.asap.api.Jwt} object.
 */
public final class JwtBuilder
{
    /**
     * Token lifetime, unless a specific lifetime is explicitly set. This is the time span between the
     * iat and the exp claims.
     */
    public static final Duration DEFAULT_LIFETIME = Duration.ofSeconds(60);

    private SigningAlgorithm alg;
    private String keyId;
    private String iss;
    private Optional sub;
    private Iterable aud;
    private Instant iat;
    private Instant exp;
    private Optional nbf;
    private String jti;

    private JwtBuilder()
    {
        Instant now = Instant.now();
        notBefore(Optional.of(now));
        issuedAt(now);
        expirationTime(now.plus(DEFAULT_LIFETIME));
        jwtId(UUID.randomUUID().toString());
        algorithm(SigningAlgorithm.RS256);
        sub = Optional.empty();
    }

    /**
     * Construct a simple jwt builder initialised with default claim values as follows:
     * 
    *
  • nbf, iat claim set to current system time
  • *
  • exp claim set current time plus default expiry as defined in {@link JwtBuilder#DEFAULT_LIFETIME}
  • *
  • jti claim set to a random UUID.
  • *
  • alg header set to {@link SigningAlgorithm#RS256}.
  • *
* @return a new fluent builder */ public static JwtBuilder newJwt() { return new JwtBuilder(); } /** * Returns a builder initialised with the given Jwt prototype. * * @param prototype Jwt to use as prototype * @return a Jwt builder initialised to be a copy of the prototype */ public static JwtBuilder copyJwt(Jwt prototype) { return new JwtBuilder() .algorithm(prototype.getHeader().getAlgorithm()) .keyId(prototype.getHeader().getKeyId()) .issuer(prototype.getClaims().getIssuer()) .subject(prototype.getClaims().getSubject()) .audience(prototype.getClaims().getAudience()) .issuedAt(prototype.getClaims().getIssuedAt()) .expirationTime(prototype.getClaims().getExpiry()) .notBefore(prototype.getClaims().getNotBefore()) .jwtId(prototype.getClaims().getJwtId()); } /** * Sets the key id jws header. * @param keyId the key id for the jws header of this jwt * @return the fluent builder */ public JwtBuilder keyId(String keyId) { this.keyId = keyId; return this; } /** * Sets the algorithm (alg) jws header. * @param alg the alg for the jws header of this jwt * @return the fluent builder */ public JwtBuilder algorithm(SigningAlgorithm alg) { this.alg = alg; return this; } /** * Sets the audience (aud) claim. * @param aud an iterable containing one or more audiences for the jwt * @return the fluent builder */ public JwtBuilder audience(Iterable aud) { this.aud = ImmutableSet.copyOf(aud); return this; } /** * Sets the audience (aud) claim. * @param aud one or more audiences for the jwt * @return the fluent builder */ public JwtBuilder audience(String... aud) { this.aud = ImmutableSet.copyOf(aud); return this; } /** * Sets the expiration time (exp) claim. * @param expiry the expiration time * @return the fluent builder */ public JwtBuilder expirationTime(Instant expiry) { this.exp = expiry; return this; } /** * Set the issued at (iat) claim. * @param iat the issued at time * @return the fluent builder */ public JwtBuilder issuedAt(Instant iat) { this.iat = iat; return this; } /** * Set the issuer (iss) claim. * @param iss the issuer * @return the fluent builder */ public JwtBuilder issuer(String iss) { this.iss = iss; return this; } /** * Set the jwt id (jti) claim. * @param jti a unique id for the jwt * @return the fluent builder */ public JwtBuilder jwtId(String jti) { this.jti = jti; return this; } /** * Set the not before (nbf) claim. * @param nbf the not before date * @return the fluent builder */ public JwtBuilder notBefore(Optional nbf) { this.nbf = nbf; return this; } /** * Sets the subject (sub) claim for this jwt. * @param sub the subject * @return the fluent builder */ public JwtBuilder subject(Optional sub) { this.sub = sub; return this; } /** * @return a JWT object representing all the values specified to this builder * @throws java.lang.NullPointerException if some required parameter has not been specified */ public Jwt build() { JwsHeader header = new ImmutableJwsHeader(alg, keyId); JwtClaims claims = new ImmutableJwtClaims(iss, sub, aud, exp, nbf, iat, jti); return new ImmutableJwt(header, claims); } /** * An immutable value object that represents a JWT. */ private static class ImmutableJwt implements Jwt { private final JwsHeader header; private final JwtClaims claimsSet; ImmutableJwt(JwsHeader header, JwtClaims claims) { this.header = Objects.requireNonNull(header); this.claimsSet = Objects.requireNonNull(claims); } @Override public JwsHeader getHeader() { return header; } @Override public JwtClaims getClaims() { return claimsSet; } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) .append("header", header) .append("claims", claimsSet) .toString(); } @Override public boolean equals(Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o.getClass() != getClass()) { return false; } ImmutableJwt rhs = (ImmutableJwt) o; return new EqualsBuilder() .append(header, rhs.header) .append(claimsSet, rhs.claimsSet) .isEquals(); } @Override public int hashCode() { return new HashCodeBuilder() .append(header) .append(claimsSet) .hashCode(); } } /** * An immutable value object that represents the information contained in the JWS header. */ private static final class ImmutableJwsHeader implements JwsHeader { private final SigningAlgorithm algorithm; private final String keyId; ImmutableJwsHeader(SigningAlgorithm algorithm, String keyId) { this.algorithm = Objects.requireNonNull(algorithm, "JWT header 'alg' cannot be null"); this.keyId = Objects.requireNonNull(keyId, "JWT header 'kid' cannot be null"); } @Override public String getKeyId() { return keyId; } @Override public SigningAlgorithm getAlgorithm() { return algorithm; } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) .append(Header.ALGORITHM.key(), algorithm) .append(Header.KEY_ID.key(), keyId) .toString(); } @Override public boolean equals(Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o.getClass() != getClass()) { return false; } ImmutableJwsHeader rhs = (ImmutableJwsHeader) o; return new EqualsBuilder() .append(algorithm, rhs.algorithm) .append(keyId, rhs.keyId) .isEquals(); } @Override public int hashCode() { return new HashCodeBuilder() .append(algorithm) .append(keyId) .hashCode(); } } /** * An immutable value object that represents the information contained in the claims (payload) of a JWT. */ private static class ImmutableJwtClaims implements JwtClaims { private final String iss; private final Optional sub; private final Set aud; private final Instant expiry; private final Optional notBefore; private final Instant issuedAt; private final String jwtId; ImmutableJwtClaims(String iss, Optional sub, Iterable aud, Instant exp, Optional nbf, Instant iat, String jti) { this.iss = Objects.requireNonNull(iss, "JWT claim 'iss' cannot be null"); this.sub = Objects.requireNonNull(sub, "JWT claim 'sub' cannot be null (but it can be None)"); this.aud = ImmutableSet.copyOf(Objects.requireNonNull(aud, "JWT claim 'aud' cannot be null")); this.issuedAt = Objects.requireNonNull(iat, "JWT claim 'iat' cannot be null"); this.expiry = Objects.requireNonNull(exp, "JWT claim 'exp' cannot be null"); this.notBefore = Objects.requireNonNull(nbf, "JWT claim 'nbf' cannot be null (but it can be None)"); this.jwtId = Objects.requireNonNull(jti, "JWT claim 'jit' cannot be null"); } @Override public String getIssuer() { return iss; } @Override public Optional getSubject() { return sub; } @Override public Set getAudience() { return aud; } @Override public Instant getExpiry() { return expiry; } @Override public Optional getNotBefore() { return notBefore; } @Override public Instant getIssuedAt() { return issuedAt; } @Override public String getJwtId() { return jwtId; } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) .append(Claim.ISSUER.key(), iss) .append(Claim.SUBJECT.key(), sub) .append(Claim.AUDIENCE.key(), aud) .append(Claim.ISSUED_AT.key(), issuedAt) .append(Claim.EXPIRY.key(), expiry) .append(Claim.NOT_BEFORE.key(), notBefore) .append(Claim.JWT_ID.key(), jwtId) .toString(); } @Override public boolean equals(Object o) { if (o == null) { return false; } if (o == this) { return true; } if (o.getClass() != getClass()) { return false; } ImmutableJwtClaims rhs = (ImmutableJwtClaims) o; return new EqualsBuilder() .append(iss, rhs.iss) .append(sub, rhs.sub) .append(aud, rhs.aud) .append(issuedAt, rhs.issuedAt) .append(expiry, rhs.expiry) .append(notBefore, rhs.notBefore) .append(jwtId, rhs.jwtId) .isEquals(); } @Override public int hashCode() { return new HashCodeBuilder() .append(iss) .append(sub) .append(aud) .append(issuedAt) .append(expiry) .append(notBefore) .append(jwtId) .hashCode(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy