com.nimbusds.jose.proc.DefaultJOSEProcessor Maven / Gradle / Ivy
Show all versions of nimbus-jose-jwt Show documentation
/*
* 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.jose.proc;
import java.security.Key;
import java.text.ParseException;
import java.util.List;
import java.util.ListIterator;
import net.jcip.annotations.ThreadSafe;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.factories.DefaultJWEDecrypterFactory;
import com.nimbusds.jose.crypto.factories.DefaultJWSVerifierFactory;
/**
* Default processor of {@link com.nimbusds.jose.PlainObject unsecured}
* (plain), {@link com.nimbusds.jose.JWSObject JWS} and
* {@link com.nimbusds.jose.JWEObject JWE} objects.
*
* Must be configured with the following:
*
*
* - To verify JWS objects: A {@link #setJWSKeySelector JWS key selector}
* using the header 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 decrypt JWE objects: 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#JOSE verifier} which expects
* the JWS, JWE and plain (unsecured) objects to have the type header omitted
* or set to {@link JOSEObjectType#JOSE JOSE}. 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) JOSE objects. Override the {@link #process(PlainObject,
* SecurityContext)} method if you need to handle unsecured JOSE objects.
*
*
To process JSON Web Tokens (JWTs) use the
* {@link com.nimbusds.jwt.proc.DefaultJWTProcessor} class.
*
* @author Vladimir Dzhuvinov
* @version 2019-10-15
*/
@ThreadSafe
public class DefaultJOSEProcessor implements ConfigurableJOSEProcessor{
/**
* The JWS type verifier.
*/
private JOSEObjectTypeVerifier jwsTypeVerifier = DefaultJOSEObjectTypeVerifier.JOSE;
/**
* The JWE type verifier.
*/
private JOSEObjectTypeVerifier jweTypeVerifier = DefaultJOSEObjectTypeVerifier.JOSE;
/**
* The JWS key selector.
*/
private JWSKeySelector jwsKeySelector;
/**
* 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();
@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 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 Payload process(final String compactJOSE, final C context)
throws ParseException, BadJOSEException, JOSEException {
return process(JOSEObject.parse(compactJOSE), context);
}
@Override
public Payload process(final JOSEObject joseObject, final C context)
throws BadJOSEException, JOSEException {
if (joseObject instanceof JWSObject) {
return process((JWSObject)joseObject, context);
}
if (joseObject instanceof JWEObject) {
return process((JWEObject)joseObject, context);
}
if (joseObject instanceof PlainObject) {
return process((PlainObject)joseObject, context);
}
// Should never happen
throw new JOSEException("Unexpected JOSE object type: " + joseObject.getClass());
}
@Override
public Payload process(final PlainObject plainObject, C context)
throws BadJOSEException {
// JWS type verifier applies to unsecured JOSE as well
if (jwsTypeVerifier == null) {
throw new BadJOSEException("Unsecured (plain) JOSE object rejected: No JWS header typ (type) verifier is configured");
}
jwsTypeVerifier.verify(plainObject.getHeader().getType(), context);
throw new BadJOSEException("Unsecured (plain) JOSE objects are rejected, extend class to handle");
}
@Override
public Payload process(final JWSObject jwsObject, C context)
throws BadJOSEException, JOSEException {
if (jwsTypeVerifier == null) {
throw new BadJOSEException("JWS object rejected: No JWS header typ (type) verifier is configured");
}
jwsTypeVerifier.verify(jwsObject.getHeader().getType(), context);
if (getJWSKeySelector() == null) {
// JWS key selector may have been deliberately omitted
throw new BadJOSEException("JWS object rejected: No JWS key selector is configured");
}
if (getJWSVerifierFactory() == null) {
throw new JOSEException("No JWS verifier is configured");
}
List extends Key> keyCandidates = getJWSKeySelector().selectJWSKeys(jwsObject.getHeader(), context);
if (keyCandidates == null || keyCandidates.isEmpty()) {
throw new BadJOSEException("JWS object rejected: Another algorithm expected, or no matching key(s) found");
}
ListIterator extends Key> it = keyCandidates.listIterator();
while (it.hasNext()) {
JWSVerifier verifier = getJWSVerifierFactory().createJWSVerifier(jwsObject.getHeader(), it.next());
if (verifier == null) {
continue;
}
final boolean validSignature = jwsObject.verify(verifier);
if (validSignature) {
return jwsObject.getPayload();
}
if (! it.hasNext()) {
// No more keys to try out
throw new BadJWSException("JWS object rejected: Invalid signature");
}
}
throw new BadJOSEException("JWS object rejected: No matching verifier(s) found");
}
@Override
public Payload process(final JWEObject jweObject, C context)
throws BadJOSEException, JOSEException {
if (jweTypeVerifier == null) {
throw new BadJOSEException("JWE object rejected: No JWE header typ (type) verifier is configured");
}
jweTypeVerifier.verify(jweObject.getHeader().getType(), context);
if (getJWEKeySelector() == null) {
// JWE key selector may have been deliberately omitted
throw new BadJOSEException("JWE object rejected: No JWE key selector is configured");
}
if (getJWEDecrypterFactory() == null) {
throw new JOSEException("No JWE decrypter is configured");
}
List extends Key> keyCandidates = getJWEKeySelector().selectJWEKeys(jweObject.getHeader(), context);
if (keyCandidates == null || keyCandidates.isEmpty()) {
throw new BadJOSEException("JWE object rejected: Another algorithm expected, or no matching key(s) found");
}
ListIterator extends Key> it = keyCandidates.listIterator();
while (it.hasNext()) {
JWEDecrypter decrypter = getJWEDecrypterFactory().createJWEDecrypter(jweObject.getHeader(), it.next());
if (decrypter == null) {
continue;
}
try {
jweObject.decrypt(decrypter);
} catch (JOSEException e) {
if (it.hasNext()) {
// Try next key
continue;
}
// No more keys to try
throw new BadJWEException("JWE object rejected: " + e.getMessage(), e);
}
if ("JWT".equalsIgnoreCase(jweObject.getHeader().getContentType())) {
// Handle nested signed JWT, see http://tools.ietf.org/html/rfc7519#section-5.2
JWSObject nestedJWS = jweObject.getPayload().toJWSObject();
if (nestedJWS == null) {
// Cannot parse payload to JWS object, return original form
return jweObject.getPayload();
}
return process(nestedJWS, context);
}
return jweObject.getPayload();
}
throw new BadJOSEException("JWE object rejected: No matching decrypter(s) found");
}
}