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              final TransportErrorMessage error =
37                      new TransportErrorMessage(TransportErrorMessage.Code.MISSING_CERT,
38                              "\"Application Certificate too small.\" Values found: [" + values.size() + "] ." + values);
39              final Exception cause = new TransportException(error) {};
40              throw new ApplicationNotFoundException(cause);
41          }
42          if (values.size() == 2)
43          {
44              return getApplicationProtocolV0();
45          }
46          return getApplicationProtocolV1();
47      }
48  
49      private Application getApplicationProtocolV1() throws RetrievalException
50      {
51          // decorate the protocol zero version
52          final Application result = getApplicationProtocolV0();
53          // with some validation of the certificate
54          final String protocol = values.get(2);
55          final String magic = values.get(3);
56          try
57          {
58              final Integer protocolVersion = isBlank(protocol) ? null : Integer.valueOf(protocol);
59              try
60              {
61                  TrustedApplicationUtils.validateMagicNumber("application details", result.getID(), protocolVersion, magic);
62              }
63              catch (final InvalidCertificateException e)
64              {
65                  throw new InvalidApplicationDetailsException(e);
66              }
67          }
68          catch (final NumberFormatException e)
69          {
70              throw new InvalidApplicationDetailsException(e);
71          }
72          return result;
73      }
74  
75      private Application getApplicationProtocolV0() throws RetrievalException
76      {
77          try
78          {
79              final String id = values.get(0);
80              final String keyStr = values.get(1);
81  
82              if (keyStr == null)
83              {
84                  throw new ApplicationNotFoundException("Public Key not found");
85              }
86  
87              final byte[] data = transcoder.decode(keyStr);
88              final PublicKey key = encryptionProvider.toPublicKey(data);
89              return new SimpleApplication(id, key);
90          }
91          catch (final InvalidKeySpecException e)
92          {
93              throw new RuntimeException(e);
94          }
95          catch (final NoSuchAlgorithmException e)
96          {
97              throw new RuntimeException(e);
98          }
99          catch (final NoSuchProviderException e)
100         {
101             throw new RuntimeException(e);
102         }
103     }
104 
105     private static boolean isBlank(final String input)
106     {
107         return (input == null) || (input.trim().length() == 0);
108     }
109 }