View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.shiro.web.mgt;
20  
21  import org.apache.shiro.authc.AuthenticationInfo;
22  import org.apache.shiro.authc.SimpleAuthenticationInfo;
23  import org.apache.shiro.authc.UsernamePasswordToken;
24  import org.apache.shiro.codec.Base64;
25  import org.apache.shiro.crypto.CryptoException;
26  import org.apache.shiro.subject.PrincipalCollection;
27  import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
28  import org.apache.shiro.web.servlet.SimpleCookie;
29  import org.apache.shiro.web.subject.WebSubject;
30  import org.apache.shiro.web.subject.WebSubjectContext;
31  import org.apache.shiro.web.subject.support.DefaultWebSubjectContext;
32  import org.junit.Test;
33  
34  import javax.servlet.http.Cookie;
35  import javax.servlet.http.HttpServletRequest;
36  import javax.servlet.http.HttpServletResponse;
37  
38  import java.util.UUID;
39  
40  import static org.easymock.EasyMock.*;
41  import static org.junit.Assert.*;
42  
43  /**
44   * Unit tests for the {@link CookieRememberMeManager} implementation.
45   *
46   * @since 1.0
47   */
48  public class CookieRememberMeManagerTest {
49  
50      @Test
51      public void onSuccessfulLogin() {
52  
53          HttpServletRequest mockRequest = createNiceMock(HttpServletRequest.class);
54          HttpServletResponse mockResponse = createNiceMock(HttpServletResponse.class);
55          WebSubject mockSubject = createNiceMock(WebSubject.class);
56          expect(mockSubject.getServletRequest()).andReturn(mockRequest).anyTimes();
57          expect(mockSubject.getServletResponse()).andReturn(mockResponse).anyTimes();
58  
59          CookieRememberMeManager mgr = new CookieRememberMeManager();
60          org.apache.shiro.web.servlet.Cookie cookie = createMock(org.apache.shiro.web.servlet.Cookie.class);
61          mgr.setCookie(cookie);
62  
63          //first remove any previous cookie
64          cookie.removeFrom(isA(HttpServletRequest.class), isA(HttpServletResponse.class));
65  
66          //then ensure a new cookie is created by reading the template's attributes:
67          expect(cookie.getName()).andReturn("rememberMe");
68          expect(cookie.getValue()).andReturn(null);
69          expect(cookie.getComment()).andReturn(null);
70          expect(cookie.getDomain()).andReturn(null);
71          expect(cookie.getPath()).andReturn(null);
72          expect(cookie.getMaxAge()).andReturn(SimpleCookie.DEFAULT_MAX_AGE);
73          expect(cookie.getVersion()).andReturn(SimpleCookie.DEFAULT_VERSION);
74          expect(cookie.isSecure()).andReturn(false);
75          expect(cookie.isHttpOnly()).andReturn(true);
76          expect(cookie.getSameSite()).andReturn(org.apache.shiro.web.servlet.Cookie.SameSiteOptions.LAX);
77  
78          UsernamePasswordToken token = new UsernamePasswordToken("user", "secret");
79          token.setRememberMe(true);
80          AuthenticationInfo account = new SimpleAuthenticationInfo("user", "secret", "test");
81  
82          replay(mockSubject);
83          replay(mockRequest);
84          replay(cookie);
85  
86          mgr.onSuccessfulLogin(mockSubject, token, account);
87  
88          verify(mockRequest);
89          verify(mockSubject);
90          verify(cookie);
91      }
92      
93      // SHIRO-183
94      @Test
95      public void getRememberedSerializedIdentityReturnsNullForDeletedCookie() {
96          HttpServletRequest mockRequest = createMock(HttpServletRequest.class);
97          HttpServletResponse mockResponse = createMock(HttpServletResponse.class);
98          WebSubjectContext context = new DefaultWebSubjectContext();
99          context.setServletRequest(mockRequest);
100         context.setServletResponse(mockResponse);
101 
102         expect(mockRequest.getAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY)).andReturn(null);
103 
104         Cookie[] cookies = new Cookie[]{
105                 new Cookie(CookieRememberMeManager.DEFAULT_REMEMBER_ME_COOKIE_NAME, org.apache.shiro.web.servlet.Cookie.DELETED_COOKIE_VALUE)
106         };
107 
108         expect(mockRequest.getCookies()).andReturn(cookies);
109         replay(mockRequest);
110 
111         CookieRememberMeManager mgr = new CookieRememberMeManager();
112         assertNull(mgr.getRememberedSerializedIdentity(context));
113     }
114     
115 
116     // SHIRO-69
117     @Test
118     public void getRememberedPrincipals() {
119         HttpServletRequest mockRequest = createMock(HttpServletRequest.class);
120         HttpServletResponse mockResponse = createMock(HttpServletResponse.class);
121         WebSubjectContext context = new DefaultWebSubjectContext();
122         context.setServletRequest(mockRequest);
123         context.setServletResponse(mockResponse);
124 
125         expect(mockRequest.getAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY)).andReturn(null);
126 
127         //The following base64 string was determined from the log output of the above 'onSuccessfulLogin' test.
128         //This will have to change any time the PrincipalCollection implementation changes:
129         final String userPCAesBase64 = "0o6DCfePYTjK4q579qzUFEfkeGRvbBOdKHp2y8/nGAltt1Vz8uW0Z8igeO" +
130                 "Tq/yBmcw25f3Q0ui/Leg3x0iQZWhw9Bbu0mFHmHsGxEd6mPwtUpSegIjyX5c/kZpqnb7QLdajPWiczX8P" +
131                 "Oc2Eku5+8ye1u38Y8uKlklHxcYCPh0pRiDSBxfjPsLaDfOpGbmPjZd4SVg68i/++TvUjqBNJyb+pDix3f" +
132                 "PeuPvReWGcE50iovezVZrEfDOAQ0cZYW35ShypMWOmE9yZnb+p8++StDyAUegryyuIa4pjuRzfMh9D+sN" +
133                 "F9tm/EnDC1VCer2S/a0AGlWAQiM7jrWt1sNinZcKIrvShaWI21tONJt8WhozNS2H72lk4p92rfLNHeglT" +
134                 "xObxIYxLfTI9KiToSe1nYmpQmbBO8x1wWDkWBG//EqRvhgbIfQVqJp12T0fJC1nFuZuVhw/ZanaAZGDk8" +
135                 "7aLMiw3T6FBZtWaspgvfH+0TJrTD8Ra386ekNXNN8JW8=";
136 
137         Cookie[] cookies = new Cookie[]{
138                 new Cookie(CookieRememberMeManager.DEFAULT_REMEMBER_ME_COOKIE_NAME, userPCAesBase64)
139         };
140 
141         expect(mockRequest.getCookies()).andReturn(cookies);
142         replay(mockRequest);
143 
144         CookieRememberMeManager mgr = new CookieRememberMeManager();
145         mgr.setCipherKey( Base64.decode("kPH+bIxk5D2deZiIxcaaaA=="));
146         PrincipalCollection collection = mgr.getRememberedPrincipals(context);
147 
148         verify(mockRequest);
149 
150         assertTrue(collection != null);
151         //noinspection ConstantConditions
152         assertTrue(collection.iterator().next().equals("user"));
153     }
154 
155     @Test(expected = CryptoException.class)
156     public void getRememberedPrincipalsNoMoreDefaultCipher() {
157         HttpServletRequest mockRequest = createMock(HttpServletRequest.class);
158         HttpServletResponse mockResponse = createMock(HttpServletResponse.class);
159         WebSubjectContext context = new DefaultWebSubjectContext();
160         context.setServletRequest(mockRequest);
161         context.setServletResponse(mockResponse);
162 
163         expect(mockRequest.getAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY)).andReturn(null);
164         expect(mockRequest.getContextPath()).andReturn( "/test" );
165 
166 
167         //The following base64 string was determined from the log output of the above 'onSuccessfulLogin' test.
168         //This will have to change any time the PrincipalCollection implementation changes:
169         final String userPCAesBase64 = "0o6DCfePYTjK4q579qzUFEfkeGRvbBOdKHp2y8/nGAltt1Vz8uW0Z8igeO" +
170                 "Tq/yBmcw25f3Q0ui/Leg3x0iQZWhw9Bbu0mFHmHsGxEd6mPwtUpSegIjyX5c/kZpqnb7QLdajPWiczX8P" +
171                 "Oc2Eku5+8ye1u38Y8uKlklHxcYCPh0pRiDSBxfjPsLaDfOpGbmPjZd4SVg68i/++TvUjqBNJyb+pDix3f" +
172                 "PeuPvReWGcE50iovezVZrEfDOAQ0cZYW35ShypMWOmE9yZnb+p8++StDyAUegryyuIa4pjuRzfMh9D+sN" +
173                 "F9tm/EnDC1VCer2S/a0AGlWAQiM7jrWt1sNinZcKIrvShaWI21tONJt8WhozNS2H72lk4p92rfLNHeglT" +
174                 "xObxIYxLfTI9KiToSe1nYmpQmbBO8x1wWDkWBG//EqRvhgbIfQVqJp12T0fJC1nFuZuVhw/ZanaAZGDk8" +
175                 "7aLMiw3T6FBZtWaspgvfH+0TJrTD8Ra386ekNXNN8JW8=";
176 
177         Cookie[] cookies = new Cookie[]{
178             new Cookie(CookieRememberMeManager.DEFAULT_REMEMBER_ME_COOKIE_NAME, userPCAesBase64)
179         };
180 
181         expect(mockRequest.getCookies()).andReturn(cookies);
182         replay(mockRequest);
183 
184         CookieRememberMeManager mgr = new CookieRememberMeManager();
185         // without the old default cipher set, this will fail (expected)
186         // mgr.setCipherKey( Base64.decode("kPH+bIxk5D2deZiIxcaaaA=="));
187         // this will throw a CryptoException
188         mgr.getRememberedPrincipals(context);
189     }
190 
191     // SHIRO-69
192 
193     @Test
194     public void getRememberedPrincipalsDecryptionError() {
195         HttpServletRequest mockRequest = createNiceMock(HttpServletRequest.class);
196         HttpServletResponse mockResponse = createNiceMock(HttpServletResponse.class);
197 
198         WebSubjectContext context = new DefaultWebSubjectContext();
199         context.setServletRequest(mockRequest);
200         context.setServletResponse(mockResponse);
201 
202         expect(mockRequest.getAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY)).andReturn(null);
203 
204         // Simulate a bad return value here (for example if this was encrypted with a different key
205         final String userPCAesBase64 = "garbage";
206         Cookie[] cookies = new Cookie[]{
207                 new Cookie(CookieRememberMeManager.DEFAULT_REMEMBER_ME_COOKIE_NAME, userPCAesBase64)
208         };
209 
210         expect(mockRequest.getCookies()).andReturn(cookies).anyTimes();
211         replay(mockRequest);
212 
213         CookieRememberMeManager mgr = new CookieRememberMeManager();
214         try {
215             mgr.getRememberedPrincipals(context);
216         } catch (CryptoException expected) {
217             return;
218         }
219         fail("CryptoException was expected to be thrown");
220     }
221 
222     @Test
223     public void onLogout() {
224         CookieRememberMeManager mgr = new CookieRememberMeManager();
225         org.apache.shiro.web.servlet.Cookie cookie = createMock(org.apache.shiro.web.servlet.Cookie.class);
226         mgr.setCookie(cookie);
227 
228         HttpServletRequest mockRequest = createMock(HttpServletRequest.class);
229         HttpServletResponse mockResponse = createMock(HttpServletResponse.class);
230         WebSubject mockSubject = createNiceMock(WebSubject.class);
231         expect(mockSubject.getServletRequest()).andReturn(mockRequest).anyTimes();
232         expect(mockSubject.getServletResponse()).andReturn(mockResponse).anyTimes();
233         expect(mockRequest.getContextPath()).andReturn(null).anyTimes();
234 
235         cookie.removeFrom(isA(HttpServletRequest.class), isA(HttpServletResponse.class));
236 
237         replay(mockRequest);
238         replay(mockResponse);
239         replay(mockSubject);
240         replay(cookie);
241 
242         mgr.onLogout(mockSubject);
243 
244         verify(mockSubject);
245         verify(mockRequest);
246         verify(mockResponse);
247         verify(cookie);
248     }
249 
250     @Test
251     public void shouldIgnoreInvalidCookieValues() {
252         // given
253         HttpServletRequest mockRequest = createMock(HttpServletRequest.class);
254         HttpServletResponse mockResponse = createMock(HttpServletResponse.class);
255         WebSubjectContext context = new DefaultWebSubjectContext();
256         context.setServletRequest(mockRequest);
257         context.setServletResponse(mockResponse);
258 
259         CookieRememberMeManager mgr = new CookieRememberMeManager();
260         Cookie[] cookies = new Cookie[]{
261                 new Cookie(CookieRememberMeManager.DEFAULT_REMEMBER_ME_COOKIE_NAME, UUID.randomUUID().toString() + "%%ldapRealm")
262         };
263 
264         expect(mockRequest.getAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY)).andReturn(null);
265         expect(mockRequest.getContextPath()).andReturn(null);
266         expect(mockRequest.getCookies()).andReturn(cookies);
267         replay(mockRequest);
268 
269         // when
270         final byte[] rememberedSerializedIdentity = mgr.getRememberedSerializedIdentity(context);
271 
272         // then
273         assertNull("should ignore invalid cookie values", rememberedSerializedIdentity);
274     }
275 }