SessionTokenClaims class
Пакет: com.hypixel.hytale.server.core.auth
Файл: com/hypixel/hytale/server/core/auth/JWTValidator.java
Поля (6)
| Модификаторы | Тип | Имя |
|---|---|---|
|
public Long |
expiresAt |
|
public Long |
issuedAt |
|
public String |
issuer |
|
public Long |
notBefore |
|
public String |
scope |
|
public String |
subject |
Методы (5)
| Модификаторы | Возврат | Сигнатура |
|---|---|---|
|
public String[] |
getScopespublic String[] getScopes() |
|
public UUID |
getSubjectAsUUIDpublic UUID getSubjectAsUUID() |
|
public boolean |
hasScopepublic boolean hasScope(@Nonnull String var1) |
|
|
if if(this.subject == null) |
|
public String |
toLogSummarypublic String toLogSummary() |
Исходный код
Показать/скрыть
class="kw">package com.hypixel.hytale.server.core.auth;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.nimbusds.jose.JWSAlgorithm;
class="kw">import com.nimbusds.jose.crypto.Ed25519Verifier;
class="kw">import com.nimbusds.jose.jwk.JWK;
class="kw">import com.nimbusds.jose.jwk.JWKSet;
class="kw">import com.nimbusds.jose.jwk.OctetKeyPair;
class="kw">import com.nimbusds.jwt.JWTClaimsSet;
class="kw">import com.nimbusds.jwt.SignedJWT;
class="kw">import java.io.IOException;
class="kw">import java.io.InputStream;
class="kw">import java.nio.charset.StandardCharsets;
class="kw">import java.nio.file.Files;
class="kw">import java.nio.file.Path;
class="kw">import java.security.cert.X509Certificate;
class="kw">import java.text.ParseException;
class="kw">import java.time.Duration;
class="kw">import java.time.Instant;
class="kw">import java.util.ArrayList;
class="kw">import java.util.List;
class="kw">import java.util.Map;
class="kw">import java.util.UUID;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.concurrent.locks.ReentrantLock;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;
class="kw">public class JWTValidator {
class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
class="kw">private class="kw">static class="kw">final long CLOCK_SKEW_SECONDS = 300L;
class="kw">private class="kw">static class="kw">final JWSAlgorithm SUPPORTED_ALGORITHM = JWSAlgorithm.EdDSA;
class="kw">private class="kw">static class="kw">final int MIN_SIGNATURE_LENGTH = 80;
class="kw">private class="kw">static class="kw">final int MAX_SIGNATURE_LENGTH = 90;
class="kw">private class="kw">static class="kw">final Duration JWKS_REFRESH_MIN_INTERVAL = Duration.ofMinutes(5L);
class="kw">private class="kw">static class="kw">final String JWKS_BUNDLED_RESOURCE = "/jwks_bundled.json";
class="kw">private class="kw">static class="kw">final String JWKS_CACHE_FILE = ".jwks.json";
class="kw">private class="kw">final SessionServiceClient sessionServiceClient;
class="kw">private class="kw">final String expectedIssuer;
class="kw">private class="kw">final String expectedAudience;
class="kw">private class="kw">volatile JWKSet cachedJwkSet;
class="kw">private class="kw">final ReentrantLock jwksFetchLock = new ReentrantLock();
class="kw">private class="kw">volatile CompletableFuture<JWKSet> pendingFetch = null;
class="kw">private class="kw">volatile Instant lastJwksRefresh;
class="kw">public JWTValidator(@Nonnull SessionServiceClient var1, @Nonnull String var2, @Nonnull String var3) {
this.sessionServiceClient = var1;
this.expectedIssuer = var2;
this.expectedAudience = var3;
this.preSeedJwksCache();
}
@Nullable
class="kw">private class="kw">static String validateJwtStructure(@Nonnull String var0, @Nonnull String var1) {
if (var0.isEmpty()) {
class="kw">return var1 + " is empty";
}
String[] var2 = var0.split("\\.", -1);
if (var2.length != 3) {
class="kw">return String.format("%s has invalid format (expected 3 parts, got %d)", var1, var2.length);
}
if (var2[2].isEmpty()) {
class="kw">return var1 + " has empty signature - possible signature stripping attack";
}
int var3 = var2[2].length();
class="kw">return var3 >= 80 && var3 <= 90 ? null : String.format("%s has invalid signature length: %d (expected %d-%d)", var1, var3, 80, 90);
}
@Nullable
class="kw">public JWTValidator.JWTClaims validateToken(@Nonnull String var1, @Nullable X509Certificate var2) {
String var3 = validateJwtStructure(var1, "Access token");
if (var3 != null) {
LOGGER.at(Level.WARNING).log("%s", var3);
class="kw">return null;
}
try {
SignedJWT var4 = SignedJWT.parse(var1);
JWSAlgorithm var5 = var4.getHeader().getAlgorithm();
if (!SUPPORTED_ALGORITHM.equals(var5)) {
LOGGER.at(Level.WARNING).log("Unsupported JWT algorithm: %s (expected EdDSA)", var5);
class="kw">return null;
}
if (!this.verifySignatureWithRetry(var4)) {
LOGGER.at(Level.WARNING).log("JWT signature verification failed");
class="kw">return null;
}
JWTClaimsSet var6 = var4.getJWTClaimsSet();
JWTValidator.JWTClaims var7 = new JWTValidator.JWTClaims();
var7.issuer = var6.getIssuer();
var7.audience = var6.getAudience() != null && !var6.getAudience().isEmpty() ? (String)var6.getAudience().get(0) : null;
var7.subject = var6.getSubject();
var7.username = var6.getStringClaim("username");
var7.issuedAt = var6.getIssueTime() != null ? var6.getIssueTime().toInstant().getEpochSecond() : null;
var7.expiresAt = var6.getExpirationTime() != null ? var6.getExpirationTime().toInstant().getEpochSecond() : null;
var7.notBefore = var6.getNotBeforeTime() != null ? var6.getNotBeforeTime().toInstant().getEpochSecond() : null;
Map var8 = var6.getJSONObjectClaim("cnf");
if (var8 != null) {
var7.certificateFingerprint = (String)var8.get("x5t#S256");
}
if (!this.expectedIssuer.equals(var7.issuer)) {
LOGGER.at(Level.WARNING).log("Invalid issuer: expected %s, got %s. Token: %s", this.expectedIssuer, var7.issuer, var7.toLogSummary());
class="kw">return null;
} else if (!this.expectedAudience.equals(var7.audience)) {
LOGGER.at(Level.WARNING).log("Invalid audience: expected %s, got %s. Token: %s", this.expectedAudience, var7.audience, var7.toLogSummary());
class="kw">return null;
} else {
long var9 = Instant.now().getEpochSecond();
if (var7.expiresAt == null) {
LOGGER.at(Level.WARNING).log("Access token missing expiration claim. Token: %s", var7.toLogSummary());
class="kw">return null;
} else if (var9 >= var7.expiresAt + 300L) {
LOGGER.at(Level.WARNING).log("Token expired (exp: %d, now: %d). Token: %s", var7.expiresAt, var9, var7.toLogSummary());
class="kw">return null;
} else if (var7.notBefore != null && var9 < var7.notBefore - 300L) {
LOGGER.at(Level.WARNING).log("Token not yet valid (nbf: %d, now: %d). Token: %s", var7.notBefore, var9, var7.toLogSummary());
class="kw">return null;
} else if (var7.issuedAt != null && var7.issuedAt > var9 + 300L) {
LOGGER.at(Level.WARNING).log("Token issued in the future (iat: %d, now: %d). Token: %s", var7.issuedAt, var9, var7.toLogSummary());
class="kw">return null;
} else if (!CertificateUtil.validateCertificateBinding(var7.certificateFingerprint, var2)) {
LOGGER.at(Level.WARNING).log("Certificate binding validation failed. Token: %s", var7.toLogSummary());
class="kw">return null;
} else if (var7.getSubjectAsUUID() == null) {
LOGGER.at(Level.WARNING).log("Access token has invalid or missing subject UUID. Token: %s", var7.toLogSummary());
class="kw">return null;
} else {
LOGGER.at(Level.INFO).log("JWT validated successfully for user %s. Token: %s", var7.username, var7.toLogSummary());
class="kw">return var7;
}
}
} catch (ParseException var11) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var11)).log("Failed to parse JWT");
class="kw">return null;
} catch (Exception var12) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var12)).log("JWT validation error");
class="kw">return null;
}
}
class="kw">private boolean verifySignature(SignedJWT var1, JWKSet var2) {
try {
String var3 = var1.getHeader().getKeyID();
OctetKeyPair var4 = null;
for (JWK var6 : var2.getKeys()) {
if (var6 class="kw">instanceof OctetKeyPair var7 && (var3 == null || var3.equals(var6.getKeyID()))) {
var4 = var7;
break;
}
}
if (var4 == null) {
LOGGER.at(Level.WARNING).log("No Ed25519 key found for kid=%s", var3);
class="kw">return false;
}
Ed25519Verifier var9 = new Ed25519Verifier(var4);
boolean var10 = var1.verify(var9);
if (var10) {
LOGGER.at(Level.FINE).log("JWT signature verified with key kid=%s", var3);
}
class="kw">return var10;
} catch (Exception var8) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var8)).log("JWT signature verification failed");
class="kw">return false;
}
}
@Nullable
class="kw">private JWKSet getJwkSet() {
class="kw">return this.getJwkSet(false);
}
@Nullable
class="kw">private JWKSet getJwkSet(boolean var1) {
if (!var1 && this.cachedJwkSet != null) {
class="kw">return this.cachedJwkSet;
}
this.jwksFetchLock.lock();
try {
if (!var1 && this.cachedJwkSet != null) {
class="kw">return this.cachedJwkSet;
}
CompletableFuture var2 = this.pendingFetch;
if (var2 != null && !var2.isDone()) {
this.jwksFetchLock.unlock();
try {
class="kw">return var2.join();
} class="kw">finally {
this.jwksFetchLock.lock();
}
}
if (var1) {
LOGGER.at(Level.INFO).log("Force refreshing JWKS cache (key rotation or verification failure)");
}
this.pendingFetch = CompletableFuture.supplyAsync(this::fetchJwksFromService);
} class="kw">finally {
this.jwksFetchLock.unlock();
}
class="kw">return this.pendingFetch.join();
}
@Nullable
class="kw">private JWKSet fetchJwksFromService() {
SessionServiceClient.JwksResponse var1 = this.sessionServiceClient.getJwks();
if (var1 != null && var1.keys != null && var1.keys.length != 0) {
try {
ArrayList var2 = new ArrayList<>();
for (SessionServiceClient.JwkKey var6 : var1.keys) {
JWK var7 = this.convertToJWK(var6);
if (var7 != null) {
var2.add(var7);
}
}
if (var2.isEmpty()) {
LOGGER.at(Level.WARNING).log("No valid JWKs found in JWKS response");
class="kw">return this.cachedJwkSet;
} else {
JWKSet var9 = new JWKSet(var2);
this.cachedJwkSet = var9;
this.lastJwksRefresh = Instant.now();
this.saveJwksCacheToDisk(var9);
LOGGER.at(Level.INFO).log("JWKS loaded with %d keys (cached permanently)", var2.size());
class="kw">return var9;
}
} catch (Exception var8) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var8)).log("Failed to parse JWKS");
class="kw">return this.cachedJwkSet;
}
} else {
LOGGER.at(Level.WARNING).log("Failed to fetch JWKS or no keys available");
class="kw">return this.cachedJwkSet;
}
}
class="kw">private boolean verifySignatureWithRetry(SignedJWT var1) {
JWKSet var2 = this.getJwkSet();
if (var2 == null) {
class="kw">return false;
} else if (this.verifySignature(var1, var2)) {
class="kw">return true;
} else if (!this.canForceRefreshJwks()) {
LOGGER.at(Level.FINE).log("Signature verification failed but JWKS was refreshed recently; skipping refresh");
class="kw">return false;
} else {
LOGGER.at(Level.INFO).log("Signature verification failed with cached JWKS, retrying with fresh keys");
JWKSet var3 = this.getJwkSet(true);
class="kw">return var3 != null && var3 != var2 ? this.verifySignature(var1, var3) : false;
}
}
class="kw">private boolean canForceRefreshJwks() {
Instant var1 = this.lastJwksRefresh;
class="kw">return var1 == null ? true : Duration.between(var1, Instant.now()).compareTo(JWKS_REFRESH_MIN_INTERVAL) >= 0;
}
@Nullable
class="kw">private JWK convertToJWK(SessionServiceClient.JwkKey var1) {
if (!"OKP".equals(var1.kty)) {
LOGGER.at(Level.WARNING).log("Unsupported key type: %s (expected OKP)", var1.kty);
class="kw">return null;
}
try {
String var2 = String.format("{\"kty\":\"OKP\",\"crv\":\"%s\",\"x\":\"%s\",\"kid\":\"%s\",\"alg\":\"EdDSA\"}", var1.crv, var1.x, var1.kid);
class="kw">return JWK.parse(var2);
} catch (Exception var3) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var3)).log("Failed to parse Ed25519 key");
class="kw">return null;
}
}
class="kw">private void preSeedJwksCache() {
JWKSet var1 = this.loadJwksCacheFromDisk();
if (var1 != null) {
this.cachedJwkSet = var1;
LOGGER.at(Level.INFO).log("JWKS pre-seeded from disk cache (%d keys)", var1.getKeys().size());
} else {
JWKSet var2 = this.loadEmbeddedJwks();
if (var2 != null) {
this.cachedJwkSet = var2;
LOGGER.at(Level.INFO).log("JWKS pre-seeded from embedded resource (%d keys)", var2.getKeys().size());
} else {
LOGGER.at(Level.INFO).log("No pre-seeded JWKS available, will fetch from network on first validation");
}
}
}
@Nullable
class="kw">private JWKSet loadEmbeddedJwks() {
try (InputStream var1 = this.getClass().getResourceAsStream("/jwks_bundled.json")) {
if (var1 == null) {
LOGGER.at(Level.FINE).log("No embedded JWKS resource found");
class="kw">return null;
} else {
String var2 = new String(var1.readAllBytes(), StandardCharsets.UTF_8);
class="kw">return JWKSet.parse(var2);
}
} catch (IOException | ParseException var6) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var6)).log("Failed to load embedded JWKS");
class="kw">return null;
}
}
@Nullable
class="kw">private JWKSet loadJwksCacheFromDisk() {
Path var1 = Path.of(".jwks.json");
if (!Files.exists(var1)) {
class="kw">return null;
}
try {
String var2 = Files.readString(var1, StandardCharsets.UTF_8);
JWKSet var3 = JWKSet.parse(var2);
LOGGER.at(Level.FINE).log("Loaded JWKS cache from disk: %s", var1);
class="kw">return var3;
} catch (IOException | ParseException var4) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var4)).log("Failed to load JWKS cache from disk");
class="kw">return null;
}
}
class="kw">private void saveJwksCacheToDisk(@Nonnull JWKSet var1) {
try {
Files.writeString(Path.of(".jwks.json"), var1.toString(), StandardCharsets.UTF_8);
LOGGER.at(Level.FINE).log("Saved JWKS cache to disk");
} catch (IOException var3) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var3)).log("Failed to save JWKS cache to disk");
}
}
@Nullable
class="kw">public JWTValidator.IdentityTokenClaims validateOfflineToken(@Nonnull String var1) {
JWTValidator.IdentityTokenClaims var2 = this.validateIdentityToken(var1);
if (var2 == null) {
class="kw">return null;
} else if (!var2.hasScope("hytale:offline")) {
LOGGER.at(Level.WARNING).log("Offline token missing required scope: expected %s, got %s", "hytale:offline", var2.scope);
class="kw">return null;
} else {
class="kw">return var2;
}
}
class="kw">public void invalidateJwksCache() {
this.jwksFetchLock.lock();
try {
this.cachedJwkSet = null;
this.pendingFetch = null;
} class="kw">finally {
this.jwksFetchLock.unlock();
}
}
@Nullable
class="kw">public JWTValidator.IdentityTokenClaims validateIdentityToken(@Nonnull String var1) {
String var2 = validateJwtStructure(var1, "Identity token");
if (var2 != null) {
LOGGER.at(Level.WARNING).log("%s", var2);
class="kw">return null;
}
try {
SignedJWT var3 = SignedJWT.parse(var1);
JWSAlgorithm var4 = var3.getHeader().getAlgorithm();
if (!SUPPORTED_ALGORITHM.equals(var4)) {
LOGGER.at(Level.WARNING).log("Unsupported identity token algorithm: %s (expected EdDSA)", var4);
class="kw">return null;
}
if (!this.verifySignatureWithRetry(var3)) {
LOGGER.at(Level.WARNING).log("Identity token signature verification failed");
class="kw">return null;
}
JWTClaimsSet var5 = var3.getJWTClaimsSet();
JWTValidator.IdentityTokenClaims var6 = new JWTValidator.IdentityTokenClaims();
var6.issuer = var5.getIssuer();
var6.subject = var5.getSubject();
var6.issuedAt = var5.getIssueTime() != null ? var5.getIssueTime().toInstant().getEpochSecond() : null;
var6.expiresAt = var5.getExpirationTime() != null ? var5.getExpirationTime().toInstant().getEpochSecond() : null;
var6.notBefore = var5.getNotBeforeTime() != null ? var5.getNotBeforeTime().toInstant().getEpochSecond() : null;
var6.scope = var5.getStringClaim("scope");
Map var7 = var5.getJSONObjectClaim("profile");
if (var7 != null) {
var6.username = (String)var7.get("username");
var6.skin = (String)var7.get("skin");
if (var7.get("entitlements") class="kw">instanceof List var9) {
var6.entitlements = var9.stream().filter(String.class::isInstance).map(String.class::cast).toArray(String[]::new);
}
}
if (!this.expectedIssuer.equals(var6.issuer)) {
LOGGER.at(Level.WARNING)
.log("Invalid identity token issuer: expected %s, got %s. Token: %s", this.expectedIssuer, var6.issuer, var6.toLogSummary());
class="kw">return null;
} else {
long var12 = Instant.now().getEpochSecond();
if (var6.expiresAt == null) {
LOGGER.at(Level.WARNING).log("Identity token missing expiration claim. Token: %s", var6.toLogSummary());
class="kw">return null;
} else if (var12 >= var6.expiresAt + 300L) {
LOGGER.at(Level.WARNING).log("Identity token expired (exp: %d, now: %d). Token: %s", var6.expiresAt, var12, var6.toLogSummary());
class="kw">return null;
} else if (var6.notBefore != null && var12 < var6.notBefore - 300L) {
LOGGER.at(Level.WARNING).log("Identity token not yet valid (nbf: %d, now: %d). Token: %s", var6.notBefore, var12, var6.toLogSummary());
class="kw">return null;
} else if (var6.issuedAt != null && var6.issuedAt > var12 + 300L) {
LOGGER.at(Level.WARNING).log("Identity token issued in the future (iat: %d, now: %d). Token: %s", var6.issuedAt, var12, var6.toLogSummary());
class="kw">return null;
} else if (var6.getSubjectAsUUID() == null) {
LOGGER.at(Level.WARNING).log("Identity token has invalid or missing subject UUID. Token: %s", var6.toLogSummary());
class="kw">return null;
} else {
LOGGER.at(Level.INFO).log("Identity token validated successfully for user %s. Token: %s", var6.username, var6.toLogSummary());
class="kw">return var6;
}
}
} catch (ParseException var10) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var10)).log("Failed to parse identity token");
class="kw">return null;
} catch (Exception var11) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var11)).log("Identity token validation error");
class="kw">return null;
}
}
@Nullable
class="kw">public JWTValidator.SessionTokenClaims validateSessionToken(@Nonnull String var1) {
String var2 = validateJwtStructure(var1, "Session token");
if (var2 != null) {
LOGGER.at(Level.WARNING).log("%s", var2);
class="kw">return null;
}
try {
SignedJWT var3 = SignedJWT.parse(var1);
JWSAlgorithm var4 = var3.getHeader().getAlgorithm();
if (!SUPPORTED_ALGORITHM.equals(var4)) {
LOGGER.at(Level.WARNING).log("Unsupported session token algorithm: %s (expected EdDSA)", var4);
class="kw">return null;
} else if (!this.verifySignatureWithRetry(var3)) {
LOGGER.at(Level.WARNING).log("Session token signature verification failed");
class="kw">return null;
} else {
JWTClaimsSet var5 = var3.getJWTClaimsSet();
JWTValidator.SessionTokenClaims var6 = new JWTValidator.SessionTokenClaims();
var6.issuer = var5.getIssuer();
var6.subject = var5.getSubject();
var6.issuedAt = var5.getIssueTime() != null ? var5.getIssueTime().toInstant().getEpochSecond() : null;
var6.expiresAt = var5.getExpirationTime() != null ? var5.getExpirationTime().toInstant().getEpochSecond() : null;
var6.notBefore = var5.getNotBeforeTime() != null ? var5.getNotBeforeTime().toInstant().getEpochSecond() : null;
var6.scope = var5.getStringClaim("scope");
if (!this.expectedIssuer.equals(var6.issuer)) {
LOGGER.at(Level.WARNING)
.log("Invalid session token issuer: expected %s, got %s. Token: %s", this.expectedIssuer, var6.issuer, var6.toLogSummary());
class="kw">return null;
} else {
long var7 = Instant.now().getEpochSecond();
if (var6.expiresAt == null) {
LOGGER.at(Level.WARNING).log("Session token missing expiration claim. Token: %s", var6.toLogSummary());
class="kw">return null;
} else if (var7 >= var6.expiresAt + 300L) {
LOGGER.at(Level.WARNING).log("Session token expired (exp: %d, now: %d). Token: %s", var6.expiresAt, var7, var6.toLogSummary());
class="kw">return null;
} else if (var6.notBefore != null && var7 < var6.notBefore - 300L) {
LOGGER.at(Level.WARNING).log("Session token not yet valid (nbf: %d, now: %d). Token: %s", var6.notBefore, var7, var6.toLogSummary());
class="kw">return null;
} else if (var6.issuedAt != null && var6.issuedAt > var7 + 300L) {
LOGGER.at(Level.WARNING).log("Session token issued in the future (iat: %d, now: %d). Token: %s", var6.issuedAt, var7, var6.toLogSummary());
class="kw">return null;
} else if (var6.getSubjectAsUUID() == null) {
LOGGER.at(Level.WARNING).log("Session token has invalid or missing subject UUID. Token: %s", var6.toLogSummary());
class="kw">return null;
} else {
LOGGER.at(Level.INFO).log("Session token validated successfully. Token: %s", var6.toLogSummary());
class="kw">return var6;
}
}
}
} catch (ParseException var9) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var9)).log("Failed to parse session token");
class="kw">return null;
} catch (Exception var10) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var10)).log("Session token validation error");
class="kw">return null;
}
}
class="kw">public class="kw">static class IdentityTokenClaims {
class="kw">public String issuer;
class="kw">public String subject;
class="kw">public String username;
class="kw">public String[] entitlements;
class="kw">public String skin;
class="kw">public Long issuedAt;
class="kw">public Long expiresAt;
class="kw">public Long notBefore;
class="kw">public String scope;
class="kw">public IdentityTokenClaims() {
}
@Nullable
class="kw">public UUID getSubjectAsUUID() {
if (this.subject == null) {
class="kw">return null;
}
try {
class="kw">return UUID.fromString(this.subject);
} catch (IllegalArgumentException var2) {
class="kw">return null;
}
}
@Nonnull
class="kw">public String[] getScopes() {
class="kw">return this.scope != null && !this.scope.isEmpty() ? this.scope.split(" ", 0) : new String[0];
}
class="kw">public boolean hasScope(@Nonnull String var1) {
for (String var5 : this.getScopes()) {
if (var5.equals(var1)) {
class="kw">return true;
}
}
class="kw">return false;
}
@Nonnull
class="kw">public String toLogSummary() {
class="kw">return JWTValidator.TokenClaimsLogFormatter.format(this.issuer, null, this.subject, this.scope, this.issuedAt, this.expiresAt, this.notBefore, null);
}
}
class="kw">public class="kw">static class JWTClaims {
class="kw">public String issuer;
class="kw">public String audience;
class="kw">public String subject;
class="kw">public String username;
class="kw">public Long issuedAt;
class="kw">public Long expiresAt;
class="kw">public Long notBefore;
class="kw">public String certificateFingerprint;
class="kw">public JWTClaims() {
}
@Nullable
class="kw">public UUID getSubjectAsUUID() {
if (this.subject == null) {
class="kw">return null;
}
try {
class="kw">return UUID.fromString(this.subject);
} catch (IllegalArgumentException var2) {
class="kw">return null;
}
}
@Nonnull
class="kw">public String toLogSummary() {
class="kw">return JWTValidator.TokenClaimsLogFormatter.format(
this.issuer, this.audience, this.subject, null, this.issuedAt, this.expiresAt, this.notBefore, this.certificateFingerprint
);
}
}
class="kw">public class="kw">static class SessionTokenClaims {
class="kw">public String issuer;
class="kw">public String subject;
class="kw">public Long issuedAt;
class="kw">public Long expiresAt;
class="kw">public Long notBefore;
class="kw">public String scope;
class="kw">public SessionTokenClaims() {
}
@Nullable
class="kw">public UUID getSubjectAsUUID() {
if (this.subject == null) {
class="kw">return null;
}
try {
class="kw">return UUID.fromString(this.subject);
} catch (IllegalArgumentException var2) {
class="kw">return null;
}
}
@Nonnull
class="kw">public String[] getScopes() {
class="kw">return this.scope != null && !this.scope.isEmpty() ? this.scope.split(" ", 0) : new String[0];
}
class="kw">public boolean hasScope(@Nonnull String var1) {
for (String var5 : this.getScopes()) {
if (var5.equals(var1)) {
class="kw">return true;
}
}
class="kw">return false;
}
@Nonnull
class="kw">public String toLogSummary() {
class="kw">return JWTValidator.TokenClaimsLogFormatter.format(this.issuer, null, this.subject, this.scope, this.issuedAt, this.expiresAt, this.notBefore, null);
}
}
class="kw">static class="kw">final class TokenClaimsLogFormatter {
class="kw">private TokenClaimsLogFormatter() {
}
@Nonnull
class="kw">static String format(
@Nullable String var0,
@Nullable String var1,
@Nullable String var2,
@Nullable String var3,
@Nullable Long var4,
@Nullable Long var5,
@Nullable Long var6,
@Nullable String var7
) {
long var8 = Instant.now().getEpochSecond();
StringBuilder var10 = new StringBuilder();
var10.append("iss=").append(var0 == null ? "null" : var0);
if (var1 != null) {
var10.append(", aud=").append(var1);
}
var10.append(", sub=").append(var2 == null ? "null" : var2);
if (var3 != null) {
var10.append(", scope=").append(var3);
}
var10.append(", iat=").append(formatInstant(var4));
var10.append(", exp=").append(formatInstantWithDelta(var5, var8));
if (var6 != null) {
var10.append(", nbf=").append(formatInstant(var6));
}
if (var4 != null && var5 != null) {
var10.append(", lifetime=").append(var5 - var4).append("s");
}
if (var7 != null) {
String var11 = var7.length() > 12 ? var7.substring(0, 12) + "..." : var7;
var10.append(", cnf=").append(var11);
}
class="kw">return var10.toString();
}
@Nonnull
class="kw">private class="kw">static String formatInstant(@Nullable Long var0) {
class="kw">return var0 == null ? "null" : Instant.ofEpochSecond(var0).toString();
}
@Nonnull
class="kw">private class="kw">static String formatInstantWithDelta(@Nullable Long var0, long var1) {
if (var0 == null) {
class="kw">return "null";
}
long var3 = var0 - var1;
String var5 = var3 >= 0L ? "+" : "";
class="kw">return Instant.ofEpochSecond(var0) + " (" + var5 + var3 + "s)";
}
}
}