1   package com.atlassian.seraph.util;
2   
3   import com.atlassian.seraph.RequestParameterConstants;
4   import com.atlassian.seraph.config.SecurityConfig;
5   import com.atlassian.seraph.config.SecurityConfigFactory;
6   import com.mockobjects.dynamic.Mock;
7   import com.mockobjects.servlet.MockHttpServletRequest;
8   import junit.framework.AssertionFailedError;
9   import junit.framework.TestCase;
10  
11  import javax.servlet.ServletException;
12  import java.io.IOException;
13  import java.io.UnsupportedEncodingException;
14  import java.net.URLEncoder;
15  
16  public class TestRedirectUtils extends TestCase
17  {
18      private LocalMockHttpServletRequest mockRequest;
19      private Mock mockSecurityConfig;
20  
21      protected void setUp() throws Exception
22      {
23          super.setUp();
24  
25          // Create a project to redirect too
26          mockRequest = new LocalMockHttpServletRequest();
27          mockRequest.setupGetContextPath("/ctx");
28  
29          mockSecurityConfig = new Mock(SecurityConfig.class);
30          SecurityConfigFactory.setSecurityConfig((SecurityConfig) mockSecurityConfig.proxy());
31      }
32  
33      public void testRelativeLoginURLHasCorrectOSDestinationSet() throws IOException, ServletException
34      {
35          // our login.url parameter in seraph-config.xml.
36          mockSecurityConfig.expectAndReturn("getLoginURL", "/login.jsp?os_destination=${originalurl}");
37          mockRequest.setupGetServletPath("/browse/JRA-123");
38          mockRequest.setupPathInfo(null);
39          mockRequest.setupQueryString(null);
40          mockRequest.setupGetAttribute(null);
41          mockRequest.setupAddParameter(RequestParameterConstants.OS_DESTINATION, (String) null);
42          assertEquals("/ctx/login.jsp?os_destination=%2Fbrowse%2FJRA-123", RedirectUtils.getLoginUrl(mockRequest));
43      }
44  
45      public void testAbsoluteLoginURLHasCorrectOSDestinationSet() throws IOException, ServletException
46      {
47          // our login.url parameter in seraph-config.xml.
48          mockSecurityConfig.expectAndReturn("getLoginURL", "http://sso.somecompany.com?target=${originalurl}");
49          mockRequest.setupGetAttribute(null);
50          mockRequest.setupQueryString(null);
51  
52          final String requestURL = "http://localhost:8080/myapp/browse/JRA-123";
53          mockRequest.setupGetRequestURL(requestURL);
54          mockRequest.setupAddParameter(RequestParameterConstants.OS_DESTINATION, (String) null);
55          assertEquals("http://sso.somecompany.com?target=" + URLEncoder.encode(requestURL, "UTF-8"), RedirectUtils.getLoginUrl(mockRequest));
56      }
57  
58      public void testRelativeLinkLoginURLHasCorrectOSDestinationSet() throws IOException, ServletException
59      {
60          // our login.url parameter in seraph-config.xml.
61          mockSecurityConfig.expectAndReturn("getLinkLoginURL", "/login.jsp?os_destination=${originalurl}");
62          mockRequest.setupGetServletPath("/browse/JRA-123");
63          mockRequest.setupPathInfo(null);
64          mockRequest.setupQueryString(null);
65          mockRequest.setupGetAttribute(null);
66          mockRequest.setupAddParameter(RequestParameterConstants.OS_DESTINATION, (String) null);
67          assertEquals("/ctx/login.jsp?os_destination=%2Fbrowse%2FJRA-123", RedirectUtils.getLinkLoginURL(mockRequest));
68      }
69  
70      public void testAbsoluteLinkLoginURLHasCorrectOSDestinationSet() throws IOException, ServletException
71      {
72          // our login.url parameter in seraph-config.xml.
73          mockSecurityConfig.expectAndReturn("getLinkLoginURL", "http://sso.somecompany.com?target=${originalurl}");
74          mockRequest.setupGetAttribute(null);
75          mockRequest.setupQueryString(null);
76  
77          final String requestURL = "http://localhost:8080/myapp/browse/JRA-123";
78          mockRequest.setupGetRequestURL(requestURL);
79          mockRequest.setupAddParameter(RequestParameterConstants.OS_DESTINATION, (String) null);
80          assertEquals("http://sso.somecompany.com?target=" + URLEncoder.encode(requestURL, "UTF-8"), RedirectUtils.getLinkLoginURL(mockRequest));
81      }
82  
83      public void testOsDestinationKeepsOriginalValueWithLinkLoginURL() throws UnsupportedEncodingException
84      {
85          final String osDestParameter = "I should not be ignored";
86          // our login.url parameter in seraph-config.xml.
87          mockSecurityConfig.expectAndReturn("getLinkLoginURL", "/login.jsp?os_destination=${originalurl}");
88          mockRequest.setupGetServletPath("/browse/JRA-123");
89          mockRequest.setupPathInfo(null);
90          mockRequest.setupQueryString(null);
91          mockRequest.setupGetAttribute(null);
92          mockRequest.setupAddParameter(RequestParameterConstants.OS_DESTINATION, osDestParameter);
93          assertEquals("/ctx/login.jsp?os_destination=" + URLEncoder.encode(osDestParameter, "UTF-8"), RedirectUtils.getLinkLoginURL(mockRequest));
94      }
95  
96      public void testOsDestinationKeepsOriginalValueWithLoginURL() throws UnsupportedEncodingException
97      {
98          final String osDestParameter = "I should not be ignored";
99          // our login.url parameter in seraph-config.xml.
100         mockSecurityConfig.expectAndReturn("getLoginURL", "http://sso.somecompany.com?target=${originalurl}");
101 
102         final String requestURL = "http://localhost:8080/myapp/browse/JRA-123";
103         mockRequest.setupGetRequestURL(requestURL);
104         mockRequest.setupQueryString(null);
105         mockRequest.setupGetAttribute(null);
106         mockRequest.setupAddParameter(RequestParameterConstants.OS_DESTINATION, osDestParameter);
107         assertEquals("http://sso.somecompany.com?target=" + URLEncoder.encode(osDestParameter, "UTF-8"), RedirectUtils.getLoginUrl(mockRequest));
108     }
109 
110     public void testAppendPathToContext()
111     {
112         final String path = "homepage.action";
113         final String context = "/confluence";
114         assertEquals("/confluence/homepage.action", RedirectUtils.appendPathToContext(context, path));
115         assertEquals("/confluence/homepage.action", RedirectUtils.appendPathToContext(context + "/", path));
116         assertEquals("/confluence/homepage.action", RedirectUtils.appendPathToContext(context, "/" + path));
117         assertEquals("/confluence/homepage.action", RedirectUtils.appendPathToContext(context + "/", "/" + path));
118 
119         // edge cases - nulls, empty strings, etc.
120         assertEquals("/homepage.action", RedirectUtils.appendPathToContext("", path));
121         assertEquals("/", RedirectUtils.appendPathToContext("", ""));
122         assertEquals("/confluence/", RedirectUtils.appendPathToContext(context, ""));
123         assertEquals("/confluence", RedirectUtils.appendPathToContext(context, null));
124         assertEquals("/homepage.action", RedirectUtils.appendPathToContext(null, path));
125         assertEquals("", RedirectUtils.appendPathToContext(null, null));
126     }
127 
128     public void testHasHttpBasicAuthenticationRequestHeader()
129     {
130         final MockHttpServletRequest request = new MockHttpServletRequest();
131         try
132         {
133             RedirectUtils.hasHttpBasicAuthenticationRequestHeader(request);
134             fail();
135         }
136         catch (final AssertionFailedError e)
137         {
138             // expected, stupid mock that makes stupid assumptions on how it is going to be used!
139         }
140 
141         request.setupAddHeader("Authorization", "");
142         assertFalse(RedirectUtils.hasHttpBasicAuthenticationRequestHeader(request));
143 
144         request.setupAddHeader("Authorization", "Basic" + " some other value");
145         assertTrue(RedirectUtils.hasHttpBasicAuthenticationRequestHeader(request));
146     }
147 
148     public void testHasBasicAuthenticationRequestQueryParameterNullFalse()
149     {
150         assertHasHttpBasicAuthenticationRequestQueryParameter(false, null, "testAuthParamName");
151     }
152 
153     public void testHasBasicAuthenticationRequestQueryParameterDoesNot()
154     {
155         assertHasHttpBasicAuthenticationRequestQueryParameter(false, "someparam1=somevalue1&someparam2=somevalue2", "testAuthParamName");
156     }
157 
158     public void testHasBasicAuthenticationRequestQueryParameterDoesInMiddle()
159     {
160         assertHasHttpBasicAuthenticationRequestQueryParameter(true, "someparam1=somevalue1&testAuthParamName=basic&someparam2=somevalue2", "testAuthParamName");
161     }
162 
163     public void testHasNotBasicAuthenticationRequestQueryParameterInMiddleTitleCase()
164     {
165         assertHasHttpBasicAuthenticationRequestQueryParameter(false, "someparam1=somevalue1&testAuthParamName=Basic&someparam2=somevalue2", "testAuthParamName");
166     }
167 
168     public void testHasNotBasicAuthenticationRequestQueryParameterInMiddleUpperCase()
169     {
170         assertHasHttpBasicAuthenticationRequestQueryParameter(false, "someparam1=somevalue1&testAuthParamName=BASIC&someparam2=somevalue2", "testAuthParamName");
171     }
172 
173     public void testHasBasicAuthenticationRequestQueryParameterAtBeginning()
174     {
175         assertHasHttpBasicAuthenticationRequestQueryParameter(true, "testAuthParamName=basic&someparam1=somevalue1&someparam2=somevalue2", "testAuthParamName");
176     }
177 
178     public void testHasNotBasicAuthenticationRequestQueryParameterAtBeginningMixedCase()
179     {
180         assertHasHttpBasicAuthenticationRequestQueryParameter(false, "testAuthParamName=Basic&someparam1=somevalue1&someparam2=somevalue2", "testAuthParamName");
181     }
182 
183     public void testHasNotBasicAuthenticationRequestQueryParameterAtBeginningUpperCase()
184     {
185         assertHasHttpBasicAuthenticationRequestQueryParameter(false, "testAuthParamName=BASIC&someparam1=somevalue1&someparam2=somevalue2", "testAuthParamName");
186     }
187 
188     public void testHasBasicAuthenticationRequestQueryParameterAtEnd()
189     {
190         assertHasHttpBasicAuthenticationRequestQueryParameter(true, "someparam1=somevalue1&someparam2=somevalue2&testAuthParamName=basic", "testAuthParamName");
191     }
192 
193     public void testHasNotBasicAuthenticationRequestQueryParameterAtEndTitleCase()
194     {
195         assertHasHttpBasicAuthenticationRequestQueryParameter(false, "someparam1=somevalue1&someparam2=somevalue2&testAuthParamName=Basic", "testAuthParamName");
196     }
197 
198     public void testHasNotBasicAuthenticationRequestQueryParameterAtEndUpperCase()
199     {
200         assertHasHttpBasicAuthenticationRequestQueryParameter(false, "someparam1=somevalue1&someparam2=somevalue2&testAuthParamName=BASIC", "testAuthParamName");
201     }
202 
203     public void testHasNotBasicAuthenticationRequestQueryParameterPlusQueryPath()
204     {
205         assertHasHttpBasicAuthenticationRequestQueryParameter(false, "/testAuthParamName=basic?someparam1=somevalue1&someparam2=somevalue2&testAuthParamName=BASIC", "testAuthParamName");
206     }
207 
208     public void testHasNotBasicAuthenticationRequestQueryParameterPlusQueryPathAndQueryHackedUrl()
209     {
210         assertHasHttpBasicAuthenticationRequestQueryParameter(false, "/someUrl&testAuthParamName=basic?someparam1=somevalue1&someparam2=somevalue2&testAuthParamName=BASIC", "testAuthParamName");
211     }
212 
213     private void assertHasHttpBasicAuthenticationRequestQueryParameter(final boolean does, final String query, final String parameterName)
214     {
215         final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
216         request.setupQueryString(query);
217 
218         assertEquals(query, does, RedirectUtils.hasHttpBasicAuthenticationRequestParameter(request, parameterName));
219     }
220 
221     //
222     // Following tests have been copied from commons-lang 2.4
223     //
224 
225     public void testContainsString()
226     {
227         assertEquals(false, RedirectUtils.contains(null, null));
228         assertEquals(false, RedirectUtils.contains(null, ""));
229         assertEquals(false, RedirectUtils.contains(null, "a"));
230         assertEquals(false, RedirectUtils.contains("", null));
231         assertEquals(true, RedirectUtils.contains("", ""));
232         assertEquals(false, RedirectUtils.contains("", "a"));
233         assertEquals(true, RedirectUtils.contains("abc", "a"));
234         assertEquals(true, RedirectUtils.contains("abc", "b"));
235         assertEquals(true, RedirectUtils.contains("abc", "c"));
236         assertEquals(true, RedirectUtils.contains("abc", "abc"));
237         assertEquals(false, RedirectUtils.contains("abc", "z"));
238     }
239 
240     public void testContainsIgnoreCase_StringString()
241     {
242         assertFalse(RedirectUtils.containsIgnoreCase(null, null));
243 
244         // Null tests
245         assertFalse(RedirectUtils.containsIgnoreCase(null, ""));
246         assertFalse(RedirectUtils.containsIgnoreCase(null, "a"));
247         assertFalse(RedirectUtils.containsIgnoreCase(null, "abc"));
248 
249         assertFalse(RedirectUtils.containsIgnoreCase("", null));
250         assertFalse(RedirectUtils.containsIgnoreCase("a", null));
251         assertFalse(RedirectUtils.containsIgnoreCase("abc", null));
252 
253         // Match len = 0
254         assertTrue(RedirectUtils.containsIgnoreCase("", ""));
255         assertTrue(RedirectUtils.containsIgnoreCase("a", ""));
256         assertTrue(RedirectUtils.containsIgnoreCase("abc", ""));
257 
258         // Match len = 1
259         assertFalse(RedirectUtils.containsIgnoreCase("", "a"));
260         assertTrue(RedirectUtils.containsIgnoreCase("a", "a"));
261         assertTrue(RedirectUtils.containsIgnoreCase("abc", "a"));
262         assertFalse(RedirectUtils.containsIgnoreCase("", "A"));
263         assertTrue(RedirectUtils.containsIgnoreCase("a", "A"));
264         assertTrue(RedirectUtils.containsIgnoreCase("abc", "A"));
265 
266         // Match len > 1
267         assertFalse(RedirectUtils.containsIgnoreCase("", "abc"));
268         assertFalse(RedirectUtils.containsIgnoreCase("a", "abc"));
269         assertTrue(RedirectUtils.containsIgnoreCase("xabcz", "abc"));
270         assertFalse(RedirectUtils.containsIgnoreCase("", "ABC"));
271         assertFalse(RedirectUtils.containsIgnoreCase("a", "ABC"));
272         assertTrue(RedirectUtils.containsIgnoreCase("xabcz", "ABC"));
273     }
274 
275     public void testGetServerNameAndPath() throws Exception
276     {
277         final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
278         // Setup the mock "incoming" request to look like: http://example.com/jira/...
279         request.setupScheme("http");
280         request.setupServerName("example.com");
281         request.setupPort(80);
282         request.setupGetContextPath("/jira");
283         assertEquals("http://example.com/jira", RedirectUtils.getServerNameAndPath(request));
284 
285         // Setup the mock "incoming" request to look like: http://example.com:88/jira/...
286         request.setupScheme("http");
287         request.setupServerName("example.com");
288         request.setupPort(88);
289         request.setupGetContextPath("/jira");
290         assertEquals("http://example.com:88/jira", RedirectUtils.getServerNameAndPath(request));
291 
292         // https://example.com/jira/...
293         request.setupScheme("https");
294         request.setupServerName("example.com");
295         request.setupPort(443);
296         request.setupGetContextPath("/jira");
297         assertEquals("https://example.com/jira", RedirectUtils.getServerNameAndPath(request));
298 
299         // https://example.com:8443/jira/...
300         request.setupScheme("https");
301         request.setupServerName("example.com");
302         request.setupPort(8443);
303         request.setupGetContextPath("/jira");
304         assertEquals("https://example.com:8443/jira", RedirectUtils.getServerNameAndPath(request));
305     }
306 
307     public void testSameContext() throws Exception
308     {
309         final LocalMockHttpServletRequest request = new LocalMockHttpServletRequest();
310         // Setup the mock "incoming" request to look like: http://example.com/jira/...
311         request.setupScheme("http");
312         request.setupServerName("example.com");
313         request.setupPort(80);
314         request.setupGetContextPath("/jira");
315         // Same context
316         assertTrue(RedirectUtils.sameContext("http://example.com/jira", request));
317         assertTrue(RedirectUtils.sameContext("http://example.com/jira/", request));       
318         assertTrue(RedirectUtils.sameContext("http://example.com/jira/Stuff", request));
319         assertTrue(RedirectUtils.sameContext("http://example.com:80/jira/Stuff", request));
320         // Different context
321         assertFalse(RedirectUtils.sameContext("http://example2.com/jira", request));
322         assertFalse(RedirectUtils.sameContext("http://example.com/jirax", request));
323         assertFalse(RedirectUtils.sameContext("http://example2.com/jirax/", request));
324         assertFalse(RedirectUtils.sameContext("http://example2.com/jirax/Stuff", request));
325     }
326 }