View Javadoc

1   package com.atlassian.asap.nimbus.parser;
2   
3   import com.atlassian.asap.api.JwsHeader.Header;
4   import com.atlassian.asap.api.JwtClaims.RegisteredClaim;
5   import com.atlassian.asap.core.SecurityProvider;
6   import com.atlassian.asap.core.exception.JwtParseException;
7   import com.atlassian.asap.core.exception.MissingRequiredClaimException;
8   import com.atlassian.asap.core.exception.MissingRequiredHeaderException;
9   import com.atlassian.asap.core.exception.UnsupportedAlgorithmException;
10  import com.atlassian.asap.core.parser.JwtParser;
11  import com.atlassian.asap.core.parser.VerifiableJwt;
12  import com.nimbusds.jose.Algorithm;
13  import com.nimbusds.jose.JWSObject;
14  import com.nimbusds.jwt.JWTClaimsSet;
15  import net.minidev.json.JSONObject;
16  
17  import java.security.Provider;
18  import java.text.ParseException;
19  import java.util.Collection;
20  import java.util.Optional;
21  
22  /**
23   * A parser of JWT implemented using the Nimbus library.
24   */
25  public class NimbusJwtParser implements JwtParser {
26  
27      private final Provider provider;
28  
29      public NimbusJwtParser() {
30          this(SecurityProvider.getProvider());
31      }
32  
33      public NimbusJwtParser(final Provider provider) {
34          this.provider = provider;
35      }
36  
37      @Override
38      public VerifiableJwt parse(final String serializedJwt) throws JwtParseException, UnsupportedAlgorithmException {
39          final JWSObject jwsObject;
40          final JWTClaimsSet claims;
41  
42          try {
43              jwsObject = JWSObject.parse(serializedJwt);
44  
45              validateRequiredHeaders(jwsObject);
46  
47              JSONObject jsonPayload = jwsObject.getPayload().toJSONObject();
48              claims = JWTClaimsSet.parse(jsonPayload);
49          } catch (ParseException e) {
50              throw new JwtParseException(e);
51          }
52  
53          validateRequiredClaims(claims);
54          return NimbusVerifiableJwt.buildVerifiableJwt(jwsObject, claims, provider);
55      }
56  
57      @Override
58      public Optional<String> determineUnverifiedIssuer(String serializedJwt) {
59          try {
60              JWSObject jwsObject = JWSObject.parse(serializedJwt);
61              JSONObject jsonPayload = jwsObject.getPayload().toJSONObject();
62              JWTClaimsSet claims = JWTClaimsSet.parse(jsonPayload);
63              return Optional.ofNullable(claims.getIssuer());
64          } catch (ParseException e) {
65              return Optional.empty();
66          }
67      }
68  
69      private void validateRequiredHeaders(JWSObject jwsObject) throws MissingRequiredHeaderException {
70          if (jwsObject.getHeader().getAlgorithm() == null || jwsObject.getHeader().getAlgorithm() == Algorithm.NONE) {
71              throw new MissingRequiredHeaderException(Header.ALGORITHM);
72          }
73  
74          if (jwsObject.getHeader().getKeyID() == null) {
75              throw new MissingRequiredHeaderException(Header.KEY_ID);
76          }
77      }
78  
79      private void validateRequiredClaims(JWTClaimsSet claims) throws MissingRequiredClaimException {
80          checkClaimNotEmpty(claims.getAudience(), RegisteredClaim.AUDIENCE);
81          checkClaimNotNull(claims.getIssuer(), RegisteredClaim.ISSUER);
82          checkClaimNotNull(claims.getJWTID(), RegisteredClaim.JWT_ID);
83          checkClaimNotNull(claims.getIssueTime(), RegisteredClaim.ISSUED_AT);
84          checkClaimNotNull(claims.getExpirationTime(), RegisteredClaim.EXPIRY);
85      }
86  
87      private static void checkClaimNotNull(Object claimValue, RegisteredClaim claim) throws MissingRequiredClaimException {
88          if (claimValue == null) {
89              throw new MissingRequiredClaimException(claim);
90          }
91      }
92  
93      private static void checkClaimNotEmpty(Collection claimValue, RegisteredClaim claim) throws MissingRequiredClaimException {
94          if (claimValue == null || claimValue.isEmpty()) {
95              throw new MissingRequiredClaimException(claim);
96          }
97      }
98  }