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.Principal;
9   import java.security.PublicKey;
10  
11  public class TestTrustedAppAuthenticatorImpl extends TestCase
12  {
13      private static final String USER = "blad-de-blah-blah";
14      private final PublicKey publicKey = new PublicKey()
15      {
16          public String getAlgorithm()
17          {
18              return "algy";
19          }
20  
21          public byte[] getEncoded()
22          {
23              return new byte[] { 4, 3, 2, 1 };
24          }
25  
26          public String getFormat()
27          {
28              return "format";
29          }
30      };
31  
32      private final TrustedApplicationsManager manager = new TrustedApplicationsManager()
33      {
34          final CurrentApplication me = new CurrentApplication()
35          {
36              public String getID()
37              {
38                  return "me-id";
39              }
40  
41              public PublicKey getPublicKey()
42              {
43                  return publicKey;
44              }
45  
46              public EncryptedCertificate encode(final String userName)
47              {
48                  return new EncryptedCertificate()
49                  {
50                      public String getCertificate()
51                      {
52                          return userName;
53                      }
54  
55                      public String getID()
56                      {
57                          return "me-id";
58                      }
59  
60                      public String getMagicNumber()
61                      {
62                          return "1";
63                      }
64  
65                      public Integer getProtocolVersion()
66                      {
67                          return new Integer(1);
68                      }
69  
70                      public String getSecretKey()
71                      {
72                          return "secret";
73                      }
74                  };
75              }
76          };
77  
78          public CurrentApplication getCurrentApplication()
79          {
80              return me;
81          }
82  
83          public TrustedApplication getTrustedApplication(String id)
84          {
85              if (id.equals("me-id"))
86              {
87                  return new TrustedApplication()
88                  {
89                      public ApplicationCertificate decode(EncryptedCertificate certificate, HttpServletRequest request) throws InvalidCertificateException
90                      {
91                          if (request.getHeader("ip-mismatch") != null)
92                          {
93                              throw new InvalidCertificateException(new InvalidRemoteAddressException(request.getRemoteAddr()));
94                          }
95                          if (request.getHeader("forward-mismatch") != null)
96                          {
97                              throw new InvalidCertificateException(new InvalidXForwardedForAddressException(request.getRemoteAddr()));
98                          }
99                          if (request.getHeader("url-mismatch") != null)
100                         {
101                             throw new InvalidCertificateException(new InvalidRequestUrlException(request.getPathInfo()));
102                         }
103                         if ("bad-cert".equals(certificate.getCertificate()))
104                         {
105                             throw new InvalidCertificateException(new SystemException("bad-cert", new NullPointerException("what a bad certificate!")));
106                         }
107                         return new DefaultApplicationCertificate("me-id", certificate.getCertificate(), System.currentTimeMillis());
108                     }
109 
110                     public PublicKey getPublicKey()
111                     {
112                         return publicKey;
113                     }
114 
115                     public String getID()
116                     {
117                         return "me-id";
118                     }
119 
120                     public RequestConditions getRequestConditions()
121                     {
122                         return null;
123                     }
124 
125                     public String getName()
126                     {
127                         return null;
128                     }
129                 };
130             }
131             return null;
132         }
133     };
134 
135     private final Principal principal = new Principal()
136     {
137         public String getName()
138         {
139             return USER;
140         }
141     };
142 
143     private final UserResolver resolver = new UserResolver()
144     {
145         public Principal resolve(ApplicationCertificate certificate)
146         {
147             return (certificate.getUserName().equals(principal.getName())) ? principal : null;
148         };
149     };
150 
151     private final boolean[] canLogin = new boolean[] { true };
152     private final AuthenticationController authenticationController = new AuthenticationController()
153     {
154         public boolean shouldAttemptAuthentication(HttpServletRequest request)
155         {
156             return true;
157         }
158 
159         public boolean canLogin(Principal user, HttpServletRequest request)
160         {
161             return canLogin[0];
162         }
163     };
164 
165     private final Authenticator authenticator = new TrustedApplicationFilterAuthenticator(manager, resolver, authenticationController)
166     {
167         public Result authenticate(HttpServletRequest request, HttpServletResponse response)
168         {
169             return super.authenticate(ImmutableRequest.wrap(request), response);
170         }
171     };
172 
173     protected void setUp() throws Exception
174     {
175         canLogin[0] = true;
176     }
177 
178     // -----------------------------------------------------------------------------------------------------------------
179     // tests
180     // -----------------------------------------------------------------------------------------------------------------
181 
182     public void testKnownAppProtocolVersion0() throws Exception
183     {
184         CurrentApplication me = manager.getCurrentApplication();
185         EncryptedCertificate cert = me.encode(USER);
186         MockRequest request = new MockTrustedAppRequestV0(cert);
187 
188         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
189 
190         assertNotNull(result);
191         assertEquals(Authenticator.Result.Status.SUCCESS, result.getStatus());
192     }
193 
194     public void testKnownAppProtocolVersion1() throws Exception
195     {
196         CurrentApplication me = manager.getCurrentApplication();
197         EncryptedCertificate cert = me.encode(USER);
198         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
199 
200         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
201 
202         assertNotNull(result);
203         assertEquals(Authenticator.Result.Status.SUCCESS, result.getStatus());
204         assertNotNull(result.getUser());
205     }
206 
207     public void testUnknownApp() throws Exception
208     {
209         EncryptedCertificate cert = new EncryptedCertificate()
210         {
211             public String getCertificate()
212             {
213                 return "cert";
214             };
215 
216             public String getID()
217             {
218                 return "appId";
219             }
220 
221             public String getMagicNumber()
222             {
223                 return "majick";
224             }
225 
226             public Integer getProtocolVersion()
227             {
228                 return new Integer(1);
229             }
230 
231             public String getSecretKey()
232             {
233                 return "dis-is-a-sekrit";
234             }
235         };
236         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
237         // CurrentApplication me = manager.getCurrentApplication();
238 
239         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
240 
241         assertNotNull(result);
242         assertEquals(Authenticator.Result.Status.FAILED, result.getStatus());
243         assertEquals("APP_UNKNOWN;\tUnknown Application: {0};\t[\"appId\"]", result.getMessage());
244         assertNull(result.getUser());
245     }
246 
247     public void testBlankAppId() throws Exception
248     {
249         EncryptedCertificate cert = new EncryptedCertificate()
250         {
251             public String getCertificate()
252             {
253                 return "cert";
254             };
255 
256             public String getID()
257             {
258                 return null;
259             }
260 
261             public String getMagicNumber()
262             {
263                 return "majick";
264             }
265 
266             public Integer getProtocolVersion()
267             {
268                 return new Integer(1);
269             }
270 
271             public String getSecretKey()
272             {
273                 return "dis-is-a-sekrit";
274             }
275         };
276         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
277         // CurrentApplication me = manager.getCurrentApplication();
278 
279         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
280 
281         assertNotNull(result);
282         assertEquals(Authenticator.Result.Status.ERROR, result.getStatus());
283         assertEquals("APP_ID_NOT_FOUND;\tApplication ID not found in request;\t[]", result.getMessage());
284         assertNull(result.getUser());
285     }
286 
287     public void testBadProtocolVersion() throws Exception
288     {
289         EncryptedCertificate cert = new EncryptedCertificate()
290         {
291             public String getCertificate()
292             {
293                 return "cert";
294             };
295 
296             public String getID()
297             {
298                 return "me-id";
299             }
300 
301             public String getMagicNumber()
302             {
303                 return "majick";
304             }
305 
306             public Integer getProtocolVersion()
307             {
308                 return new Integer(1);
309             }
310 
311             public String getSecretKey()
312             {
313                 return "dis-is-a-sekrit";
314             }
315         };
316         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
317         request.addHeader(TrustedApplicationUtils.Header.Request.VERSION, "a-dodgy-version");
318 
319         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
320 
321         assertNotNull(result);
322         assertEquals(Authenticator.Result.Status.ERROR, result.getStatus());
323         assertEquals("BAD_PROTOCOL_VERSION;\tBad protocol version: {0};\t[\"a-dodgy-version\"]", result.getMessage());
324         assertNull(result.getUser());
325     }
326 
327     public void testMissingSecretKey() throws Exception
328     {
329         EncryptedCertificate cert = new EncryptedCertificate()
330         {
331             public String getCertificate()
332             {
333                 return "cert";
334             };
335 
336             public String getID()
337             {
338                 return "me-id";
339             }
340 
341             public String getMagicNumber()
342             {
343                 return "majick";
344             }
345 
346             public Integer getProtocolVersion()
347             {
348                 return new Integer(1);
349             }
350 
351             public String getSecretKey()
352             {
353                 return "";
354             }
355         };
356         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
357 
358         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
359 
360         assertNotNull(result);
361         assertEquals(Authenticator.Result.Status.ERROR, result.getStatus());
362         assertEquals("SECRET_KEY_NOT_FOUND;\tSecret Key not found in request;\t[]", result.getMessage());
363         assertNull(result.getUser());
364     }
365 
366     public void testMissingMagicNumber() throws Exception
367     {
368         EncryptedCertificate cert = new EncryptedCertificate()
369         {
370             public String getCertificate()
371             {
372                 return "cert";
373             };
374 
375             public String getID()
376             {
377                 return "me-id";
378             }
379 
380             public String getMagicNumber()
381             {
382                 return null;
383             }
384 
385             public Integer getProtocolVersion()
386             {
387                 return new Integer(1);
388             }
389 
390             public String getSecretKey()
391             {
392                 return "asudyasduh";
393             }
394         };
395         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
396 
397         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
398 
399         assertNotNull(result);
400         assertEquals(Authenticator.Result.Status.ERROR, result.getStatus());
401         assertEquals("MAGIC_NUMBER_NOT_FOUND;\tMagic Number not found in request;\t[]", result.getMessage());
402         assertNull(result.getUser());
403     }
404 
405     public void testBadCertificate() throws Exception
406     {
407         CurrentApplication me = manager.getCurrentApplication();
408         EncryptedCertificate cert = me.encode(USER);
409         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
410         request.addHeader(TrustedApplicationUtils.Header.Request.CERTIFICATE, "bad-cert");
411 
412         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
413 
414         assertNotNull(result);
415         assertEquals(result.getMessage(), Authenticator.Result.Status.ERROR, result.getStatus());
416         assertEquals("SYSTEM;\tException: {0} occurred serving request for application: {1};\t[\"java.lang.NullPointerException: what a bad certificate!\",\"bad-cert\"]", result.getMessage());
417         assertNull(result.getUser());
418     }
419 
420     public void testPrincipalNotFound() throws Exception
421     {
422         CurrentApplication me = manager.getCurrentApplication();
423         EncryptedCertificate cert = me.encode("unknown-principal");
424         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
425 
426         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
427 
428         assertNotNull(result);
429         assertEquals(result.getMessage(), Authenticator.Result.Status.FAILED, result.getStatus());
430         assertEquals("USER_UNKNOWN;\tUnknown User: {0};\t[\"unknown-principal\"]", result.getMessage());
431         assertNull(result.getUser());
432     }
433 
434     public void testPrincipalLoginDenied() throws Exception
435     {
436         CurrentApplication me = manager.getCurrentApplication();
437         EncryptedCertificate cert = me.encode(USER);
438         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
439 
440         canLogin[0] = false;
441         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
442 
443         assertNotNull(result);
444         assertEquals(result.getMessage(), Authenticator.Result.Status.FAILED, result.getStatus());
445         assertEquals("PERMISSION_DENIED;\tPermission Denied;\t[]", result.getMessage());
446         assertNull(result.getUser());
447     }
448 
449     public void testBadRequestIp() throws Exception
450     {
451         CurrentApplication me = manager.getCurrentApplication();
452         EncryptedCertificate cert = me.encode(USER);
453         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
454         request.addHeader("ip-mismatch", "true");
455 
456         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
457 
458         assertNotNull(result);
459         assertEquals(result.getMessage(), Authenticator.Result.Status.ERROR, result.getStatus());
460         assertEquals("BAD_REMOTE_IP;\tRequest not allowed from IP address: {0};\t[\"i.am.a.teapot\"]", result.getMessage());
461         assertNull(result.getUser());
462     }
463 
464     public void testBadXForwardIp() throws Exception
465     {
466         CurrentApplication me = manager.getCurrentApplication();
467         EncryptedCertificate cert = me.encode(USER);
468         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1(cert);
469         request.addHeader("forward-mismatch", "true");
470 
471         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
472 
473         assertNotNull(result);
474         assertEquals(Authenticator.Result.Status.ERROR, result.getStatus());
475         assertEquals("BAD_XFORWARD_IP;\tRequest not allowed from IP address: {0};\t[\"i.am.a.teapot\"]", result.getMessage());
476         assertNull(result.getUser());
477     }
478 
479     public void testBadRequestUrl() throws Exception
480     {
481         CurrentApplication me = manager.getCurrentApplication();
482         EncryptedCertificate cert = me.encode(USER);
483         MockTrustedAppRequestV1 request = new MockTrustedAppRequestV1("/jira/secure/DeleteProject.jspa", cert);
484         request.addHeader("url-mismatch", "true");
485 
486         Authenticator.Result result = authenticator.authenticate(request, new MockResponse());
487 
488         assertNotNull(result);
489         assertEquals(Authenticator.Result.Status.ERROR, result.getStatus());
490         assertEquals("BAD_URL;\tRequest not allowed to access URL: {0};\t[\"/jira/secure/DeleteProject.jspa\"]", result.getMessage());
491         assertNull(result.getUser());
492     }
493 }