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

com.nimbusds.jwt.proc.DefaultJWTProcessor Maven / Gradle / Ivy

Go to download

Java library for Javascript Object Signing and Encryption (JOSE) and JSON Web Tokens (JWT)

There is a newer version: 9.47
Show newest version
/*
 * nimbus-jose-jwt
 *
 * Copyright 2012-2019, Connect2id Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
 * this file except in compliance with the License. You may obtain a copy of the
 * License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.nimbusds.jwt.proc;


import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.factories.DefaultJWEDecrypterFactory;
import com.nimbusds.jose.crypto.factories.DefaultJWSVerifierFactory;
import com.nimbusds.jose.proc.*;
import com.nimbusds.jwt.*;

import java.security.Key;
import java.text.ParseException;
import java.util.List;
import java.util.ListIterator;


/**
 * Default processor of {@link com.nimbusds.jwt.PlainJWT unsecured} (plain),
 * {@link com.nimbusds.jwt.SignedJWT signed} and
 * {@link com.nimbusds.jwt.EncryptedJWT encrypted} JSON Web Tokens (JWTs).
 *
 * 

Must be configured with the following: * *

    *
  • To process signed JWTs: A {@link #setJWSKeySelector JWS key * selector} using the header or the {@link JWTClaimsSetAwareJWSKeySelector * header and claims set} to suggest key candidate(s) for the signature * verification. The key selection procedure is application-specific and * may involve key ID lookup, a certificate check and / or some * {@link SecurityContext context}.
  • * *
  • To process encrypted JWTs: A {@link #setJWEKeySelector JWE key * selector} using the header to suggest key candidate(s) for decryption. * The key selection procedure is application-specific and may involve key * ID lookup, a certificate check and / or some {@link SecurityContext * context}.
  • *
* *

An optional {@link SecurityContext context} parameter is available to * facilitate passing of additional data between the caller and the underlying * selector of key candidates (in both directions). * *

See sections 6 of RFC 7515 (JWS) and RFC 7516 (JWE) for guidelines on key * selection. * *

This processor is configured with a standard header "typ" (type) * parameter {@link DefaultJOSEObjectTypeVerifier#JWT verifier} which expects * the signed, encrypted and plain (unsecured) JWTs to have the type header * omitted or set to {@link JOSEObjectType#JWT JWT}. To accept other "typ" * values pass an appropriately configured JWS and / or JWE * {@link DefaultJOSEObjectTypeVerifier type verifier}. * *

This processor comes with the default {@link DefaultJWSVerifierFactory * JWS verifier factory} and the default {@link DefaultJWEDecrypterFactory * JWE decrypter factory}; they can construct verifiers / decrypters for all * standard JOSE algorithms implemented by the library. * *

Note that for security reasons this processor is hardwired to reject * unsecured (plain) JWTs. Override the {@link #process(PlainJWT, SecurityContext)} * if you need to handle plain JWTs. * *

A {@link DefaultJWTClaimsVerifier default JWT claims verifier} is * provided, to perform a minimal check of the claims after a successful JWS * verification / JWE decryption. It checks the token expiration (exp) and * not-before (nbf) timestamps if these are present. The default JWT claims * verifier may be extended to perform additional checks, such as issuer and * subject acceptance. * *

To process generic JOSE objects (with arbitrary payloads) use the * {@link com.nimbusds.jose.proc.DefaultJOSEProcessor} class. * * @author Vladimir Dzhuvinov * @author Misagh Moayyed * @version 2024-01-15 */ public class DefaultJWTProcessor implements ConfigurableJWTProcessor { /** * The JWS type verifier. */ private JOSEObjectTypeVerifier jwsTypeVerifier = DefaultJOSEObjectTypeVerifier.JWT; /** * The JWE type verifier. */ private JOSEObjectTypeVerifier jweTypeVerifier = DefaultJOSEObjectTypeVerifier.JWT; /** * The JWS key selector. */ private JWSKeySelector jwsKeySelector; /** * The JWT claims aware JWS key selector, alternative to * {@link #jwsKeySelector}. */ private JWTClaimsSetAwareJWSKeySelector claimsSetAwareJWSKeySelector; /** * The JWE key selector. */ private JWEKeySelector jweKeySelector; /** * The JWS verifier factory. */ private JWSVerifierFactory jwsVerifierFactory = new DefaultJWSVerifierFactory(); /** * The JWE decrypter factory. */ private JWEDecrypterFactory jweDecrypterFactory = new DefaultJWEDecrypterFactory(); /** * The claims verifier. */ private JWTClaimsSetVerifier claimsVerifier = new DefaultJWTClaimsVerifier<>(null, null); @Override public JOSEObjectTypeVerifier getJWSTypeVerifier() { return jwsTypeVerifier; } @Override public void setJWSTypeVerifier(final JOSEObjectTypeVerifier jwsTypeVerifier) { this.jwsTypeVerifier = jwsTypeVerifier; } @Override public JWSKeySelector getJWSKeySelector() { return jwsKeySelector; } @Override public void setJWSKeySelector(final JWSKeySelector jwsKeySelector) { this.jwsKeySelector = jwsKeySelector; } @Override public JWTClaimsSetAwareJWSKeySelector getJWTClaimsSetAwareJWSKeySelector() { return claimsSetAwareJWSKeySelector; } @Override public void setJWTClaimsSetAwareJWSKeySelector(final JWTClaimsSetAwareJWSKeySelector jwsKeySelector) { this.claimsSetAwareJWSKeySelector = jwsKeySelector; } @Override public JOSEObjectTypeVerifier getJWETypeVerifier() { return jweTypeVerifier; } @Override public void setJWETypeVerifier(final JOSEObjectTypeVerifier jweTypeVerifier) { this.jweTypeVerifier = jweTypeVerifier; } @Override public JWEKeySelector getJWEKeySelector() { return jweKeySelector; } @Override public void setJWEKeySelector(final JWEKeySelector jweKeySelector) { this.jweKeySelector = jweKeySelector; } @Override public JWSVerifierFactory getJWSVerifierFactory() { return jwsVerifierFactory; } @Override public void setJWSVerifierFactory(final JWSVerifierFactory factory) { jwsVerifierFactory = factory; } @Override public JWEDecrypterFactory getJWEDecrypterFactory() { return jweDecrypterFactory; } @Override public void setJWEDecrypterFactory(final JWEDecrypterFactory factory) { jweDecrypterFactory = factory; } @Override public JWTClaimsSetVerifier getJWTClaimsSetVerifier() { return claimsVerifier; } @Override public void setJWTClaimsSetVerifier(final JWTClaimsSetVerifier claimsVerifier) { this.claimsVerifier = claimsVerifier; } /** * Extracts the claims set from the specified JWT. * * @param jwt The JWT. Must not be {@code null}. * * @return The JWT claims set. * * @throws BadJWTException If the payload of the JWT doesn't represent * a valid JSON object and a JWT claims set. */ protected JWTClaimsSet extractJWTClaimsSet(final JWT jwt) throws BadJWTException { try { return jwt.getJWTClaimsSet(); } catch (ParseException e) { // Payload not a JSON object throw new BadJWTException(e.getMessage(), e); } } /** * Verifies the specified JWT claims set. * * @param claimsSet The JWT claims set. Must not be {@code null}. * @param context Optional context, {@code null} if not required. * * @return The verified JWT claims set. * * @throws BadJWTException If the JWT claims set is rejected. */ protected JWTClaimsSet verifyJWTClaimsSet(final JWTClaimsSet claimsSet, final C context) throws BadJWTException { if (getJWTClaimsSetVerifier() != null) { getJWTClaimsSetVerifier().verify(claimsSet, context); } return claimsSet; } /** * Selects key candidates for verifying a signed JWT. * * @param header The JWS header. Must not be {@code null}. * @param claimsSet The JWT claims set (not verified). Must not be * {@code null}. * @param context Optional context, {@code null} if not required. * * @return The key candidates in trial order, empty list if none. * * @throws KeySourceException If a key sourcing exception is * encountered, e.g. on remote JWK * retrieval. * @throws BadJOSEException If an internal processing exception is * encountered. */ protected List selectKeys(final JWSHeader header, final JWTClaimsSet claimsSet, final C context) throws KeySourceException, BadJOSEException { if (getJWTClaimsSetAwareJWSKeySelector() != null) { return getJWTClaimsSetAwareJWSKeySelector().selectKeys(header, claimsSet, context); } else if (getJWSKeySelector() != null) { return getJWSKeySelector().selectJWSKeys(header, context); } else { throw new BadJOSEException("Signed JWT rejected: No JWS key selector is configured"); } } @Override public JWTClaimsSet process(final String jwtString, final C context) throws ParseException, BadJOSEException, JOSEException { return process(JWTParser.parse(jwtString), context); } @Override public JWTClaimsSet process(final JWT jwt, final C context) throws BadJOSEException, JOSEException { if (jwt instanceof SignedJWT) { return process((SignedJWT)jwt, context); } if (jwt instanceof EncryptedJWT) { return process((EncryptedJWT)jwt, context); } if (jwt instanceof PlainJWT) { return process((PlainJWT)jwt, context); } // Should never happen throw new JOSEException("Unexpected JWT object type: " + jwt.getClass()); } @Override public JWTClaimsSet process(final PlainJWT plainJWT, final C context) throws BadJOSEException, JOSEException { // JWS type verifier applies to unsecured JOSE as well if (jwsTypeVerifier == null) { throw new BadJOSEException("Plain JWT rejected: No JWS header typ (type) verifier is configured"); } jwsTypeVerifier.verify(plainJWT.getHeader().getType(), context); throw new BadJOSEException("Unsecured (plain) JWTs are rejected, extend class to handle"); } @Override public JWTClaimsSet process(final SignedJWT signedJWT, final C context) throws BadJOSEException, JOSEException { if (jwsTypeVerifier == null) { throw new BadJOSEException("Signed JWT rejected: No JWS header typ (type) verifier is configured"); } jwsTypeVerifier.verify(signedJWT.getHeader().getType(), context); if (getJWSKeySelector() == null && getJWTClaimsSetAwareJWSKeySelector() == null) { // JWS key selector may have been deliberately omitted throw new BadJOSEException("Signed JWT rejected: No JWS key selector is configured"); } if (getJWSVerifierFactory() == null) { throw new JOSEException("No JWS verifier is configured"); } JWTClaimsSet claimsSet = extractJWTClaimsSet(signedJWT); List keyCandidates = selectKeys(signedJWT.getHeader(), claimsSet, context); if (keyCandidates == null || keyCandidates.isEmpty()) { throw new BadJOSEException("Signed JWT rejected: Another algorithm expected, or no matching key(s) found"); } ListIterator it = keyCandidates.listIterator(); while (it.hasNext()) { JWSVerifier verifier = getJWSVerifierFactory().createJWSVerifier(signedJWT.getHeader(), it.next()); if (verifier == null) { continue; } final boolean validSignature = signedJWT.verify(verifier); if (validSignature) { return verifyJWTClaimsSet(claimsSet, context); } if (! it.hasNext()) { // No more keys to try out throw new BadJWSException("Signed JWT rejected: Invalid signature"); } } throw new BadJOSEException("JWS object rejected: No matching verifier(s) found"); } @Override public JWTClaimsSet process(final EncryptedJWT encryptedJWT, final C context) throws BadJOSEException, JOSEException { if (jweTypeVerifier == null) { throw new BadJOSEException("Encrypted JWT rejected: No JWE header typ (type) verifier is configured"); } jweTypeVerifier.verify(encryptedJWT.getHeader().getType(), context); if (getJWEKeySelector() == null) { // JWE key selector may have been deliberately omitted throw new BadJOSEException("Encrypted JWT rejected: No JWE key selector is configured"); } if (getJWEDecrypterFactory() == null) { throw new JOSEException("No JWE decrypter is configured"); } List keyCandidates = getJWEKeySelector().selectJWEKeys(encryptedJWT.getHeader(), context); if (keyCandidates == null || keyCandidates.isEmpty()) { throw new BadJOSEException("Encrypted JWT rejected: Another algorithm expected, or no matching key(s) found"); } ListIterator it = keyCandidates.listIterator(); while (it.hasNext()) { JWEDecrypter decrypter = getJWEDecrypterFactory().createJWEDecrypter(encryptedJWT.getHeader(), it.next()); if (decrypter == null) { continue; } try { encryptedJWT.decrypt(decrypter); } catch (JOSEException e) { if (it.hasNext()) { // Try next key continue; } // No more keys to try throw new BadJWEException("Encrypted JWT rejected: " + e.getMessage(), e); } if ("JWT".equalsIgnoreCase(encryptedJWT.getHeader().getContentType())) { // Handle nested signed JWT, see http://tools.ietf.org/html/rfc7519#section-5.2 SignedJWT signedJWTPayload = encryptedJWT.getPayload().toSignedJWT(); if (signedJWTPayload == null) { // Cannot parse payload to signed JWT throw new BadJWTException("The payload is not a nested signed JWT"); } return process(signedJWTPayload, context); } JWTClaimsSet claimsSet = extractJWTClaimsSet(encryptedJWT); return verifyJWTClaimsSet(claimsSet, context); } throw new BadJOSEException("Encrypted JWT rejected: No matching decrypter(s) found"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy