WebToken.java

/*
 * Copyright © 2024 Indiana University
 * All rights reserved.
 *
 * BSD 3-Clause License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * - Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * 
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * 
 * - Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package edu.iu.crypt;

import java.net.URI;
import java.time.Duration;
import java.time.Instant;

import edu.iu.crypt.WebEncryption.Encryption;
import edu.iu.crypt.WebKey.Algorithm;
import edu.iu.crypt.WebKey.Use;

/**
 * Represents a JSON Web Token (JWT).
 */
public interface WebToken {

	/**
	 * Gets a mutable {@link WebTokenBuilder} instance.
	 * 
	 * @return {@link WebTokenBuilder}
	 */
	static WebTokenBuilder builder() {
		return Init.SPI.getJwtBuilder();
	}

	/**
	 * Convenience method to determine if a JWT is encrypted.
	 * 
	 * @param jwt JWT
	 * @return true if the JWT is encrypted; else false
	 */
	static boolean isEncrypted(String jwt) {
		return WebCryptoHeader.getProtectedHeader(jwt).getAlgorithm().use.equals(Use.ENCRYPT);
	}

	/**
	 * Verifies a signed JSON Web Token (JWT).
	 * 
	 * @param jwt       Signed JWT
	 * @param issuerKey Public key of the token issuer
	 * @return {@link WebToken}
	 */
	static WebToken verify(String jwt, WebKey issuerKey) {
		return Init.SPI.verifyJwt(jwt, issuerKey);
	}

	/**
	 * Decrypts and verifies a signed JSON Web Token (JWT).
	 * 
	 * @param jwt         Signed JWT
	 * @param issuerKey   Public key of the token issuer
	 * @param audienceKey Public key of the token audience
	 * @return {@link WebToken}
	 */
	static WebToken decryptAndVerify(String jwt, WebKey issuerKey, WebKey audienceKey) {
		return Init.SPI.decryptAndVerifyJwt(jwt, issuerKey, audienceKey);
	}

	/**
	 * Gets the token identifier.
	 * 
	 * @return token identifier (jti claim);
	 */
	String getTokenId();

	/**
	 * Gets the token issuer URI.
	 * 
	 * @return {@link URI}
	 */
	URI getIssuer();

	/**
	 * Gets the token audience URIs.
	 * 
	 * @return at least one {@link URI}
	 */
	Iterable<URI> getAudience();

	/**
	 * Gets the subject of the JWT.
	 * 
	 * @return subject (sub claim)
	 */
	String getSubject();

	/**
	 * Gets the time the JWT was issued.
	 * 
	 * @return issued time (iat claim)
	 */
	Instant getIssuedAt();

	/**
	 * Gets the time before which the JWT should not be accepted.
	 * 
	 * @return not before time (nbf claim)
	 */
	Instant getNotBefore();

	/**
	 * Gets the time after which the JWT should not be accepted.
	 * 
	 * @return token expiration time (exp claim)
	 */
	Instant getExpires();

	/**
	 * Gets the nonce claim.
	 * 
	 * @return nonce claim value
	 * @see <a href=
	 *      "https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes">OpenID
	 *      Connection Core 1.0 Section 15.5.2</a>
	 */
	String getNonce();

	/**
	 * Determines if the token has expired.
	 * 
	 * @return true if {@link #getExpires()} is in the past
	 */
	boolean isExpired();

	/**
	 * Verify JWT registered claims are well-formed and within the allowed time
	 * window.
	 * 
	 * <p>
	 * In addition to the rules outlined in
	 * <a href="https://datatracker.ietf.org/doc/html/rfc7519#section-4.1">RFC-7519
	 * JWT Section 4.1</a>, REQUIRES the following claim values to be present and
	 * not empty:
	 * </p>
	 * <ul>
	 * <li>{@link #getIssuer()}</li>
	 * <li>{@link #getAudience()}</li>
	 * <li>{@link #getSubject()}</li>
	 * <li>{@link #getIssuedAt()}</li>
	 * <li>{@link #getExpires()}</li>
	 * </ul>
	 * 
	 * @param audience Expected audience {@link URI}
	 * @param ttl      Maximum assertion time to live allowed by configuration
	 */
	void validateClaims(URI audience, Duration ttl);

	/**
	 * Encodes all claims as a signed JSON Web Token
	 * 
	 * @param type      token type; e.g., "JWT"
	 * @param algorithm signature algorithm
	 * @param issuerKey issuer key
	 * @return Signed JWT
	 */
	String sign(String type, Algorithm algorithm, WebKey issuerKey);

	/**
	 * Encodes all claims as a signed and encrypted JSON Web Token.
	 * 
	 * @param type             token type; e.g., "JWT"
	 * @param signAlgorithm    signature algorithm
	 * @param issuerKey        issuer key
	 * @param encryptAlgorithm key protection algorithm
	 * @param encryption       content encryption algorithm
	 * @param audienceKey      audience key
	 * @return Signed and encrypted JWT
	 */
	String signAndEncrypt(String type, Algorithm signAlgorithm, WebKey issuerKey, Algorithm encryptAlgorithm,
			Encryption encryption, WebKey audienceKey);

}