View Javadoc

1   package com.atlassian.asap.core.keys.privatekey;
2   
3   import com.atlassian.asap.core.keys.DataUriKeyReader;
4   import com.google.common.annotations.VisibleForTesting;
5   import org.slf4j.Logger;
6   import org.slf4j.LoggerFactory;
7   
8   import java.net.URI;
9   import java.net.URISyntaxException;
10  import java.util.Optional;
11  
12  import static com.google.common.base.Preconditions.checkArgument;
13  
14  /**
15   * Reads private keys specified as data uri from environment variables.
16   *
17   * <p>Note that Environment variables are case-insensitive in some systems (Windows). However, ASAP key identifiers are case-sensitive.
18   * That means that the same environment variable will provide the private key for "keyidentifier", "KEYIDENTIFIER", "keyIdentifier" and so on.
19   *
20   * @see System#getenv(String)
21   */
22  public final class EnvironmentVariableKeyProvider extends DataUriKeyProvider {
23      static final String URL_SCHEME = "env";
24      private static final Logger logger = LoggerFactory.getLogger(EnvironmentVariableKeyProvider.class);
25  
26      @VisibleForTesting
27      EnvironmentVariableKeyProvider(String variableName, DataUriKeyReader keyReader, Environment environment) {
28          super(getDataUriFromEnvironment(variableName, environment), keyReader);
29      }
30  
31      private static URI getDataUriFromEnvironment(String variableName, Environment environment) {
32          logger.debug("Reading private key from environment variable {}", variableName);
33          String environmentVariableValue = environment.getVariable(variableName)
34                  .orElseThrow(() -> new IllegalArgumentException("Undefined environment variable: " + variableName));
35          try {
36              return new URI(environmentVariableValue);
37          } catch (URISyntaxException e) {
38              throw new IllegalArgumentException("Value of environment variable " + variableName +
39                      " cannot be parsed as a URI");
40          }
41      }
42  
43      /**
44       * Instantiates the class by parsing a URL with the following syntax:
45       * <code>env:///[BASE_ENV_VARIABLE_NAME]</code>.
46       *
47       * @param uri       URI with the syntax described above
48       * @param keyReader reader of PEM documents
49       * @return a new instance of the class
50       */
51      public static EnvironmentVariableKeyProvider fromUri(URI uri, DataUriKeyReader keyReader) {
52          return fromUri(uri, keyReader, new Environment());
53      }
54  
55      @VisibleForTesting
56      static EnvironmentVariableKeyProvider fromUri(URI uri, DataUriKeyReader keyReader, Environment environment) {
57          checkArgument(uri.isAbsolute(), "URL must be absolute"); // implies that scheme != null
58          checkArgument(URL_SCHEME.equals(uri.getScheme()), "URL must have " + URL_SCHEME + " scheme");
59          checkArgument(uri.getPath() != null && uri.getPath().startsWith("/"), "URL must have a path component");
60          checkArgument(uri.getQuery() == null, "URL must not have a query component");
61          checkArgument(uri.getAuthority() == null, "URL must not have an authority component");
62  
63          String basePropertyName = uri.getPath().substring(1); // remove the trailing slash
64          return new EnvironmentVariableKeyProvider(basePropertyName, keyReader, environment);
65      }
66  
67      static class Environment {
68          public Optional<String> getVariable(String name) {
69              return Optional.ofNullable(System.getenv(name));
70          }
71      }
72  }