1   package com.atlassian.security.auth.trustedapps.filter;
2   
3   import com.atlassian.security.auth.trustedapps.*;
4   import junit.framework.TestCase;
5   
6   import javax.servlet.http.HttpServletRequest;
7   import javax.servlet.http.HttpServletResponse;
8   import java.security.KeyPair;
9   import java.security.NoSuchAlgorithmException;
10  import java.security.NoSuchProviderException;
11  import java.security.Principal;
12  
13  /**
14   * This test is really an integration test as it tests the production behaviour of the authenticate method
15   */
16  public class TestTrustedApplicationsFilterAuthenticate extends TestCase
17  {
18      // -----------------------------------------------------------------------------------------------------------------
19      // members
20      // -----------------------------------------------------------------------------------------------------------------
21  
22      private final EncryptionProvider provider = new BouncyCastleEncryptionProvider();
23      private final TrustedApplicationsManager manager = new TrustedApplicationsManager()
24      {
25          final KeyPair pair;
26          final CurrentApplication me;
27  
28          {
29              try
30              {
31                  pair = provider.generateNewKeyPair();
32              }
33              catch (NoSuchAlgorithmException e)
34              {
35                  throw new RuntimeException(e);
36              }
37              catch (NoSuchProviderException e)
38              {
39                  throw new RuntimeException(e);
40              }
41              me = new DefaultCurrentApplication(pair.getPublic(), pair.getPrivate(), "me");
42          }
43  
44          public CurrentApplication getCurrentApplication()
45          {
46              return me;
47          }
48  
49          public TrustedApplication getTrustedApplication(String id)
50          {
51              if (id.equals("me"))
52              {
53                  return new DefaultTrustedApplication(provider, pair.getPublic(), "me", RequestConditions.builder().setCertificateTimeout(1000L).build())
54                  {
55                      @Override
56                      protected void checkRequest(HttpServletRequest request) throws InvalidCertificateException
57                      {
58                          try
59                          {
60                              if (request.getHeader("ip-mismatch") != null)
61                              {
62                                  throw new InvalidRemoteAddressException(request.getRemoteAddr());
63                              }
64                              if (request.getHeader("forward-mismatch") != null)
65                              {
66                                  throw new InvalidXForwardedForAddressException(request.getRemoteAddr());
67                              }
68                              if (request.getHeader("url-mismatch") != null)
69                              {
70                                  throw new InvalidRequestUrlException(request.getPathInfo());
71                              }
72                          }
73                          catch (final InvalidRequestException e)
74                          {
75                              throw new InvalidCertificateException(e);
76                          }
77                      }
78                  };
79              }
80              return null;
81          }
82      };
83  
84      private Principal principal = null;
85      private final UserResolver userResolver = new UserResolver()
86      {
87          public Principal resolve(ApplicationCertificate certificate)
88          {
89              return principal;
90          }
91      };
92      private final TrustedApplicationsFilter filter = new TrustedApplicationsFilter(manager, userResolver, new AuthenticationController()
93      {
94          public boolean canLogin(Principal user, HttpServletRequest request)
95          {
96              return true;
97          }
98  
99          public boolean shouldAttemptAuthentication(HttpServletRequest request)
100         {
101             return true;
102         }
103 
104     }, new AuthenticationListener()
105     {
106         public void authenticationSuccess(Authenticator.Result result, HttpServletRequest request, HttpServletResponse response)
107         {
108         }
109 
110         public void authenticationFailure(Authenticator.Result result, HttpServletRequest request, HttpServletResponse response)
111         {
112         }
113 
114         public void authenticationError(Authenticator.Result result, HttpServletRequest request, HttpServletResponse response)
115         {
116         }
117 
118         public void authenticationNotAttempted(HttpServletRequest request, HttpServletResponse response)
119         {
120         }
121     })
122     {
123     };
124 
125     protected void setUp() throws Exception
126     {
127         principal = null;
128     }
129 
130     // -----------------------------------------------------------------------------------------------------------------
131     // tests
132     // -----------------------------------------------------------------------------------------------------------------
133 
134     public void testNoTrustedAppAttempt() throws Exception
135     {
136         MockRequest request = new MockRequest("/some/path");
137         MockResponse response = new MockResponse();
138         assertFalse(filter.authenticate(request, response));
139         // TODO: add assertion about listener
140         final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
141         assertNull(error, error);
142     }
143 
144     public void testKnownAppProtocolVersion0() throws Exception
145     {
146         CurrentApplication me = manager.getCurrentApplication();
147         principal = new Principal()
148         {
149             public String getName()
150             {
151                 return "blah-de-blah-blah";
152             }
153         };
154         EncryptedCertificate cert = me.encode("blah-de-blah-blah");
155         MockRequest request = new MockTrustedAppRequestV0(cert);
156         MockResponse response = new MockResponse();
157         assertTrue(filter.authenticate(request, response));
158         // TODO: add assertion about listener
159         final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
160         assertNull(error, error);
161     }
162 
163     public void testKnownAppProtocolVersion1() throws Exception
164     {
165         CurrentApplication me = manager.getCurrentApplication();
166         principal = new Principal()
167         {
168             public String getName()
169             {
170                 return "blah-de-blah-blah";
171             }
172         };
173         EncryptedCertificate cert = me.encode("blah-de-blah-blah");
174         MockRequest request = new MockTrustedAppRequestV0(cert);
175 
176         MockResponse response = new MockResponse();
177         assertTrue(filter.authenticate(request, response));
178         // TODO: add assertion about listener
179         final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
180         assertNull(error, error);
181     }
182 
183     public void testUnknownApp() throws Exception
184     {
185         EncryptedCertificate cert = new EncryptedCertificate()
186         {
187             public String getCertificate()
188             {
189                 return "some-cert";
190             }
191 
192             public String getID()
193             {
194                 return "appId";
195             }
196 
197             public String getMagicNumber()
198             {
199                 return "dis is majick";
200             }
201 
202             public Integer getProtocolVersion()
203             {
204                 return new Integer(1);
205             }
206 
207             public String getSecretKey()
208             {
209                 return "dis-is-a-sekrit";
210             }
211         };
212         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
213         assertFailed("Unknown Application:", request);
214     }
215 
216     public void testBadSecretKey() throws Exception
217     {
218         CurrentApplication me = manager.getCurrentApplication();
219         EncryptedCertificate cert = me.encode("blad-de-blah-blah");
220         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
221         request.addHeader(TrustedApplicationUtils.Header.Request.SECRET_KEY, "0123981237123827234842374");
222         assertError("BAD_MAGIC;\tUnable to decrypt certificate {0} for application {1};\t[\"secret key\",\"me\"]", request);
223     }
224 
225     public void testBadCertificate() throws Exception
226     {
227         CurrentApplication me = manager.getCurrentApplication();
228         EncryptedCertificate cert = me.encode("blad-de-blah-blah");
229         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
230         request.addHeader(TrustedApplicationUtils.Header.Request.CERTIFICATE, "0123981237123827234842374");
231         assertError("BAD_MAGIC;\tUnable to decrypt certificate {0} for application {1};\t[\"secret key\",\"me\"]", request);
232     }
233 
234     public void testBadPublicKey() throws Exception
235     {
236         CurrentApplication me = manager.getCurrentApplication();
237         EncryptedCertificate cert = me.encode("blad-de-blah-blah");
238         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
239         request.addHeader(TrustedApplicationUtils.Header.Request.MAGIC, "123798211233723187217");
240         assertError("BAD_MAGIC;\tUnable to decrypt certificate {0} for application {1};\t[\"public key\",\"me\"]", request);
241     }
242 
243     public void testBadRequestIp() throws Exception
244     {
245         CurrentApplication me = manager.getCurrentApplication();
246         EncryptedCertificate cert = me.encode("blad-de-blah-blah");
247         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
248         request.addHeader("ip-mismatch", "true");
249         assertError("BAD_REMOTE_IP;\tRequest not allowed from IP address: {0};\t[\"i.am.a.teapot\"]", request);
250     }
251 
252     public void testBadXForwardIp() throws Exception
253     {
254         CurrentApplication me = manager.getCurrentApplication();
255         EncryptedCertificate cert = me.encode("blad-de-blah-blah");
256         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
257         request.addHeader("forward-mismatch", "true");
258         assertError("BAD_XFORWARD_IP;\tRequest not allowed from IP address: {0};\t[\"i.am.a.teapot\"]", request);
259     }
260 
261     public void testBadRequestUrl() throws Exception
262     {
263         CurrentApplication me = manager.getCurrentApplication();
264         EncryptedCertificate cert = me.encode("blad-de-blah-blah");
265         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1("/jira/secure/DeleteProject.jspa", cert);
266         request.addHeader("url-mismatch", "true");
267         assertError("BAD_URL;\tRequest not allowed to access URL: {0};\t[\"/jira/secure/DeleteProject.jspa\"]", request);
268     }
269 
270     // -----------------------------------------------------------------------------------------------------------------
271     // helpers
272     // -----------------------------------------------------------------------------------------------------------------
273 
274     private void assertFailed(String msg, MockRequest request)
275     {
276         MockResponse response = new MockResponse();
277 
278         assertFalse(filter.authenticate(request, response));
279         // TODO: add assertion about listener
280         final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
281         System.out.println(error);
282         assertNotNull(error);
283         assertTrue("Expected: '" + msg + "' got:" + error, error.indexOf(msg) >= 0);
284     }
285 
286     private void assertError(String msg, MockRequest request)
287     {
288         MockResponse response = new MockResponse();
289 
290         assertFalse(filter.authenticate(request, response));
291         // TODO: add assertion about listener       
292         final String error = (String) response.getHeaders().get(TrustedApplicationUtils.Header.Response.ERROR);
293         System.out.println(error);
294         assertNotNull(error);
295         assertEquals(msg, error);
296         //assertTrue("Expected: '" + msg + "' got:" + error, error.indexOf(msg) >= 0);
297     }
298 }