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.keys.KeyProvider;
6   import com.atlassian.asap.core.validator.ValidatedKeyId;
7   import com.google.common.annotations.VisibleForTesting;
8   import com.google.common.collect.ImmutableList;
9   import org.slf4j.Logger;
10  import org.slf4j.LoggerFactory;
11  
12  import java.security.PublicKey;
13  import java.util.Iterator;
14  import java.util.List;
15  
16  /**
17   * Represents a set of repositories that host identical set of keys - i.e. they are mirrors of each other in terms of
18   * key content. Each repository in the set is expected to hold a full set of keys, so failure to find a key in any one
19   * can be treated as authoritative for the set.
20   */
21  public class MirroredKeyProvider implements KeyProvider<PublicKey> {
22      private static final Logger logger = LoggerFactory.getLogger(MirroredKeyProvider.class);
23  
24      private final List<KeyProvider<PublicKey>> mirrors;
25  
26      @VisibleForTesting
27      MirroredKeyProvider(List<KeyProvider<PublicKey>> mirrors) {
28          this.mirrors = ImmutableList.copyOf(mirrors);
29      }
30  
31      /**
32       * Create a mirrored key provider representing a given set of mirrored key repository providers.
33       * If there is only one provider in the given set of mirrors, then return the provider instead of
34       * wrapping it.
35       *
36       * @param mirrors list of mirrored key repository providers
37       * @return the mirrored key provider if there are more than one mirrors, or a key provider when it is
38       * the only provider in the set of mirrors.
39       */
40      public static KeyProvider<PublicKey> createMirroredKeyProvider(List<KeyProvider<PublicKey>> mirrors) {
41          // this is an optimization to avoid wrapping the keyprovider
42          // when there is only one keyprovider
43          if (mirrors.size() == 1) {
44              return mirrors.get(0);
45          } else {
46              return new MirroredKeyProvider(mirrors);
47          }
48      }
49  
50      @Override
51      public PublicKey getKey(ValidatedKeyId validatedKeyId) throws CannotRetrieveKeyException {
52          for (Iterator<KeyProvider<PublicKey>> keyProviderIterator = mirrors.iterator(); keyProviderIterator.hasNext(); ) {
53              try {
54                  return keyProviderIterator.next().getKey(validatedKeyId);
55              } catch (PublicKeyNotFoundException ex) {
56                  // Because they are mirrored, if the key is not present in one of them,
57                  // then it is absent in all of them
58                  throw ex;
59              } catch (CannotRetrieveKeyException ex) {
60                  if (keyProviderIterator.hasNext()) {
61                      logger.debug("Error communicating with a key provider, going to try next mirror", ex);
62                  } else {
63                      logger.error("Error communicating with all key providers: {}", mirrors, ex);
64                      throw new CannotRetrieveKeyException("Error communicating with all key providers", ex);
65                  }
66              }
67  
68          }
69          throw new CannotRetrieveKeyException("There are no mirrors available");
70      }
71  
72      public List<KeyProvider<PublicKey>> getMirrors() {
73          return mirrors;
74      }
75  
76      @Override
77      public String toString() {
78          return this.getClass().getSimpleName() + "{" + mirrors + '}';
79      }
80  }