View Javadoc

1   package com.atlassian.asap.core.validator;
2   
3   import com.atlassian.asap.api.Jwt;
4   import com.atlassian.asap.api.exception.CannotRetrieveKeyException;
5   import com.atlassian.asap.api.exception.InvalidTokenException;
6   import com.atlassian.asap.core.keys.KeyProvider;
7   import com.atlassian.asap.core.parser.JwtParser;
8   import com.atlassian.asap.core.parser.VerifiableJwt;
9   import com.atlassian.asap.core.server.AuthenticationContext;
10  import com.atlassian.asap.nimbus.parser.NimbusJwtParser;
11  
12  import java.security.PublicKey;
13  import java.time.Clock;
14  import java.util.Collections;
15  import java.util.Objects;
16  import java.util.Optional;
17  import java.util.Set;
18  import java.util.function.Supplier;
19  
20  /**
21   * Orchestrates the parsing of the JWT using the provided {@link JwtParser}, the verification of its signature using
22   * the provided {@link KeyProvider} and the validation of its claims using the
23   * provided {@link JwtClaimsValidator}.
24   */
25  public class JwtValidatorImpl implements JwtValidator {
26      private final KeyProvider<PublicKey> publicKeyProvider;
27      private final JwtParser jwtParser;
28      private final JwtClaimsValidator jwtClaimsValidator;
29      private final Supplier<Set<String>> resourceServerAudiences;
30  
31      /**
32       * Create a new instance of {@link JwtValidatorImpl}.
33       *
34       * @param publicKeyProvider       the key provider to use for retrieving public keys for signature verification
35       * @param jwtParser               the parser to use for parsing a serialized jwt string
36       * @param claimValidator          the validator to use for verifying the claims set contained in a JWT
37       * @param resourceServerAudiences all JWT messages will need to have one of these audiences to be valid.
38       *                                the supplier is called every time a JWT token is validated
39       */
40      public JwtValidatorImpl(KeyProvider<PublicKey> publicKeyProvider,
41                              JwtParser jwtParser,
42                              JwtClaimsValidator claimValidator,
43                              Supplier<Set<String>> resourceServerAudiences) {
44          this.publicKeyProvider = Objects.requireNonNull(publicKeyProvider);
45          this.jwtParser = Objects.requireNonNull(jwtParser);
46          this.jwtClaimsValidator = Objects.requireNonNull(claimValidator);
47          this.resourceServerAudiences = Objects.requireNonNull(resourceServerAudiences);
48      }
49  
50  
51      /**
52       * Create a new instance of {@link JwtValidatorImpl}.
53       *
54       * @param publicKeyProvider       the key provider to use for retrieving public keys for signature verification
55       * @param jwtParser               the parser to use for parsing a serialized jwt string
56       * @param claimValidator          the validator to use for verifying the claims set contained in a JWT
57       * @param resourceServerAudiences all JWT messages will need to have one of these audiences to be valid
58       */
59      public JwtValidatorImpl(KeyProvider<PublicKey> publicKeyProvider,
60                              JwtParser jwtParser,
61                              JwtClaimsValidator claimValidator,
62                              Set<String> resourceServerAudiences) {
63          this(publicKeyProvider, jwtParser, claimValidator, () -> resourceServerAudiences);
64      }
65  
66      /**
67       * Create a new instance of {@link JwtValidatorImpl}.
68       *
69       * @param publicKeyProvider      the key provider to use for retrieving public keys for signature verification
70       * @param jwtParser              the parser to use for parsing a serialized jwt string
71       * @param claimValidator         the validator to use for verifying the claims set contained in a JWT
72       * @param resourceServerAudience all JWT messages will need to have this audience to be valid
73       */
74      public JwtValidatorImpl(KeyProvider<PublicKey> publicKeyProvider,
75                              JwtParser jwtParser,
76                              JwtClaimsValidator claimValidator,
77                              String resourceServerAudience) {
78          this(publicKeyProvider, jwtParser, claimValidator, Collections.singleton(resourceServerAudience));
79      }
80  
81      @Override
82      public final Jwt readAndValidate(String serializedJwt)
83              throws InvalidTokenException, CannotRetrieveKeyException {
84          // Parse the serialized JWT without performing any verification of the signature or claims
85          VerifiableJwt verifiableJwt = jwtParser.parse(serializedJwt);
86  
87          // Ensure we have a valid key id before the public key is fetched
88          ValidatedKeyId validatedKeyId = ValidatedKeyId.validate(verifiableJwt.getHeader().getKeyId());
89  
90          // fetch the public key and verify the signature of the JWT
91          PublicKey publicKey = publicKeyProvider.getKey(validatedKeyId);
92          verifiableJwt.verifySignature(publicKey);
93  
94          // validate the claims of the JWT, and return it if validation is successful
95          jwtClaimsValidator.validate(verifiableJwt, resourceServerAudiences.get());
96  
97          return verifiableJwt;
98      }
99  
100     @Override
101     public final Optional<String> determineUnverifiedIssuer(String serializedJwt) {
102         return jwtParser.determineUnverifiedIssuer(serializedJwt);
103     }
104 
105     /**
106      * A factory method that returns an instance with a typical configuration.
107      *
108      * @param authenticationContext context of the authentication
109      * @return a request authenticator for the given context
110      */
111     public static JwtValidator createDefault(AuthenticationContext authenticationContext) {
112         return new JwtValidatorImpl(authenticationContext.getPublicKeyProvider(),
113                 new NimbusJwtParser(),
114                 new JwtClaimsValidator(Clock.systemUTC()),
115                 authenticationContext.getResourceServerAudiences());
116     }
117 
118     /**
119      * A factory method that returns an instance with a typical configuration.
120      *
121      * @param audience             the audience this filter will accept requests for
122      * @param publicKeyRepoBaseUrl the base URL of the public key repository
123      * @return a web filter
124      */
125     public static JwtValidator createDefault(String audience, String publicKeyRepoBaseUrl) {
126         AuthenticationContext authContext = new AuthenticationContext(audience, publicKeyRepoBaseUrl);
127         return createDefault(authContext);
128     }
129 
130     /**
131      * A factory method that returns an instance with a typical configuration.
132      *
133      * @param audiences            the audiences this filter will accept requests for
134      * @param publicKeyRepoBaseUrl the base URL of the public key repository
135      * @return a web filter
136      */
137     public static JwtValidator createDefault(Set<String> audiences, String publicKeyRepoBaseUrl) {
138         AuthenticationContext authContext = new AuthenticationContext(audiences, publicKeyRepoBaseUrl);
139         return createDefault(authContext);
140     }
141 }