View Javadoc

1   package com.atlassian.asap.core.keys.publickey;
2   
3   import com.atlassian.asap.api.exception.CannotRetrieveKeyException;
4   import com.atlassian.asap.core.exception.PublicKeyNotFoundException;
5   import com.atlassian.asap.core.exception.PublicKeyRetrievalException;
6   import com.atlassian.asap.core.keys.KeyProvider;
7   import com.atlassian.asap.core.keys.KeyReader;
8   import com.atlassian.asap.core.validator.ValidatedKeyId;
9   import com.google.common.annotations.VisibleForTesting;
10  import com.google.common.base.Preconditions;
11  import org.slf4j.Logger;
12  import org.slf4j.LoggerFactory;
13  
14  import java.io.IOException;
15  import java.io.InputStream;
16  import java.io.InputStreamReader;
17  import java.nio.charset.StandardCharsets;
18  import java.security.PublicKey;
19  import java.util.Objects;
20  
21  import static com.atlassian.asap.core.keys.ClassPathUri.classPathUri;
22  
23  /**
24   * Retrieves public keys from the classpath. The use of this provider in production code is discouraged because it
25   * does not make it possible to quickly add, remove or rotate keys. However, it may be useful for testing purposes.
26   */
27  public class ClasspathPublicKeyProvider implements KeyProvider<PublicKey> {
28      private static final Logger logger = LoggerFactory.getLogger(ClasspathPublicKeyProvider.class);
29  
30      private final KeyReader keyReader;
31      private final String classpathBase;
32  
33      /**
34       * Create a provider that reads public keys under the given classpath base.
35       *
36       * @param classpathBase classpath prefix, must end on a slash
37       * @param keyReader     key reader
38       */
39      public ClasspathPublicKeyProvider(String classpathBase, KeyReader keyReader) {
40          this.keyReader = Objects.requireNonNull(keyReader);
41          this.classpathBase = Objects.requireNonNull(classpathBase);
42          Preconditions.checkArgument(classpathBase.endsWith("/"), "Classpath prefix must end with a slash");
43      }
44  
45      @Override
46      public PublicKey getKey(ValidatedKeyId validatedKeyId) throws CannotRetrieveKeyException {
47          String pathToKey = classpathBase + validatedKeyId.getKeyId();
48  
49          logger.debug("Reading public key from classpath: {}", pathToKey);
50  
51          try (InputStream inputStream = ClasspathPublicKeyProvider.class.getResourceAsStream(pathToKey)) {
52              if (inputStream == null) {
53                  throw new PublicKeyNotFoundException(
54                          "Public key not found in the classpath", validatedKeyId, classPathUri(pathToKey));
55              }
56              try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.US_ASCII)) {
57                  return keyReader.readPublicKey(reader);
58              }
59          } catch (IOException e) {
60              throw new PublicKeyRetrievalException(
61                      "Error retrieving public key from classpath", e, validatedKeyId, classPathUri(pathToKey));
62          }
63      }
64  
65      @VisibleForTesting
66      String getClasspathBase() {
67          return classpathBase;
68      }
69  
70      @Override
71      public String toString() {
72          return this.getClass().getSimpleName();
73      }
74  }