1   package com.atlassian.seraph.filter;
2   
3   import com.atlassian.seraph.auth.Authenticator;
4   import com.atlassian.seraph.auth.AuthenticatorException;
5   import com.atlassian.seraph.config.SecurityConfig;
6   import com.atlassian.seraph.elevatedsecurity.CountingElevatedSecurityGuard;
7   import com.atlassian.seraph.interceptor.LoginInterceptor;
8   import com.atlassian.seraph.util.LocalMockHttpServletRequest;
9   import com.mockobjects.dynamic.C;
10  import com.mockobjects.dynamic.Mock;
11  import junit.framework.TestCase;
12  
13  import java.security.Principal;
14  import java.util.ArrayList;
15  import java.util.Collections;
16  import java.util.List;
17  import java.util.Map;
18  import javax.servlet.http.HttpServletRequest;
19  import javax.servlet.http.HttpServletResponse;
20  import javax.servlet.http.HttpSession;
21  
22  /**
23   * Tests for {@link com.atlassian.seraph.filter.PasswordBasedLoginFilter} 
24   */
25  public class TestPasswordBasedLoginFilter extends TestCase
26  {
27      public void testNullUserNameFails()
28      {
29          final MockSecurityConfig securityConfig = new MockSecurityConfig(Collections.EMPTY_LIST);
30          final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter(null, "password", securityConfig);
31  
32          final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
33          assertEquals(PasswordBasedLoginFilter.LOGIN_NOATTEMPT, actualStatus);
34      }
35  
36  
37      public void testNullPasswordFails()
38      {
39          final MockSecurityConfig securityConfig = new MockSecurityConfig(Collections.EMPTY_LIST);
40          final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", null, securityConfig);
41  
42          final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
43          assertEquals(PasswordBasedLoginFilter.LOGIN_NOATTEMPT, actualStatus);
44      }
45  
46      public void testNullUserPairFails()
47      {
48          final PasswordBasedLoginFilter passwordBasedLoginFilter = new PasswordBasedLoginFilter()
49          {
50              PasswordBasedLoginFilter.UserPasswordPair extractUserPasswordPair(final HttpServletRequest request)
51              {
52                  return null;
53              }
54          };
55  
56          final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
57          assertEquals(PasswordBasedLoginFilter.LOGIN_NOATTEMPT, actualStatus);
58      }
59  
60      public void testElevatedSecurityGuard_FailedCheck()
61      {
62          final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(false, "userName");
63  
64          final MockSecurityConfig securityConfig = new MockSecurityConfig(null, securityGuard, null, null, Collections.EMPTY_LIST);
65          final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
66  
67  
68          final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
69          assertEquals(PasswordBasedLoginFilter.LOGIN_FAILED, actualStatus);
70          assertEquals(1, securityGuard.getFailedCount());
71          assertEquals(0, securityGuard.getSuccessCount());
72      }
73  
74      public void testElevatedSecurityGuard_PassedCheck_ButFailedAuthenticator()
75      {
76          final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
77  
78          final AssertingAuthenticator authenticator = new AssertingAuthenticator(false, "userName", "password");
79  
80          final MockSecurityConfig securityConfig = new MockSecurityConfig(null, securityGuard, authenticator, null, Collections.EMPTY_LIST);
81          final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
82  
83  
84          final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
85          assertEquals(PasswordBasedLoginFilter.LOGIN_FAILED, actualStatus);
86          assertEquals(1, securityGuard.getFailedCount());
87          assertEquals(0, securityGuard.getSuccessCount());
88      }
89  
90      public void testElevatedSecurityGuard_PassedCheck_ButAuthenticatorThrewException()
91      {
92          final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
93  
94          @SuppressWarnings ({ "ThrowableInstanceNeverThrown" })
95          final AssertingAuthenticator authenticator = new AssertingAuthenticator(false, "userName", "password", new AuthenticatorException());
96  
97          final MockSecurityConfig securityConfig = new MockSecurityConfig(null, securityGuard, authenticator, null, Collections.EMPTY_LIST);
98          final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
99  
100 
101         final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
102         assertEquals(PasswordBasedLoginFilter.LOGIN_FAILED, actualStatus);
103 
104         // we dont run the security guard on exception!  Its not really a fail against the user
105         assertEquals(0, securityGuard.getFailedCount());
106         assertEquals(0, securityGuard.getSuccessCount());
107     }
108 
109     public void testElevatedSecurityGuard_PassedCheck_AndPassedAuthenticator()
110     {
111         final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
112 
113         final AssertingAuthenticator authenticator = new AssertingAuthenticator(true, "userName", "password");
114         final MockSecurityConfig securityConfig = new MockSecurityConfig(null, securityGuard, authenticator, null, Collections.EMPTY_LIST);
115         final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
116 
117 
118         final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
119         assertEquals(PasswordBasedLoginFilter.LOGIN_SUCCESS, actualStatus);
120         assertEquals(0, securityGuard.getFailedCount());
121         assertEquals(1, securityGuard.getSuccessCount());
122     }
123 
124 
125     public void testInterceptorsAreCalled()
126     {
127         CountingLoginInterceptor loginInterceptor = new CountingLoginInterceptor();
128         List<CountingLoginInterceptor> interceptors = new ArrayList<CountingLoginInterceptor>();
129         interceptors.add(loginInterceptor);
130 
131         final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
132 
133         final AssertingAuthenticator authenticator = new AssertingAuthenticator(true, "userName", "password", null);
134 
135         final MockSecurityConfig securityConfig = new MockSecurityConfig(null, securityGuard, authenticator, null, interceptors);
136         final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
137 
138 
139         passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
140         assertEquals(1, loginInterceptor.getBeforeLogin());
141         assertEquals(1, loginInterceptor.getAfterLogin());
142 
143     }
144 
145     class TestedPasswordBasedLoginFilter extends PasswordBasedLoginFilter
146     {
147         private final String userName;
148         private final String password;
149         private final MockSecurityConfig mockSecurityConfig;
150 
151 
152         TestedPasswordBasedLoginFilter(final String userName, final String password, final MockSecurityConfig mockSecurityConfig)
153         {
154             this.userName = userName;
155             this.password = password;
156             this.mockSecurityConfig = mockSecurityConfig;
157         }
158 
159         @Override
160         PasswordBasedLoginFilter.UserPasswordPair extractUserPasswordPair(final HttpServletRequest request)
161         {
162             return new PasswordBasedLoginFilter.UserPasswordPair(userName, password, true);
163         }
164 
165         @Override
166         protected SecurityConfig getSecurityConfig()
167         {
168             return mockSecurityConfig;
169         }
170     }
171 
172     class AssertingAuthenticator implements Authenticator
173     {
174         private final boolean loginOK;
175         private final String expectedUserName;
176         private final String expectedPassword;
177         private final AuthenticatorException authenticatorException;
178 
179         public AssertingAuthenticator(final boolean loginOK, final String expectedUserName, final String expectedPassword)
180         {
181             this(loginOK, expectedUserName, expectedPassword, null);
182         }
183 
184         public AssertingAuthenticator(final boolean loginOK, final String expectedUserName, final String expectedPassword, final AuthenticatorException authenticatorException)
185         {
186             this.loginOK = loginOK;
187             this.expectedUserName = expectedUserName;
188             this.expectedPassword = expectedPassword;
189             this.authenticatorException = authenticatorException;
190         }
191 
192         public boolean login(final HttpServletRequest request, final HttpServletResponse response, final String username, final String password)
193                 throws AuthenticatorException
194         {
195             return loginImpl(username, password);
196         }
197 
198         public boolean login(final HttpServletRequest request, final HttpServletResponse response, final String username, final String password, final boolean storeCookie)
199                 throws AuthenticatorException
200         {
201             return loginImpl(username, password);
202         }
203 
204         private boolean loginImpl(final String username, final String password) throws AuthenticatorException
205         {
206             assertEquals(expectedUserName, username);
207             assertEquals(expectedPassword, password);
208             if (authenticatorException != null)
209             {
210                 throw authenticatorException;
211             }
212             return loginOK;
213         }
214 
215         public String getRemoteUser(final HttpServletRequest request)
216         {
217             return null;
218         }
219 
220         public void destroy()
221         {
222         }
223 
224         public Principal getUser(final HttpServletRequest request)
225         {
226             return null;
227         }
228 
229         public Principal getUser(final HttpServletRequest request, final HttpServletResponse response)
230         {
231             return null;
232         }
233 
234         public boolean isUserInRole(final HttpServletRequest request, final String role)
235         {
236             return false;
237         }
238 
239         public boolean logout(final HttpServletRequest request, final HttpServletResponse response)
240                 throws AuthenticatorException
241         {
242             return false;
243         }
244 
245         public void init(final Map<String, String> params, final SecurityConfig config)
246         {
247         }
248     }
249 
250     class CountingLoginInterceptor implements LoginInterceptor
251     {
252         private int beforeLogin;
253         private int afterLogin;
254 
255         public void beforeLogin(final HttpServletRequest request, final HttpServletResponse response, final String username, final String password, final boolean cookieLogin)
256         {
257             beforeLogin++;
258         }
259 
260         public void afterLogin(final HttpServletRequest request, final HttpServletResponse response, final String username, final String password, final boolean cookieLogin, final String loginStatus)
261         {
262             afterLogin++;
263         }
264 
265         public void destroy()
266         {
267         }
268 
269         public void init(final Map<String, String> params, final SecurityConfig config)
270         {
271         }
272 
273         public int getBeforeLogin()
274         {
275             return beforeLogin;
276         }
277 
278         public int getAfterLogin()
279         {
280             return afterLogin;
281         }
282     }
283 
284     private HttpServletResponse makeHttpResponse()
285     {
286         final Mock mockHttpServletResponse = new Mock(HttpServletResponse.class);
287         mockHttpServletResponse.expect("addHeader", C.ANY_ARGS);
288         return (HttpServletResponse) mockHttpServletResponse.proxy();
289     }
290 
291     private LocalMockHttpServletRequest makeHttpRequest()
292     {
293         final LocalMockHttpServletRequest httpServletRequest = new LocalMockHttpServletRequest();
294         httpServletRequest.setupGetAttribute(null);
295 
296         final HttpSession session = new MockSession();
297         httpServletRequest.setSession(session);
298         return httpServletRequest;
299     }
300 
301 
302 }