1 package com.atlassian.seraph.service.rememberme;
2
3 import com.atlassian.seraph.spi.rememberme.RememberMeConfiguration;
4 import com.atlassian.seraph.spi.rememberme.RememberMeTokenDao;
5 import junit.framework.TestCase;
6 import org.mockito.ArgumentCaptor;
7 import static org.mockito.Matchers.eq;
8 import static org.mockito.Mockito.mock;
9 import static org.mockito.Mockito.times;
10 import static org.mockito.Mockito.verify;
11 import static org.mockito.Mockito.when;
12
13 import javax.servlet.http.Cookie;
14 import javax.servlet.http.HttpServletRequest;
15 import javax.servlet.http.HttpServletResponse;
16
17
18
19 public class TestDefaultRememberMeService extends TestCase
20 {
21 private HttpServletRequest request;
22 private HttpServletResponse response;
23 private RememberMeConfiguration configuration;
24 private RememberMeTokenGenerator tokenGenerator;
25 private RememberMeTokenDao tokenDao;
26 private DefaultRememberMeService service;
27 private RememberMeToken fredsToken;
28
29 private static final String FRED_FLINTSTONE = "fred flintstone";
30 private static final String RANDOM_STRING = "randomString";
31 private static final String COOKIE_NAME = "cookieName";
32 private static final String COOKIE_DOMAIN = "cookiedomain";
33 private static final String COOKIE_PATH = "cookiepath";
34 private static final int COOKIE_AGE = 1673;
35 private static final long TOKEN_ID = 456L;
36 private static final String COLON = "%3A";
37 private static final String COOKIE_VALUE = "456" + COLON + "randomString";
38 private static final String BAD_COOKIE_VALUE = "456" + COLON + "badValue";
39
40 @Override
41 protected void setUp() throws Exception
42 {
43 request = mock(HttpServletRequest.class);
44 response = mock(HttpServletResponse.class);
45 configuration = mock(RememberMeConfiguration.class);
46 tokenGenerator = mock(RememberMeTokenGenerator.class);
47 tokenDao = mock(RememberMeTokenDao.class);
48
49
50 service = new DefaultRememberMeService(configuration, tokenDao, tokenGenerator);
51
52 fredsToken = DefaultRememberMeToken.builder(TOKEN_ID, RANDOM_STRING).setUserName(FRED_FLINTSTONE).build();
53
54 when(tokenGenerator.generateToken(FRED_FLINTSTONE)).thenReturn(fredsToken);
55 when(configuration.getCookieName()).thenReturn(COOKIE_NAME);
56 when(configuration.getCookieDomain(request)).thenReturn(COOKIE_DOMAIN);
57 when(configuration.getCookiePath(request)).thenReturn(COOKIE_PATH);
58 when(configuration.getCookieMaxAgeInSeconds()).thenReturn(COOKIE_AGE);
59 when(configuration.isCookieHttpOnly()).thenReturn(false);
60 }
61
62 @Override
63 protected void tearDown() throws Exception
64 {
65 }
66
67 public void testAddRememberMe_NoCookies()
68 {
69 when(request.getCookies()).thenReturn(new Cookie[0]);
70 when(tokenDao.save(fredsToken)).thenReturn(fredsToken);
71
72 service.addRememberMeCookie(request, response, FRED_FLINTSTONE);
73
74 assertCookieValuesAreSet(response, false);
75 }
76
77 public void testAddRememberMe_NoCookies_HttpOnly()
78 {
79 when(configuration.isCookieHttpOnly()).thenReturn(true);
80 when(request.getCookies()).thenReturn(new Cookie[0]);
81 when(tokenDao.save(fredsToken)).thenReturn(fredsToken);
82
83 service.addRememberMeCookie(request, response, FRED_FLINTSTONE);
84
85 assertCookieValuesAreSet(response, true);
86 }
87
88 public void testAddRememberMe_WithExistingCookies()
89 {
90 Cookie existingCookie = new Cookie(COOKIE_NAME, "oldValue");
91 when(request.getCookies()).thenReturn(new Cookie[] { existingCookie });
92 when(tokenDao.save(fredsToken)).thenReturn(fredsToken);
93
94 service.addRememberMeCookie(request, response, FRED_FLINTSTONE);
95
96 assertCookieValuesAreSet(response, false);
97 }
98
99 public void testAddRememberMe_WithExistingCookies_HttpOnly()
100 {
101 when(configuration.isCookieHttpOnly()).thenReturn(true);
102
103 Cookie existingCookie = new Cookie(COOKIE_NAME, "oldValue");
104 when(request.getCookies()).thenReturn(new Cookie[] { existingCookie });
105 when(tokenDao.save(fredsToken)).thenReturn(fredsToken);
106
107 service.addRememberMeCookie(request, response, FRED_FLINTSTONE);
108
109 assertCookieValuesAreSet(response, true);
110 }
111
112 public void testRemoveRememberMeCookie_NoCookies()
113 {
114 when(request.getCookies()).thenReturn(new Cookie[] { });
115
116 service.removeRememberMeCookie(request, response);
117
118 verify(response, times(0)).addHeader(null, null);
119 }
120
121 public void testRemoveRememberMeCookie_WithExistingCookie()
122 {
123 Cookie existingCookie = new Cookie(COOKIE_NAME, "oldValue");
124
125 when(request.getCookies()).thenReturn(new Cookie[] { existingCookie });
126
127 service.removeRememberMeCookie(request, response);
128
129 assertThatExistingCookieIsRemoved(false);
130 }
131
132 public void testRemoveRememberMeCookie_WithExistingCookie_HttpOnly()
133 {
134 Cookie existingCookie = new Cookie(COOKIE_NAME, "oldValue");
135
136 when(request.getCookies()).thenReturn(new Cookie[] { existingCookie });
137 when(configuration.isCookieHttpOnly()).thenReturn(true);
138
139 service.removeRememberMeCookie(request, response);
140
141 assertThatExistingCookieIsRemoved(true);
142 }
143
144 private void assertCookieValuesAreSet(final HttpServletResponse response, boolean httpOnlyUsed)
145 {
146 if (httpOnlyUsed)
147 {
148 ArgumentCaptor<String> cookieCaptor = ArgumentCaptor.forClass(String.class);
149 verify(response, times(1)).addHeader(eq("Set-Cookie"), cookieCaptor.capture());
150
151 final String header = cookieCaptor.getValue();
152 assertTrue(header.indexOf(COOKIE_NAME + "=" + COOKIE_VALUE) == 0);
153 assertTrue(header.indexOf("; Domain=" + COOKIE_DOMAIN) != -1);
154 assertTrue(header.indexOf("; Path=" + COOKIE_PATH) != -1);
155 assertTrue(header.indexOf("; HttpOnly") != -1);
156 }
157 else
158 {
159 ArgumentCaptor<Cookie> cookieCaptor = ArgumentCaptor.forClass(Cookie.class);
160 verify(response, times(1)).addCookie(cookieCaptor.capture());
161
162 final Cookie cooky = cookieCaptor.getValue();
163 assertEquals(COOKIE_NAME, cooky.getName());
164 assertEquals(COOKIE_DOMAIN, cooky.getDomain());
165 assertEquals(COOKIE_PATH, cooky.getPath());
166 assertEquals(COOKIE_AGE, cooky.getMaxAge());
167 assertEquals(COOKIE_VALUE, cooky.getValue());
168 }
169 }
170
171 private void assertThatExistingCookieIsRemoved(boolean isHttpOnly)
172 {
173 if (isHttpOnly)
174 {
175 ArgumentCaptor<String> cookieCaptor = ArgumentCaptor.forClass(String.class);
176 verify(response, times(1)).addHeader(eq("Set-Cookie"), cookieCaptor.capture());
177
178 final String header = cookieCaptor.getValue();
179
180 assertTrue(header.indexOf(COOKIE_NAME + "=" + "") == 0);
181
182 assertTrue(header.indexOf("; Domain=" + COOKIE_DOMAIN) != -1);
183 assertTrue(header.indexOf("; Path=" + COOKIE_PATH) != -1);
184 assertTrue(header.indexOf("; HttpOnly") != -1);
185
186 }
187 else
188 {
189 ArgumentCaptor<Cookie> cookieCaptor = ArgumentCaptor.forClass(Cookie.class);
190 verify(response, times(1)).addCookie(cookieCaptor.capture());
191
192 final Cookie cooky = cookieCaptor.getValue();
193 assertEquals(COOKIE_NAME, cooky.getName());
194 assertEquals(COOKIE_DOMAIN, cooky.getDomain());
195 assertEquals(COOKIE_PATH, cooky.getPath());
196 assertEquals(0, cooky.getMaxAge());
197 assertEquals("", cooky.getValue());
198 }
199
200 }
201
202 public void testGetRememberMeCookieAuthenticatedUsername_NoCookies()
203 {
204 when(request.getCookies()).thenReturn(new Cookie[0]);
205
206 final String username = service.getRememberMeCookieAuthenticatedUsername(request, response);
207 assertNull(username);
208 }
209
210 public void testGetRememberMeCookieAuthenticatedUsername_HasCookie_ButItDoesNotMatch()
211 {
212 Cookie existingCookie = new Cookie(COOKIE_NAME, BAD_COOKIE_VALUE);
213 when(request.getCookies()).thenReturn(new Cookie[] { existingCookie });
214
215 when(tokenDao.findById(TOKEN_ID)).thenReturn(fredsToken);
216
217 final String username = service.getRememberMeCookieAuthenticatedUsername(request, response);
218 assertNull(username);
219
220 assertThatExistingCookieIsRemoved(false);
221 }
222
223
224 public void testGetRememberMeCookieAuthenticatedUsername_HasCookie_ButTheAppDoesntLikeIt()
225 {
226 Cookie existingCookie = new Cookie(COOKIE_NAME, COOKIE_VALUE);
227 when(request.getCookies()).thenReturn(new Cookie[] { existingCookie });
228
229 when(tokenDao.findById(TOKEN_ID)).thenReturn(null);
230
231 final String username = service.getRememberMeCookieAuthenticatedUsername(request, response);
232 assertNull(username);
233
234 assertThatExistingCookieIsRemoved(false);
235 }
236
237 public void testGetRememberMeCookieAuthenticatedUsername_HasCookie_AndItsGood()
238 {
239 Cookie existingCookie = new Cookie(COOKIE_NAME, COOKIE_VALUE);
240 when(request.getCookies()).thenReturn(new Cookie[] { existingCookie });
241
242 when(tokenDao.findById(TOKEN_ID)).thenReturn(fredsToken);
243
244 final String username = service.getRememberMeCookieAuthenticatedUsername(request, response);
245 assertEquals(FRED_FLINTSTONE, username);
246 }
247 }