1616import java .security .PublicKey ;
1717import java .security .interfaces .RSAPublicKey ;
1818import java .util .Arrays ;
19- import java .util .Base64 ;
2019import java .util .Collections ;
2120import java .util .Date ;
2221import java .util .List ;
4443import com .ibm .websphere .security .jwt .JwtToken ;
4544import com .ibm .websphere .security .jwt .KeyException ;
4645import com .ibm .websphere .security .jwt .KeyStoreServiceException ;
47- import com .ibm .ws .ffdc .annotation .FFDCIgnore ;
4846import com .ibm .ws .kernel .productinfo .ProductInfo ;
4947import com .ibm .ws .security .common .crypto .KeyAlgorithmChecker ;
5048import com .ibm .ws .security .common .jwk .impl .JwKRetriever ;
@@ -91,7 +89,7 @@ public JwtToken parseJwt(String jwtString, JwtConsumerConfig config, MpConfigPro
9189 JwtTokenConsumerImpl jwtToken = new JwtTokenConsumerImpl (jwtContext );
9290 checkForReusedJwt (jwtToken , config );
9391 if (!isJwtContextAlreadyCached ) {
94- cacheJwtContext (jwtString , jwtContext , config );
92+ cacheJwtContext (jwtString , jwtContext , config , properties );
9593 }
9694 return jwtToken ;
9795 }
@@ -100,7 +98,7 @@ JwtContext parseJwtAndGetJwtContext(String jwtString, JwtConsumerConfig config,
10098 throws Exception {
10199 JwtContext jwtContext = parseJwtWithoutValidation (jwtString , config , mpConfigProps );
102100 if (config .isValidationRequired ()) {
103- validateJwtContext (jwtContext , jwtString , config , mpConfigProps );
101+ validateJwtContext (jwtContext , config , mpConfigProps );
104102 }
105103 return jwtContext ;
106104 }
@@ -377,20 +375,33 @@ protected JwtContext parseJwtWithoutValidation(String jwtString, JwtConsumerConf
377375 new Object [] { config .getId (), jwtString });
378376 throw new InvalidTokenException (errorMsg );
379377 }
380- checkJwtFormatAgainstConfigRequirements (jwtString , config , mpConfigProps );
381378 return parseNewJwtWithoutValidation (jwtString , config , mpConfigProps );
382379 }
383380
384381 void checkJwtFormatAgainstConfigRequirements (String jwtString , JwtConsumerConfig config ,
385382 MpConfigProperties mpConfigProps ) throws InvalidTokenException {
383+ JwtClaims jweHeaderParameters = null ;
384+ boolean isJWE = JweHelper .isJwe (jwtString );
385+ if (isJWE ) {
386+ jweHeaderParameters = JweHelper .getJweHeaderParams (jwtString );
387+ }
388+ checkJwtFormatAgainstConfigRequirements (jwtString , config , mpConfigProps , isJWE , jweHeaderParameters );
389+ }
390+
391+ private void checkJwtFormatAgainstConfigRequirements (String jwtString , JwtConsumerConfig config ,
392+ MpConfigProperties mpConfigProps , boolean isJWE , JwtClaims jweHeaderParameters ) throws InvalidTokenException {
386393 if (JweHelper .isJwsRequired (config , mpConfigProps ) && !JweHelper .isJws (jwtString )) {
387394 String errorMsg = Tr .formatMessage (tc , "JWS_REQUIRED_BUT_TOKEN_NOT_JWS" , new Object [] { config .getId () });
388395 throw new InvalidTokenException (errorMsg );
389396 }
390- if (JweHelper .isJweRequired (config , mpConfigProps ) && !JweHelper . isJwe ( jwtString ) ) {
397+ if (JweHelper .isJweRequired (config , mpConfigProps ) && !isJWE ) {
391398 String errorMsg = Tr .formatMessage (tc , "JWE_REQUIRED_BUT_TOKEN_NOT_JWE" , new Object [] { config .getId () });
392399 throw new InvalidTokenException (errorMsg );
393400 }
401+
402+ if (isJWE ) {
403+ validateHeaders (config , mpConfigProps , jweHeaderParameters );
404+ }
394405 }
395406
396407 JwtContext getJwtContextFromCache (@ Sensitive String jwtString , JwtConsumerConfig config ) {
@@ -405,23 +416,28 @@ private synchronized void initializeCache() {
405416 }
406417 }
407418
408- void cacheJwtContext (@ Sensitive String jwtString , JwtContext jwtContext , JwtConsumerConfig config ) {
419+ void cacheJwtContext (@ Sensitive String jwtString , JwtContext jwtContext , JwtConsumerConfig config , MpConfigProperties mpConfigProps ) {
409420 initializeCache ();
410- jwtCache .put (jwtString , config .getId (), jwtContext , config . getClockSkew ());
421+ jwtCache .put (jwtString , config .getId (), jwtContext , getClockSkew (config , mpConfigProps ));
411422 }
412423
413424 JwtContext parseNewJwtWithoutValidation (@ Sensitive String jwtString , JwtConsumerConfig config ,
414425 MpConfigProperties mpConfigProps ) throws InvalidTokenException , InvalidJwtException {
415- if (JweHelper .isJwe (jwtString )) {
416- jwtString = JweHelper .extractJwsFromJweToken (jwtString , config , mpConfigProps );
426+ JwtClaims jweHeaderParameters = null ;
427+ boolean isJWE = JweHelper .isJwe (jwtString );
428+ if (isJWE ) {
429+ jweHeaderParameters = JweHelper .getJweHeaderParams (jwtString );
430+ }
431+ checkJwtFormatAgainstConfigRequirements (jwtString , config , mpConfigProps , isJWE , jweHeaderParameters );
432+ if (isJWE ) {
433+ jwtString = JweHelper .extractJwsFromJweToken (jwtString , config , mpConfigProps , jweHeaderParameters );
417434 }
418435 JwtConsumerBuilder builder = initializeJwtConsumerBuilderWithoutValidation (config );
419436 JwtConsumer firstPassJwtConsumer = builder .build ();
420437 return firstPassJwtConsumer .process (jwtString );
421438 }
422439
423- protected void validateJwtContext (JwtContext jwtContext , String jwtString , JwtConsumerConfig config ,
424- MpConfigProperties mpConfigProps ) throws Exception {
440+ protected void validateJwtContext (JwtContext jwtContext , JwtConsumerConfig config , MpConfigProperties mpConfigProps ) throws Exception {
425441 Key key = getSigningKey (config , jwtContext , mpConfigProps );
426442 JwtClaims jwtClaims = jwtContext .getJwtClaims ();
427443
@@ -431,51 +447,36 @@ protected void validateJwtContext(JwtContext jwtContext, String jwtString, JwtCo
431447
432448 validateClaims (jwtClaims , jwtContext , config , mpConfigProps );
433449 validateSignatureAlgorithmWithKey (config , key , mpConfigProps );
434- validateHeaders (jwtContext , jwtString , config , mpConfigProps );
435450
436451 JwtConsumerBuilder consumerBuilder = initializeJwtConsumerBuilderWithValidation (config , jwtClaims , key );
437452 JwtConsumer jwtConsumer = consumerBuilder .build ();
438453 processJwtContextWithConsumer (jwtConsumer , jwtContext );
439454 }
440455
441- @ FFDCIgnore (Exception .class )
442- private void validateHeaders (JwtContext jwtContext , String jwtString , JwtConsumerConfig config ,
443- MpConfigProperties mpConfigProps ) throws Exception {
444-
445- if (isRunningBetaMode () && JweHelper .isJwe (jwtString )) {
446- try {
447- String keyManagementKeyAlgorithm = null ;
448- // Get keyManagementKeyAlgorithm from server.xml
449- keyManagementKeyAlgorithm = config .getKeyManagementKeyAlgorithm ();
450- /**
451- * If keyManagementKeyAlgorithm from server.xml is null, then take the value of
452- * keyManagementKeyAlgorithm from mpConfigProps
453- */
454- if (keyManagementKeyAlgorithm == null ) {
455- String value = mpConfigProps .get (MpConfigProperties .DECRYPT_KEY_ALGORITHM );
456- if (value != null ) {
457- keyManagementKeyAlgorithm = value ;
458- }
459- }
460- /**
461- * If keyManagementKeyAlgorithm is not null, do the following check if
462- * keyManagementKeyAlgorithm is null (i.e. MP JWT < 2.1) skip the check
463- */
464- if (keyManagementKeyAlgorithm != null ) {
465- String [] parts = jwtString .split (("\\ ." ));
466- String headerParametersAsJsonString = new String (Base64 .getDecoder ().decode (parts [0 ]), "UTF-8" );
467- JwtClaims headerParameters = JwtClaims .parse (headerParametersAsJsonString );
468- String tokenAlg = (String ) headerParameters .getClaimValue ("alg" );
469-
470- validateKeyManagementKeyAlgorithm (keyManagementKeyAlgorithm , tokenAlg );
471- }
472- } catch (Exception e ) {
473- if (tc .isDebugEnabled ()) {
474- Tr .debug (tc , "Exception validating headers: " , e );
456+ private void validateHeaders (JwtConsumerConfig config , MpConfigProperties mpConfigProps , JwtClaims jweHeaderParameters ) throws InvalidTokenException {
457+
458+ if (isRunningBetaMode ()) {
459+ String keyManagementKeyAlgorithm = null ;
460+ // Get keyManagementKeyAlgorithm from server.xml
461+ keyManagementKeyAlgorithm = config .getKeyManagementKeyAlgorithm ();
462+ /**
463+ * If keyManagementKeyAlgorithm from server.xml is null, then take the value of
464+ * keyManagementKeyAlgorithm from mpConfigProps
465+ */
466+ if (keyManagementKeyAlgorithm == null ) {
467+ String value = mpConfigProps .get (MpConfigProperties .DECRYPT_KEY_ALGORITHM );
468+ if (value != null ) {
469+ keyManagementKeyAlgorithm = value ;
475470 }
476- throw e ;
477471 }
478-
472+ /**
473+ * If keyManagementKeyAlgorithm is not null, do the following check if
474+ * keyManagementKeyAlgorithm is null (i.e. MP JWT < 2.1) skip the check
475+ */
476+ if (keyManagementKeyAlgorithm != null ) {
477+ String tokenAlg = (String ) jweHeaderParameters .getClaimValue ("alg" );
478+ validateKeyManagementKeyAlgorithm (keyManagementKeyAlgorithm , tokenAlg );
479+ }
479480 }
480481 }
481482
@@ -523,14 +524,7 @@ JwtConsumerBuilder initializeJwtConsumerBuilderWithValidation(JwtConsumerConfig
523524 return builder ;
524525 }
525526
526- void validateClaims (JwtClaims jwtClaims , JwtContext jwtContext , JwtConsumerConfig config ,
527- MpConfigProperties mpConfigProps )
528- throws MalformedClaimException , InvalidClaimException , InvalidTokenException {
529- String issuer = config .getIssuer ();
530- if (issuer == null ) {
531- issuer = mpConfigProps .get (MpConfigProperties .ISSUER );
532- }
533-
527+ private long getClockSkew (JwtConsumerConfig config , MpConfigProperties mpConfigProps ) {
534528 long clockSkew = config .getClockSkew ();
535529 /**
536530 * If clockSkew from server.xml is negative, then take the value of clock_skew
@@ -539,11 +533,23 @@ void validateClaims(JwtClaims jwtClaims, JwtContext jwtContext, JwtConsumerConfi
539533 if (clockSkew < 0 ) {
540534 String value = mpConfigProps .get (MpConfigProperties .CLOCK_SKEW );
541535 if (value != null ) {
542- clockSkew = Long .valueOf (value );
536+ clockSkew = Long .valueOf (value ) * 1000 ;
543537 } else {
544538 clockSkew = 0 ;
545539 }
546540 }
541+ return clockSkew ;
542+ }
543+
544+ void validateClaims (JwtClaims jwtClaims , JwtContext jwtContext , JwtConsumerConfig config ,
545+ MpConfigProperties mpConfigProps )
546+ throws MalformedClaimException , InvalidClaimException , InvalidTokenException {
547+ String issuer = config .getIssuer ();
548+ if (issuer == null ) {
549+ issuer = mpConfigProps .get (MpConfigProperties .ISSUER );
550+ }
551+
552+ long clockSkew = getClockSkew (config , mpConfigProps );
547553
548554 long tokenAgeInMilliSeconds = 0 ;
549555 // Take tokenAge value from server.xml
0 commit comments