org.smallmind.web.jwt.jose4j.JWTConsumer Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2007 through 2024 David Berkman
*
* This file is part of the SmallMind Code Project.
*
* The SmallMind Code Project is free software, you can redistribute
* it and/or modify it under either, at your discretion...
*
* 1) The terms of GNU Affero General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* ...or...
*
* 2) The terms of the Apache License, Version 2.0.
*
* The SmallMind Code Project is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License or Apache License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and the Apache License along with the SmallMind Code Project. If not, see
* or .
*
* Additional permission under the GNU Affero GPL version 3 section 7
* ------------------------------------------------------------------
* If you modify this Program, or any covered work, by linking or
* combining it with other code, such other code is not for that reason
* alone subject to any of the requirements of the GNU Affero GPL
* version 3.
*/
package org.smallmind.web.jwt.jose4j;
import java.security.Key;
import java.util.ArrayList;
import java.util.LinkedList;
import org.jose4j.jwe.JsonWebEncryption;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwx.JsonWebStructure;
import org.jose4j.keys.KeyPersuasion;
import org.smallmind.web.json.scaffold.util.JsonCodec;
import static org.jose4j.jws.AlgorithmIdentifiers.NONE;
public class JWTConsumer {
private boolean skipSignatureVerification;
private boolean skipVerificationKeyResolutionOnNone;
private boolean requireSignature = true;
private boolean requireEncryption;
private boolean requireIntegrity;
public JWTConsumer setSkipSignatureVerification (boolean skipSignatureVerification) {
this.skipSignatureVerification = skipSignatureVerification;
return this;
}
public JWTConsumer setSkipVerificationKeyResolutionOnNone (boolean skipVerificationKeyResolutionOnNone) {
this.skipVerificationKeyResolutionOnNone = skipVerificationKeyResolutionOnNone;
return this;
}
public JWTConsumer setRequireSignature (boolean requireSignature) {
this.requireSignature = requireSignature;
return this;
}
public JWTConsumer setRequireEncryption (boolean requireEncryption) {
this.requireEncryption = requireEncryption;
return this;
}
public JWTConsumer setRequireIntegrity (boolean requireIntegrity) {
this.requireIntegrity = requireIntegrity;
return this;
}
public T process (String jwt, Key decryptionKey, Class claimsClass)
throws Exception {
T jwtClaims = null;
LinkedList joseObjects = new LinkedList<>();
String workingJwt = jwt;
while (jwtClaims == null) {
JsonWebStructure joseObject;
joseObject = JsonWebStructure.fromCompactSerialization(workingJwt);
String payload;
if (joseObject instanceof JsonWebSignature) {
JsonWebSignature jws = (JsonWebSignature)joseObject;
payload = jws.getUnverifiedPayload();
} else {
JsonWebEncryption jwe = (JsonWebEncryption)joseObject;
jwe.setKey(decryptionKey);
payload = jwe.getPayload();
}
if (this.isNestedJwt(joseObject)) {
workingJwt = payload;
} else {
jwtClaims = JsonCodec.read(payload, claimsClass);
}
joseObjects.addFirst(joseObject);
}
processContext(jwt, decryptionKey, joseObjects);
return jwtClaims;
}
public void processContext (String jwt, Key verificationKey, LinkedList joseObjects)
throws Exception {
boolean hasSignature = false;
boolean hasEncryption = false;
boolean hasSymmetricEncryption = false;
ArrayList originalJoseObjects = new ArrayList<>(joseObjects);
for (int idx = originalJoseObjects.size() - 1; idx >= 0; idx--) {
JsonWebStructure currentJoseObject = originalJoseObjects.get(idx);
if (currentJoseObject instanceof JsonWebSignature) {
JsonWebSignature jws = (JsonWebSignature)currentJoseObject;
boolean isNoneAlg = NONE.equals(jws.getAlgorithmHeaderValue());
if (!skipSignatureVerification) {
if (!isNoneAlg || !skipVerificationKeyResolutionOnNone) {
jws.setKey(verificationKey);
}
if (!jws.verifySignature()) {
throw new InvalidJWTSignatureException(jws.getAlgorithmHeaderValue());
}
}
if (!isNoneAlg) {
hasSignature = true;
}
} else {
JsonWebEncryption jwe = (JsonWebEncryption)currentJoseObject;
hasEncryption = true;
hasSymmetricEncryption = jwe.getKeyManagementModeAlgorithm().getKeyPersuasion() == KeyPersuasion.SYMMETRIC;
}
}
if (this.requireSignature && !hasSignature) {
throw new InvalidJWTException("The JWT has no signature but the JWT Consumer is configured to require one: " + jwt);
} else if (this.requireEncryption && !hasEncryption) {
throw new InvalidJWTException("The JWT has no encryption but the JWT Consumer is configured to require it: " + jwt);
} else if (this.requireIntegrity && !hasSignature && !hasSymmetricEncryption) {
throw new InvalidJWTException("The JWT has no integrity protection (signature/MAC or symmetric AEAD encryption) but the JWT Consumer is configured to require it: " + jwt);
}
}
private boolean isNestedJwt (JsonWebStructure joseObject) {
String cty = joseObject.getContentTypeHeaderValue();
return cty != null && (cty.equalsIgnoreCase("jwt") || cty.equalsIgnoreCase("application/jwt"));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy