001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2019, Connect2id Ltd. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jwt.proc; 019 020 021import java.security.Key; 022import java.text.ParseException; 023import java.util.List; 024import java.util.ListIterator; 025 026import com.nimbusds.jose.*; 027import com.nimbusds.jose.crypto.factories.DefaultJWEDecrypterFactory; 028import com.nimbusds.jose.crypto.factories.DefaultJWSVerifierFactory; 029import com.nimbusds.jose.proc.*; 030import com.nimbusds.jwt.*; 031 032 033/** 034 * Default processor of {@link com.nimbusds.jwt.PlainJWT unsecured} (plain), 035 * {@link com.nimbusds.jwt.SignedJWT signed} and 036 * {@link com.nimbusds.jwt.EncryptedJWT encrypted} JSON Web Tokens (JWTs). 037 * 038 * <p>Must be configured with the following: 039 * 040 * <ol> 041 * <li>To process signed JWTs: A JWS key selector using the 042 * {@link JWSKeySelector header} or the 043 * {@link JWTClaimsSetAwareJWSKeySelector header and claims set} to 044 * determine the key candidate(s) for the signature verification. The key 045 * selection procedure is application-specific and may involve key ID 046 * lookup, a certificate check and / or some 047 * {@link SecurityContext context}.</li> 048 * 049 * <li>To process encrypted JWTs: A JWE key selector using the 050 * {@link JWEKeySelector header} to determine the key candidate(s) for 051 * decryption. The key selection procedure is application-specific and may 052 * involve key ID lookup, a certificate check and / or some 053 * {@link SecurityContext context}.</li> 054 * </ol> 055 * 056 * <p>An optional context parameter is available to facilitate passing of 057 * additional data between the caller and the underlying selector of key 058 * candidates (in both directions). 059 * 060 * <p>See sections 6 of RFC 7515 (JWS) and RFC 7516 (JWE) for guidelines on key 061 * selection. 062 * 063 * <p>This processor comes with the default {@link DefaultJWSVerifierFactory 064 * JWS verifier factory} and the default {@link DefaultJWEDecrypterFactory 065 * JWE decrypter factory}; they can construct verifiers / decrypters for all 066 * standard JOSE algorithms implemented by the library. 067 * 068 * <p>Note that for security reasons this processor is hardwired to reject 069 * unsecured (plain) JWTs. Override the {@link #process(PlainJWT, SecurityContext)} 070 * if you need to handle plain JWTs as well. 071 * 072 * <p>A {@link DefaultJWTClaimsVerifier default JWT claims verifier} is 073 * provided, to perform a minimal check of the claims after a successful JWS 074 * verification / JWE decryption. It checks the token expiration (exp) and 075 * not-before (nbf) timestamps if these are present. The default JWT claims 076 * verifier may be extended to perform additional checks, such as issuer and 077 * subject acceptance. 078 * 079 * <p>To process generic JOSE objects (with arbitrary payloads) use the 080 * {@link com.nimbusds.jose.proc.DefaultJOSEProcessor} class. 081 * 082 * @author Vladimir Dzhuvinov 083 * @version 2019-07-18 084 */ 085public class DefaultJWTProcessor<C extends SecurityContext> 086 implements ConfigurableJWTProcessor<C> { 087 088 // Cache exceptions 089 private static final BadJOSEException PLAIN_JWT_REJECTED_EXCEPTION = 090 new BadJOSEException("Unsecured (plain) JWTs are rejected, extend class to handle"); 091 private static final BadJOSEException NO_JWS_KEY_SELECTOR_EXCEPTION = 092 new BadJOSEException("Signed JWT rejected: No JWS key selector is configured"); 093 private static final BadJOSEException NO_JWE_KEY_SELECTOR_EXCEPTION = 094 new BadJOSEException("Encrypted JWT rejected: No JWE key selector is configured"); 095 private static final JOSEException NO_JWS_VERIFIER_FACTORY_EXCEPTION = 096 new JOSEException("No JWS verifier is configured"); 097 private static final JOSEException NO_JWE_DECRYPTER_FACTORY_EXCEPTION = 098 new JOSEException("No JWE decrypter is configured"); 099 private static final BadJOSEException NO_JWS_KEY_CANDIDATES_EXCEPTION = 100 new BadJOSEException("Signed JWT rejected: Another algorithm expected, or no matching key(s) found"); 101 private static final BadJOSEException NO_JWE_KEY_CANDIDATES_EXCEPTION = 102 new BadJOSEException("Encrypted JWT rejected: Another algorithm expected, or no matching key(s) found"); 103 private static final BadJOSEException INVALID_SIGNATURE = 104 new BadJWSException("Signed JWT rejected: Invalid signature"); 105 private static final BadJWTException INVALID_NESTED_JWT_EXCEPTION = 106 new BadJWTException("The payload is not a nested signed JWT"); 107 private static final BadJOSEException NO_MATCHING_VERIFIERS_EXCEPTION = 108 new BadJOSEException("JWS object rejected: No matching verifier(s) found"); 109 private static final BadJOSEException NO_MATCHING_DECRYPTERS_EXCEPTION = 110 new BadJOSEException("Encrypted JWT rejected: No matching decrypter(s) found"); 111 112 /** 113 * The JWS key selector. 114 */ 115 private JWSKeySelector<C> jwsKeySelector; 116 117 118 /** 119 * The JWT claims aware JWS key selector, alternative to 120 * {@link #jwsKeySelector}. 121 */ 122 private JWTClaimsSetAwareJWSKeySelector<C> claimsSetAwareJWSKeySelector; 123 124 125 /** 126 * The JWE key selector. 127 */ 128 private JWEKeySelector<C> jweKeySelector; 129 130 131 /** 132 * The JWS verifier factory. 133 */ 134 private JWSVerifierFactory jwsVerifierFactory = new DefaultJWSVerifierFactory(); 135 136 137 /** 138 * The JWE decrypter factory. 139 */ 140 private JWEDecrypterFactory jweDecrypterFactory = new DefaultJWEDecrypterFactory(); 141 142 143 /** 144 * The claims verifier. 145 */ 146 private JWTClaimsSetVerifier<C> claimsVerifier = new DefaultJWTClaimsVerifier<>(); 147 148 149 /** 150 * The deprecated claims verifier. 151 */ 152 private JWTClaimsVerifier deprecatedClaimsVerifier = null; 153 154 155 @Override 156 public JWSKeySelector<C> getJWSKeySelector() { 157 158 return jwsKeySelector; 159 } 160 161 162 @Override 163 public void setJWSKeySelector(final JWSKeySelector<C> jwsKeySelector) { 164 165 this.jwsKeySelector = jwsKeySelector; 166 } 167 168 169 @Override 170 public JWTClaimsSetAwareJWSKeySelector<C> getJWTClaimsSetAwareJWSKeySelector() { 171 172 return claimsSetAwareJWSKeySelector; 173 } 174 175 176 @Override 177 public void setJWTClaimsSetAwareJWSKeySelector(final JWTClaimsSetAwareJWSKeySelector<C> jwsKeySelector) { 178 179 this.claimsSetAwareJWSKeySelector = jwsKeySelector; 180 } 181 182 183 @Override 184 public JWEKeySelector<C> getJWEKeySelector() { 185 186 return jweKeySelector; 187 } 188 189 190 @Override 191 public void setJWEKeySelector(final JWEKeySelector<C> jweKeySelector) { 192 193 this.jweKeySelector = jweKeySelector; 194 } 195 196 197 @Override 198 public JWSVerifierFactory getJWSVerifierFactory() { 199 200 return jwsVerifierFactory; 201 } 202 203 204 @Override 205 public void setJWSVerifierFactory(final JWSVerifierFactory factory) { 206 207 jwsVerifierFactory = factory; 208 } 209 210 211 @Override 212 public JWEDecrypterFactory getJWEDecrypterFactory() { 213 214 return jweDecrypterFactory; 215 } 216 217 218 @Override 219 public void setJWEDecrypterFactory(final JWEDecrypterFactory factory) { 220 221 jweDecrypterFactory = factory; 222 } 223 224 225 @Override 226 public JWTClaimsSetVerifier<C> getJWTClaimsSetVerifier() { 227 228 return claimsVerifier; 229 } 230 231 232 @Override 233 public void setJWTClaimsSetVerifier(final JWTClaimsSetVerifier<C> claimsVerifier) { 234 235 this.claimsVerifier = claimsVerifier; 236 this.deprecatedClaimsVerifier = null; // clear other verifier 237 } 238 239 240 @Override 241 @Deprecated 242 public JWTClaimsVerifier getJWTClaimsVerifier() { 243 244 return deprecatedClaimsVerifier; 245 } 246 247 248 @Override 249 @Deprecated 250 public void setJWTClaimsVerifier(final JWTClaimsVerifier claimsVerifier) { 251 252 this.claimsVerifier = null; // clear official verifier 253 this.deprecatedClaimsVerifier = claimsVerifier; 254 } 255 256 257 private JWTClaimsSet extractJWTClaimsSet(final JWT jwt) 258 throws BadJWTException { 259 260 try { 261 return jwt.getJWTClaimsSet(); 262 } catch (ParseException e) { 263 // Payload not a JSON object 264 throw new BadJWTException(e.getMessage(), e); 265 } 266 } 267 268 269 private JWTClaimsSet verifyClaims(final JWTClaimsSet claimsSet, final C context) 270 throws BadJWTException { 271 272 if (getJWTClaimsSetVerifier() != null) { 273 getJWTClaimsSetVerifier().verify(claimsSet, context); 274 } else if (getJWTClaimsVerifier() != null) { 275 // Fall back to deprecated claims verifier 276 getJWTClaimsVerifier().verify(claimsSet); 277 } 278 return claimsSet; 279 } 280 281 282 private List<? extends Key> selectKeys(final JWSHeader header, final JWTClaimsSet claimsSet, final C context) 283 throws KeySourceException, BadJOSEException { 284 285 if (getJWTClaimsSetAwareJWSKeySelector() != null) { 286 return getJWTClaimsSetAwareJWSKeySelector().selectKeys(header, claimsSet, context); 287 } else if (getJWSKeySelector() != null) { 288 return getJWSKeySelector().selectJWSKeys(header, context); 289 } else { 290 throw NO_JWS_KEY_SELECTOR_EXCEPTION; 291 } 292 } 293 294 295 @Override 296 public JWTClaimsSet process(final String jwtString, final C context) 297 throws ParseException, BadJOSEException, JOSEException { 298 299 return process(JWTParser.parse(jwtString), context); 300 } 301 302 303 @Override 304 public JWTClaimsSet process(final JWT jwt, final C context) 305 throws BadJOSEException, JOSEException { 306 307 if (jwt instanceof SignedJWT) { 308 return process((SignedJWT)jwt, context); 309 } 310 311 if (jwt instanceof EncryptedJWT) { 312 return process((EncryptedJWT)jwt, context); 313 } 314 315 if (jwt instanceof PlainJWT) { 316 return process((PlainJWT)jwt, context); 317 } 318 319 // Should never happen 320 throw new JOSEException("Unexpected JWT object type: " + jwt.getClass()); 321 } 322 323 324 @Override 325 public JWTClaimsSet process(final PlainJWT plainJWT, final C context) 326 throws BadJOSEException, JOSEException { 327 328 throw PLAIN_JWT_REJECTED_EXCEPTION; 329 } 330 331 332 @Override 333 public JWTClaimsSet process(final SignedJWT signedJWT, final C context) 334 throws BadJOSEException, JOSEException { 335 336 if (getJWSKeySelector() == null && getJWTClaimsSetAwareJWSKeySelector() == null) { 337 // JWS key selector may have been deliberately omitted 338 throw NO_JWS_KEY_SELECTOR_EXCEPTION; 339 } 340 341 if (getJWSVerifierFactory() == null) { 342 throw NO_JWS_VERIFIER_FACTORY_EXCEPTION; 343 } 344 345 JWTClaimsSet claimsSet = extractJWTClaimsSet(signedJWT); 346 347 List<? extends Key> keyCandidates = selectKeys(signedJWT.getHeader(), claimsSet, context); 348 349 if (keyCandidates == null || keyCandidates.isEmpty()) { 350 throw NO_JWS_KEY_CANDIDATES_EXCEPTION; 351 } 352 353 ListIterator<? extends Key> it = keyCandidates.listIterator(); 354 355 while (it.hasNext()) { 356 357 JWSVerifier verifier = getJWSVerifierFactory().createJWSVerifier(signedJWT.getHeader(), it.next()); 358 359 if (verifier == null) { 360 continue; 361 } 362 363 final boolean validSignature = signedJWT.verify(verifier); 364 365 if (validSignature) { 366 return verifyClaims(claimsSet, context); 367 } 368 369 if (! it.hasNext()) { 370 // No more keys to try out 371 throw INVALID_SIGNATURE; 372 } 373 } 374 375 throw NO_MATCHING_VERIFIERS_EXCEPTION; 376 } 377 378 379 @Override 380 public JWTClaimsSet process(final EncryptedJWT encryptedJWT, final C context) 381 throws BadJOSEException, JOSEException { 382 383 if (getJWEKeySelector() == null) { 384 // JWE key selector may have been deliberately omitted 385 throw NO_JWE_KEY_SELECTOR_EXCEPTION; 386 } 387 388 if (getJWEDecrypterFactory() == null) { 389 throw NO_JWE_DECRYPTER_FACTORY_EXCEPTION; 390 } 391 392 List<? extends Key> keyCandidates = getJWEKeySelector().selectJWEKeys(encryptedJWT.getHeader(), context); 393 394 if (keyCandidates == null || keyCandidates.isEmpty()) { 395 throw NO_JWE_KEY_CANDIDATES_EXCEPTION; 396 } 397 398 ListIterator<? extends Key> it = keyCandidates.listIterator(); 399 400 while (it.hasNext()) { 401 402 JWEDecrypter decrypter = getJWEDecrypterFactory().createJWEDecrypter(encryptedJWT.getHeader(), it.next()); 403 404 if (decrypter == null) { 405 continue; 406 } 407 408 try { 409 encryptedJWT.decrypt(decrypter); 410 411 } catch (JOSEException e) { 412 413 if (it.hasNext()) { 414 // Try next key 415 continue; 416 } 417 418 // No more keys to try 419 throw new BadJWEException("Encrypted JWT rejected: " + e.getMessage(), e); 420 } 421 422 if ("JWT".equalsIgnoreCase(encryptedJWT.getHeader().getContentType())) { 423 424 // Handle nested signed JWT, see http://tools.ietf.org/html/rfc7519#section-5.2 425 SignedJWT signedJWTPayload = encryptedJWT.getPayload().toSignedJWT(); 426 427 if (signedJWTPayload == null) { 428 // Cannot parse payload to signed JWT 429 throw INVALID_NESTED_JWT_EXCEPTION; 430 } 431 432 return process(signedJWTPayload, context); 433 } 434 435 JWTClaimsSet claimsSet = extractJWTClaimsSet(encryptedJWT); 436 return verifyClaims(claimsSet, context); 437 } 438 439 throw NO_MATCHING_DECRYPTERS_EXCEPTION; 440 } 441}