1 package com.atlassian.seraph.filter;
2
3 import com.atlassian.seraph.auth.Authenticator;
4 import com.atlassian.seraph.config.SecurityConfig;
5 import com.atlassian.seraph.config.SecurityConfigFactory;
6 import com.atlassian.seraph.util.LocalMockHttpServletRequest;
7 import com.mockobjects.dynamic.Mock;
8 import com.mockobjects.servlet.MockHttpServletResponse;
9 import com.mockobjects.servlet.MockHttpSession;
10 import com.sun.tools.internal.ws.processor.model.Response;
11 import junit.framework.TestCase;
12
13 import java.io.IOException;
14 import java.security.Principal;
15 import java.util.Collections;
16 import javax.servlet.FilterChain;
17 import javax.servlet.ServletException;
18 import javax.servlet.ServletRequest;
19 import javax.servlet.ServletResponse;
20 import javax.servlet.http.HttpServletRequest;
21 import javax.servlet.http.HttpServletResponse;
22 import javax.servlet.http.HttpSession;
23
24 import static com.mockobjects.dynamic.C.anyArgs;
25 import static java.util.Collections.singletonMap;
26
27 public class TestBaseLoginFilter extends TestCase
28 {
29 private static final Principal TEST_USER = new Principal()
30 {
31 public String getName()
32 {
33 return "Test User";
34 }
35 };
36 private SecurityConfig securityConfig;
37 private CountingBaseLoginFilter baseLoginFilter;
38
39 @Override
40 protected void setUp() throws Exception
41 {
42 baseLoginFilter = new CountingBaseLoginFilter();
43 }
44
45 public void testRedirectToOriginalDestinationNoURL() throws Exception
46 {
47
48 final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
49 final HttpSession session = new MockSession();
50 request.setSession(session);
51 request.setupGetContextPath("/jira");
52 request.setupAddParameter("os_destination", (String) null);
53
54
55 final Mock mockHttpServletResponse = new Mock(HttpServletResponse.class);
56
57
58 assertFalse(baseLoginFilter.redirectToOriginalDestination(request, (HttpServletResponse) mockHttpServletResponse.proxy()));
59
60 mockHttpServletResponse.verify();
61 }
62
63 public void testRedirectToOriginalDestinationViaSession() throws Exception
64 {
65 final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
66
67 request.setupAddParameter("os_destination", (String[]) null);
68
69 final HttpSession session = new MockSession();
70 session.setAttribute("seraph_originalurl", "/Stuff");
71 request.setSession(session);
72 request.setupGetContextPath("/jira");
73
74
75 final Mock mockHttpServletResponse = new Mock(HttpServletResponse.class);
76
77 mockHttpServletResponse.expect("sendRedirect", "/jira/Stuff");
78
79 assertTrue(baseLoginFilter.redirectToOriginalDestination(request, (HttpServletResponse) mockHttpServletResponse.proxy()));
80
81 mockHttpServletResponse.verify();
82 }
83
84 public void testRedirectToOriginalDestinationViaRequestParameter() throws Exception
85 {
86 final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
87
88 request.setSession(new MockSession());
89 request.setupScheme("http");
90 request.setupServerName("example.com");
91 request.setupPort(80);
92 request.setupGetContextPath("/jira");
93 request.setupAddParameter("os_destination", "http://example.com/jira/Stuff");
94
95
96 final Mock mockHttpServletResponse = new Mock(HttpServletResponse.class);
97
98 mockHttpServletResponse.expect("sendRedirect", "http://example.com/jira/Stuff");
99
100 assertTrue(baseLoginFilter.redirectToOriginalDestination(request, (HttpServletResponse) mockHttpServletResponse.proxy()));
101
102 mockHttpServletResponse.verify();
103 }
104
105 public void testRedirectToOriginalDestinationViaRequestButWhenSessionParameterIsAlsoPresent() throws Exception
106 {
107 final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
108
109 request.setupAddParameter("os_destination", "/Request");
110
111 final HttpSession session = new MockSession();
112 session.setAttribute("seraph_originalurl", "/Session");
113 request.setSession(session);
114 request.setupGetContextPath("/jira");
115
116
117 final Mock mockHttpServletResponse = new Mock(HttpServletResponse.class);
118
119 mockHttpServletResponse.expect("sendRedirect", "/jira/Request");
120
121 assertTrue(baseLoginFilter.redirectToOriginalDestination(request, (HttpServletResponse) mockHttpServletResponse.proxy()));
122
123 assertNull(session.getAttribute("seraph_originalurl"));
124 mockHttpServletResponse.verify();
125 }
126
127
128 public void testRedirectToOriginalDestinationViaBoth() throws Exception
129 {
130 final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
131
132 request.setSession(new MockSession());
133 request.setupScheme("http");
134 request.setupServerName("example.com");
135 request.setupGetContextPath("/jira");
136 request.setupAddParameter("os_destination", "http://evil.com/jira/Stuff");
137
138
139 final Mock mockHttpServletResponse = new Mock(HttpServletResponse.class);
140
141 mockHttpServletResponse.expect("sendRedirect", "/jira/");
142
143 assertTrue(baseLoginFilter.redirectToOriginalDestination(request, (HttpServletResponse) mockHttpServletResponse.proxy()));
144
145 mockHttpServletResponse.verify();
146 }
147
148 public void testSecurityWrappingAndLoginCalled() throws IOException, ServletException
149 {
150 securityConfig = new MockSecurityConfig(null, null, null, Collections.EMPTY_LIST);
151
152 final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
153 request.setupGetAttribute(null);
154 request.setupGetParameterMap(Collections.EMPTY_MAP);
155
156 final MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();
157
158 CountingFilterChain filterChain = new CountingFilterChain();
159
160 baseLoginFilter.doFilter(request, mockHttpServletResponse, filterChain);
161 assertEquals(1, baseLoginFilter.getLoginCount());
162 assertEquals("We must not call the FilterChain more than once", 1, filterChain.getFilterCount());
163 }
164
165 public void testAlreadyFilterNeverCallsLogin() throws IOException, ServletException
166 {
167 final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
168 request.setAttribute(BaseLoginFilter.ALREADY_FILTERED, true);
169
170
171 final MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();
172 CountingFilterChain filterChain = new CountingFilterChain();
173
174 baseLoginFilter.doFilter(request, mockHttpServletResponse, filterChain);
175 assertEquals(0, baseLoginFilter.getLoginCount());
176 assertEquals("We must not call the FilterChain more than once", 1, filterChain.getFilterCount());
177 }
178
179 public void testRedirectIfUserIsAlreadyLoggedIn() throws IOException, ServletException
180 {
181 MockHttpSession session = new MockHttpSession();
182 session.setupGetAttribute("seraph_originalurl", null);
183
184 final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
185 request.setupScheme("http");
186 request.setupServerName("example.com");
187 request.setupGetContextPath("/jira");
188 request.setupGetParameterMap(singletonMap("os_destination", "http://example.com/jira/Stuff"));
189 request.setupAddParameter("os_destination", "http://example.com/jira/Stuff");
190 request.setSession(session);
191
192 final MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();
193 mockHttpServletResponse.setExpectedRedirect("/jira/");
194
195 final Mock mockAuthenticator = new Mock(Authenticator.class);
196 mockAuthenticator.expectAndReturn("getUser", anyArgs(2), TEST_USER);
197
198 securityConfig =
199 new MockSecurityConfig(null, (Authenticator) mockAuthenticator.proxy(), null, Collections.EMPTY_LIST);
200 SecurityConfigFactory.setSecurityConfig(securityConfig);
201
202 CountingFilterChain filterChain = new CountingFilterChain();
203
204 baseLoginFilter.doFilter(request, mockHttpServletResponse, filterChain);
205
206 assertEquals(1, baseLoginFilter.getLoginCount());
207 mockHttpServletResponse.verify();
208 assertEquals("We must not call the FilterChain when redirecting", 0, filterChain.getFilterCount());
209 }
210
211 class CountingBaseLoginFilter extends BaseLoginFilter
212 {
213 private int loginCount = 0;
214 private final String loginStatus;
215
216 public CountingBaseLoginFilter()
217 {
218 this(LOGIN_NOATTEMPT);
219 }
220
221 public CountingBaseLoginFilter(final String loginStatus)
222 {
223 this.loginStatus = loginStatus;
224 }
225
226
227
228
229
230
231
232
233
234
235 @Override
236 public String login(final HttpServletRequest request, final HttpServletResponse response)
237 {
238 loginCount++;
239 return loginStatus;
240
241 }
242
243 @Override
244 protected SecurityConfig getSecurityConfig()
245 {
246 if (securityConfig == null)
247 {
248 securityConfig = new MockSecurityConfig();
249 }
250 return securityConfig;
251 }
252
253 public int getLoginCount()
254 {
255 return loginCount;
256 }
257 }
258
259 static class CountingFilterChain implements FilterChain
260 {
261 private int filterCount = 0;
262
263 public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse)
264 throws IOException, ServletException
265 {
266
267
268 assertTrue(servletRequest instanceof BaseLoginFilter.SecurityHttpRequestWrapper);
269 filterCount++;
270 }
271
272 public int getFilterCount()
273 {
274 return filterCount;
275 }
276 }
277 }