1   package com.atlassian.security.auth.trustedapps;
2   
3   import com.atlassian.security.auth.trustedapps.Transcoder.Base64Transcoder;
4   
5   import java.security.NoSuchAlgorithmException;
6   import java.security.NoSuchProviderException;
7   import java.security.PublicKey;
8   import java.security.spec.InvalidKeySpecException;
9   import java.util.ArrayList;
10  import java.util.List;
11  
12  public class ListApplicationRetriever implements ApplicationRetriever
13  {
14      private final List<String> values;
15      private final EncryptionProvider encryptionProvider;
16      private final Transcoder transcoder = new Base64Transcoder();
17  
18      ListApplicationRetriever(final EncryptionProvider encryptionProvider, final List<String> values)
19      {
20          Null.not("encryptionProvider", encryptionProvider);
21          Null.not("values", values);
22          int i = 0;
23          for (final Object element : values)
24          {
25              Null.not("value: " + i++, element);
26          }
27  
28          this.encryptionProvider = encryptionProvider;
29          this.values = new ArrayList<String>(values);
30      }
31  
32      public Application getApplication() throws RetrievalException
33      {
34          if (values.size() < 2)
35          {
36              throw new ApplicationNotFoundException("Application Certificate too small");
37          }
38          if (values.size() == 2)
39          {
40              return getApplicationProtocolV0();
41          }
42          return getApplicationProtocolV1();
43      }
44  
45      private Application getApplicationProtocolV1() throws RetrievalException
46      {
47          // decorate the protocol zero version
48          final Application result = getApplicationProtocolV0();
49          // with some validation of the certificate
50          final String protocol = values.get(2);
51          final String magic = values.get(3);
52          try
53          {
54              final Integer protocolVersion = isBlank(protocol) ? null : Integer.valueOf(protocol);
55              try
56              {
57                  TrustedApplicationUtils.validateMagicNumber("application details", result.getID(), protocolVersion, magic);
58              }
59              catch (final InvalidCertificateException e)
60              {
61                  throw new InvalidApplicationDetailsException(e);
62              }
63          }
64          catch (final NumberFormatException e)
65          {
66              throw new InvalidApplicationDetailsException(e);
67          }
68          return result;
69      }
70  
71      private Application getApplicationProtocolV0() throws RetrievalException
72      {
73          try
74          {
75              final String id = values.get(0);
76              final String keyStr = values.get(1);
77  
78              if (keyStr == null)
79              {
80                  throw new ApplicationNotFoundException("Public Key not found");
81              }
82  
83              final byte[] data = transcoder.decode(keyStr);
84              final PublicKey key = encryptionProvider.toPublicKey(data);
85              return new SimpleApplication(id, key);
86          }
87          catch (final InvalidKeySpecException e)
88          {
89              throw new RuntimeException(e);
90          }
91          catch (final NoSuchAlgorithmException e)
92          {
93              throw new RuntimeException(e);
94          }
95          catch (final NoSuchProviderException e)
96          {
97              throw new RuntimeException(e);
98          }
99      }
100 
101     private static boolean isBlank(final String input)
102     {
103         return (input == null) || (input.trim().length() == 0);
104     }
105 }