mirror of https://github.com/jwtk/jjwt.git
Issue #8 Add ability to resolve signing key based on Jws embedded values before its signature is verified
This commit is contained in:
parent
3e35e4e226
commit
3eb4f01c3f
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* 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 io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* A JwsSigningKeyResolver is invoked by a {@link io.jsonwebtoken.JwtParser JwtParser} if it's provided and the
|
||||
* provided JWT is signed.
|
||||
* <p/>
|
||||
* Implementations of this interfaces must be provided to {@link io.jsonwebtoken.JwtParser JwtParser} when the values
|
||||
* embedded in the JWS need to be used to determine the <code>signing key</code> used to sign the JWS.
|
||||
*
|
||||
* @since 0.4
|
||||
*/
|
||||
public interface JwsSigningKeyResolver {
|
||||
|
||||
/**
|
||||
* This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} parsed a {@link Jws} and needs
|
||||
* to resolve the signing key, based on a value embedded in the {@link JwsHeader} and/or the {@link Claims}
|
||||
* <p/>
|
||||
* <p>This method will only be invoked if an implementation is provided.</p>
|
||||
* <p/>
|
||||
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
|
||||
* (as the {@code alg} header parameter).</p>
|
||||
*
|
||||
* @param header the parsed {@link JwsHeader}
|
||||
* @param claims the parsed {@link Claims}
|
||||
* @return any object to be used after inspecting the JWS, or {@code null} if no return value is necessary.
|
||||
*/
|
||||
byte[] resolveSigningKey(JwsHeader header, Claims claims);
|
||||
}
|
|
@ -77,6 +77,21 @@ public interface JwtParser {
|
|||
*/
|
||||
JwtParser setSigningKey(Key key);
|
||||
|
||||
/**
|
||||
* Sets the {@link JwsSigningKeyResolver} used to resolve the <code>signing key</code> using the parsed {@link JwsHeader}
|
||||
* and/or the {@link Claims}. If the specified JWT string is not a JWS (no signature), this resolver is not used.
|
||||
* <p/>
|
||||
* <p>This method will set the signing key resolver to be used in case a signing key is not provided by any of the other methods.</p>
|
||||
* <p/>
|
||||
* <p>This is a convenience method: the {@code jwsSignatureKeyResolver} is used after a Jws has been parsed and either the
|
||||
* {@link JwsHeader} or the {@link Claims} embedded in the {@link Jws} can be used to resolve the signing key.
|
||||
* </p>
|
||||
*
|
||||
* @param jwsSigningKeyResolver the signing key resolver used to retrieve the signing key.
|
||||
* @return the parser for method chaining.
|
||||
*/
|
||||
JwtParser setJwsSigningKeyResolver(JwsSigningKeyResolver jwsSigningKeyResolver);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false}
|
||||
* otherwise.
|
||||
|
|
|
@ -21,6 +21,7 @@ import io.jsonwebtoken.ExpiredJwtException;
|
|||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Jws;
|
||||
import io.jsonwebtoken.JwsHeader;
|
||||
import io.jsonwebtoken.JwsSigningKeyResolver;
|
||||
import io.jsonwebtoken.Jwt;
|
||||
import io.jsonwebtoken.JwtHandler;
|
||||
import io.jsonwebtoken.JwtHandlerAdapter;
|
||||
|
@ -55,6 +56,8 @@ public class DefaultJwtParser implements JwtParser {
|
|||
|
||||
private Key key;
|
||||
|
||||
private JwsSigningKeyResolver jwsSigningKeyResolver;
|
||||
|
||||
@Override
|
||||
public JwtParser setSigningKey(byte[] key) {
|
||||
Assert.notEmpty(key, "signing key cannot be null or empty.");
|
||||
|
@ -76,6 +79,13 @@ public class DefaultJwtParser implements JwtParser {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtParser setJwsSigningKeyResolver(JwsSigningKeyResolver jwsSigningKeyResolver) {
|
||||
Assert.notNull(jwsSigningKeyResolver, "jwsSigningKeyResolver cannot be null.");
|
||||
this.jwsSigningKeyResolver = jwsSigningKeyResolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSigned(String jwt) {
|
||||
|
||||
|
@ -234,6 +244,9 @@ public class DefaultJwtParser implements JwtParser {
|
|||
|
||||
if (key != null && keyBytes != null) {
|
||||
throw new IllegalStateException("A key object and key bytes cannot both be specified. Choose either.");
|
||||
} else if ((key != null || keyBytes != null) && jwsSigningKeyResolver != null) {
|
||||
String object = key != null ? " a key object " : " key bytes ";
|
||||
throw new IllegalStateException("A signing key resolver object and" + object + "cannot both be specified. Choose either.");
|
||||
}
|
||||
|
||||
//digitally signed, let's assert the signature:
|
||||
|
@ -241,7 +254,13 @@ public class DefaultJwtParser implements JwtParser {
|
|||
|
||||
if (key == null) { //fall back to keyBytes
|
||||
|
||||
if (!Objects.isEmpty(this.keyBytes)) {
|
||||
byte[] keyBytes = this.keyBytes;
|
||||
|
||||
if (Objects.isEmpty(keyBytes) && jwsSigningKeyResolver != null) { //use the jwsSigningKeyResolver
|
||||
keyBytes = jwsSigningKeyResolver.resolveSigningKey(jwsHeader, claims);
|
||||
}
|
||||
|
||||
if (!Objects.isEmpty(keyBytes)) {
|
||||
|
||||
Assert.isTrue(!algorithm.isRsa(),
|
||||
"Key bytes cannot be specified for RSA signatures. Please specify a PublicKey or PrivateKey instance.");
|
||||
|
|
Loading…
Reference in New Issue