View Javadoc

1   package com.atlassian.asap.core.client.jersey;
2   
3   import com.atlassian.asap.api.Jwt;
4   import com.atlassian.asap.api.JwtBuilder;
5   import com.atlassian.asap.api.client.http.AuthorizationHeaderGenerator;
6   import com.atlassian.asap.api.exception.CannotRetrieveKeyException;
7   import com.atlassian.asap.api.exception.InvalidTokenException;
8   import com.atlassian.asap.core.client.http.AuthorizationHeaderGeneratorImpl;
9   import com.google.common.annotations.VisibleForTesting;
10  import org.slf4j.Logger;
11  import org.slf4j.LoggerFactory;
12  
13  import javax.annotation.Priority;
14  import javax.ws.rs.Priorities;
15  import javax.ws.rs.client.ClientRequestContext;
16  import javax.ws.rs.client.ClientRequestFilter;
17  import javax.ws.rs.core.Response;
18  import javax.ws.rs.ext.Provider;
19  import java.io.IOException;
20  import java.net.URI;
21  import java.time.Instant;
22  import java.util.Objects;
23  import java.util.Optional;
24  import java.util.UUID;
25  
26  import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION;
27  import static javax.ws.rs.core.Response.Status.UNAUTHORIZED;
28  
29  /**
30   * Use this class to authenticate Jersey 2 client requests with ASAP.
31   *
32   * @since 2.10
33   */
34  @Provider
35  @Priority(Priorities.AUTHENTICATION)
36  public class AsapAuthenticationFilter implements ClientRequestFilter {
37      @VisibleForTesting
38      static final String CLIENT_ASAP_TOKEN_ERROR_MESSAGE = "Client failed to generate ASAP token.";
39  
40      private static final Logger log = LoggerFactory.getLogger(AsapAuthenticationFilter.class);
41  
42      private final Jwt prototype;
43      private final AuthorizationHeaderGenerator authorizationHeaderGenerator;
44  
45      public AsapAuthenticationFilter(Jwt prototype, URI privateKeyPath) {
46          this(prototype, AuthorizationHeaderGeneratorImpl.createDefault(privateKeyPath));
47      }
48  
49      public AsapAuthenticationFilter(Jwt prototype, AuthorizationHeaderGenerator authorizationHeaderGenerator) {
50          this.prototype = Objects.requireNonNull(prototype);
51          this.authorizationHeaderGenerator = Objects.requireNonNull(authorizationHeaderGenerator);
52      }
53  
54      private String getAsapBearerToken() throws CannotRetrieveKeyException, InvalidTokenException {
55          return authorizationHeaderGenerator.generateAuthorizationHeader(newJwtToken());
56      }
57  
58      private Jwt newJwtToken() {
59          Instant now = Instant.now();
60  
61          return JwtBuilder.copyJwt(prototype)
62                  .notBefore(Optional.of(now))
63                  .issuedAt(now)
64                  .expirationTime(now.plus(JwtBuilder.DEFAULT_LIFETIME))
65                  .jwtId(UUID.randomUUID().toString())
66                  .build();
67      }
68  
69      @Override
70      public void filter(ClientRequestContext requestContext) throws IOException {
71          if (!requestContext.getHeaders().containsKey(AUTHORIZATION)) {
72              try {
73                  requestContext.getHeaders().add(AUTHORIZATION, getAsapBearerToken());
74              } catch (CannotRetrieveKeyException | InvalidTokenException ex) {
75                  log.error("Exception generating ASAP token.", ex);
76                  requestContext.abortWith(Response.status(UNAUTHORIZED).entity(CLIENT_ASAP_TOKEN_ERROR_MESSAGE).build());
77              }
78          }
79      }
80  }