1   package com.atlassian.seraph.filter;
2   
3   import com.atlassian.seraph.auth.AuthType;
4   import com.atlassian.seraph.auth.AuthenticationContext;
5   import com.atlassian.seraph.auth.Authenticator;
6   import com.atlassian.seraph.config.SecurityConfig;
7   import com.atlassian.seraph.controller.SecurityController;
8   import com.atlassian.seraph.util.RedirectUtils;
9   import junit.framework.TestCase;
10  import org.mockito.Matchers;
11  import org.mockito.Mock;
12  import org.mockito.Mockito;
13  import org.mockito.MockitoAnnotations;
14  
15  import java.security.Principal;
16  import javax.servlet.FilterChain;
17  import javax.servlet.http.Cookie;
18  import javax.servlet.http.HttpServletRequest;
19  import javax.servlet.http.HttpServletResponse;
20  import javax.servlet.http.HttpSession;
21  
22  import static org.mockito.Mockito.*;
23  
24  public class TestSecurityFilter extends TestCase
25  {
26      @Mock private HttpServletRequest request;
27      @Mock private HttpServletResponse response;
28      @Mock private FilterChain filterChain;
29      @Mock private SecurityConfig securityConfig;
30      @Mock private SecurityController securityController;
31      @Mock private Authenticator authenticator;
32      @Mock private AuthenticationContext authenticationContext;
33      private static final String OS_AUTH_TYPE = "os_authType";
34  
35      @Override
36      protected void setUp() throws Exception
37      {
38          MockitoAnnotations.initMocks(this);
39  
40          when(request.getAttribute(BaseLoginFilter.ALREADY_FILTERED)).thenReturn("not null"); // the actual value doesn't matter so long as it is not-null
41          when(securityController.isSecurityEnabled()).thenReturn(true);
42  
43          when(securityConfig.getAuthType()).thenReturn(OS_AUTH_TYPE);
44          when(securityConfig.getController()).thenReturn(securityController);
45          when(securityConfig.getAuthenticator()).thenReturn(authenticator);
46          when(securityConfig.getAuthenticationContext()).thenReturn(authenticationContext);
47  
48          super.setUp();
49      }
50  
51      /**
52       * When authType=basic and authentication fails it should abort. We are mocking out the part that
53       * would normally send the 401 error so we can't really test that, thanks to Seraph's terrible internal
54       * structure.
55       */
56      public void testAuthType_basic() throws Exception {
57          final String authType = "basic";
58  
59          when(request.getServletPath()).thenReturn("/something");
60          when(request.getParameter(OS_AUTH_TYPE)).thenReturn(authType);
61          when(request.getQueryString()).thenReturn(String.format("%s=%s", OS_AUTH_TYPE, authType));
62          when(request.getHeader("Authorization")).thenReturn("BASIC abcdef");
63          when(authenticator.getUser(request, response)).thenReturn(null);
64  
65          final SecurityFilter filter = new TestableSecurityFilter();
66  
67          filter.doFilter(request, response, filterChain);
68  
69          // verify that nothing else happened.
70          verify(filterChain, never()).doFilter(request, response);
71          verify(authenticationContext, never()).setUser(Matchers.<Principal>any());
72          verify(response, never()).sendRedirect(Matchers.<String>any());        
73      }
74  
75      public void testAuthType_cookie() throws Exception {
76          final String authType = "cookie";
77  
78          when(request.getServletPath()).thenReturn("/something");
79          when(request.getParameter(OS_AUTH_TYPE)).thenReturn(authType);
80          when(request.getQueryString()).thenReturn(String.format("%s=%s", OS_AUTH_TYPE, authType));
81          when(authenticator.getUser(request, response)).thenReturn(null);
82  
83          final SecurityFilter filter = new TestableSecurityFilter();
84  
85          filter.doFilter(request, response, filterChain);
86  
87          // check that we are getting a 401 with message.
88          verify(response).sendError(401, "os_authType was 'cookie' but no valid cookie was sent.");
89  
90          // verify that nothing else happened.
91          verify(filterChain, never()).doFilter(request, response);
92          verify(authenticationContext, never()).setUser(Matchers.<Principal>any());
93          verify(response, never()).sendRedirect(Matchers.<String>any());
94      }
95  
96      // Just like in testAuthType_basic we can't test for the 401....
97      public void testAuthType_any_basic() throws Exception
98      {
99          final String authType = "any";
100 
101         when(request.getServletPath()).thenReturn("/something");
102         when(request.getParameter(OS_AUTH_TYPE)).thenReturn(authType);
103         when(request.getQueryString()).thenReturn(String.format("%s=%s", OS_AUTH_TYPE, authType));
104 
105         // we sent along an authorization header triggering basic auth
106         when(request.getHeader("Authorization")).thenReturn("BASIC abcdef");
107         when(authenticator.getUser(request, response)).thenReturn(null);
108 
109         final SecurityFilter filter = new TestableSecurityFilter();
110 
111         filter.doFilter(request, response, filterChain);
112 
113         // verify that nothing else happened.
114         verify(filterChain, never()).doFilter(request, response);
115         verify(authenticationContext, never()).setUser(Matchers.<Principal>any());
116         verify(response, never()).sendRedirect(Matchers.<String>any());
117     }
118 
119     // test that sending a bad cookie doesn't log us in
120     public void testAuthType_any_cookie() throws Exception
121     {
122         final String authType = "any";
123         final Cookie[] cookies = { new Cookie("JSESSIONID", "value") };
124 
125         when(request.getSession(false)).thenReturn(null);
126         when(request.getServletPath()).thenReturn("/something");
127         when(request.getParameter(OS_AUTH_TYPE)).thenReturn(authType);
128         when(request.getQueryString()).thenReturn(String.format("%s=%s", OS_AUTH_TYPE, authType));
129 
130         // we sent along a cookie
131         when(request.getCookies()).thenReturn(cookies);
132 
133         when(authenticator.getUser(request, response)).thenReturn(null);
134 
135         final SecurityFilter filter = new TestableSecurityFilter();
136 
137         filter.doFilter(request, response, filterChain);
138 
139         // verify that nothing else happened.
140         verify(filterChain, never()).doFilter(request, response);
141         verify(authenticationContext, never()).setUser(Matchers.<Principal>any());
142         verify(response, never()).sendRedirect(Matchers.<String>any());
143     }
144 
145     // test that we are anonymous if we don't send a cookie at all
146     public void testAuthType_any_anonymous() throws Exception
147     {
148         final String authType = "any";
149 
150         when(request.getServletPath()).thenReturn("/something");
151         when(request.getParameter(OS_AUTH_TYPE)).thenReturn(authType);
152         when(request.getQueryString()).thenReturn(String.format("%s=%s", OS_AUTH_TYPE, authType));
153 
154         // We don't have either a cookie or a basic auth header so we should go through as
155         // anonymous
156         when(authenticator.getUser(request, response)).thenReturn(null);
157 
158         final SecurityFilter filter = new TestableSecurityFilter();
159 
160         filter.doFilter(request, response, filterChain);
161 
162         // verify that we are actually anonymous and the rest of the filter chain got invoked
163         verify(filterChain).doFilter(request, response);
164         verify(authenticationContext).setUser(null);
165 
166         verify(response, never()).sendRedirect(Matchers.<String>any());
167     }
168 
169     // If the request has an os_authTypeDefault parameter (presumably set by a filter that has run
170     // before us in production) then that should be used as a default.
171     public void testDefaults_Any() throws Exception
172     {
173         final Cookie[] cookies = { new Cookie("JSESSIONID", "value") };
174 
175         when(request.getAttribute(AuthType.DEFAULT_ATTRIBUTE)).thenReturn("any");
176         when(request.getServletPath()).thenReturn("/rest/something");
177 
178         // we sent along a cookie
179         when(request.getCookies()).thenReturn(cookies);
180 
181         when(authenticator.getUser(request, response)).thenReturn(null);
182 
183         final SecurityFilter filter = new TestableSecurityFilter();
184 
185         filter.doFilter(request, response, filterChain);
186 
187         // verify that nothing else happened. (since we sent an invalid cookie and are under /rest/)
188         verify(filterChain, never()).doFilter(request, response);
189         verify(authenticationContext, never()).setUser(Matchers.<Principal>any());
190         verify(response, never()).sendRedirect(Matchers.<String>any());
191     }
192 
193     // Ensure that if we get back an authType of NONE that we handle is properly
194     public void testAuthType_none() throws Exception
195     {
196         when(request.getServletPath()).thenReturn("/something");
197         // We don't have either a cookie or a basic auth header so we should go through as
198         // anonymous
199         when(authenticator.getUser(request, response)).thenReturn(null);
200 
201         final SecurityFilter filter = new TestableSecurityFilter();
202 
203         filter.doFilter(request, response, filterChain);
204 
205         // verify that we are actually anonymous and the rest of the filter chain got invoked
206         verify(filterChain).doFilter(request, response);
207         verify(authenticationContext).setUser(null);
208 
209         verify(response, never()).sendRedirect(Matchers.<String>any());
210     }
211 
212     class TestableSecurityFilter extends SecurityFilter {
213         @Override
214         protected SecurityConfig getSecurityConfig()
215         {
216             return securityConfig;
217         }
218     }
219 }