/*
* Copyright (c) 2009 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.service.security.persistentlogin;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eurekastreams.server.service.security.userdetails.ExtendedUserDetails;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Test;
import org.springframework.security.Authentication;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.eurekastreams.server.domain.PersistentLogin;
import org.springframework.security.ui.rememberme.InvalidCookieException;
/**
* Test class for PersistentLoginService class.
*
*/
public class PersistentLoginServiceTest
{
/**
* Context for building mock objects.
*/
private final Mockery context = new JUnit4Mockery()
{
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
/**
* Test constructor rejects null key.
*/
@Test(expected = IllegalArgumentException.class)
public void testConstructorNullKey()
{
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
new PersistentLoginService(null, userDetailsService, loginRepo);
}
/**
* Test constructor rejects null UserDetailsService.
*/
@Test(expected = IllegalArgumentException.class)
public void testConstructorNullUserDetailsService()
{
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
new PersistentLoginService("blah", null, loginRepo);
}
/**
* Test constructor rejects null PersistentLoginRepository.
*/
@Test(expected = IllegalArgumentException.class)
public void testConstructorNullPersistentLoginRepository()
{
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
new PersistentLoginService("blah", userDetailsService, null);
}
/**
* Test wrong number of cookie tokens causes exception.
*/
@Test(expected = InvalidCookieException.class)
public void testProcessAutoLoginCookieWrongNumTokens()
{
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final String[] cookieTokens = new String[] { "blah", "foo" };
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.processAutoLoginCookie(cookieTokens, request, response);
context.assertIsSatisfied();
}
/**
* Test wrong number format causes exception.
*/
@Test(expected = InvalidCookieException.class)
public void testProcessAutoLoginCookieWrongNumberFormat()
{
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final String[] cookieTokens = new String[] { "blah", "foo", "whatever" };
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.processAutoLoginCookie(cookieTokens, request, response);
context.assertIsSatisfied();
}
/**
* Test expired token causes exception.
*/
@Test(expected = InvalidCookieException.class)
public void testProcessAutoLoginCookieTokenExpired()
{
final int cookieDelay = 1000;
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final String[] cookieTokens = new String[] { "blah",
String.valueOf(System.currentTimeMillis() - cookieDelay), "whatever" };
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.processAutoLoginCookie(cookieTokens, request, response);
context.assertIsSatisfied();
}
/**
* Test no persistentLogin information found causes exception.
*/
@Test(expected = InvalidCookieException.class)
public void testProcessAutoLoginNoDataRecord()
{
final int cookieDelay = 30000;
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final String[] cookieTokens = new String[] { "blah",
String.valueOf(System.currentTimeMillis() + cookieDelay), "whatever" };
final ExtendedUserDetails userDetails = context
.mock(ExtendedUserDetails.class);
context.checking(new Expectations()
{
{
oneOf(userDetailsService).loadUserByUsername("blah");
will(returnValue(userDetails));
oneOf(userDetails).getPersistentLogin();
will(returnValue(null));
}
});
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.processAutoLoginCookie(cookieTokens, request, response);
context.assertIsSatisfied();
}
/**
* Test expiration time mismatch causes exception.
*/
@Test(expected = InvalidCookieException.class)
public void testProcessAutoLoginExpiryTimeMismatch()
{
final long cookieDelay = 30000L;
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final String[] cookieTokens = new String[] { "blah", "", "whatever" };
final ExtendedUserDetails userDetails = context
.mock(ExtendedUserDetails.class);
final PersistentLogin login = context.mock(PersistentLogin.class);
final long cookieTime = System.currentTimeMillis() + cookieDelay;
cookieTokens[1] = String.valueOf(cookieTime);
context.checking(new Expectations()
{
{
oneOf(userDetailsService).loadUserByUsername("blah");
will(returnValue(userDetails));
oneOf(userDetails).getPersistentLogin();
will(returnValue(login));
oneOf(login).getTokenValue();
will(returnValue("abc123"));
oneOf(login).getTokenExpirationDate();
will(returnValue((cookieTime + 4L)));
}
});
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.processAutoLoginCookie(cookieTokens, request, response);
context.assertIsSatisfied();
}
/**
* Test token signature mismatch causes exception.
*/
@Test(expected = InvalidCookieException.class)
public void testProcessAutoLoginTokenValueMismatch()
{
final long cookieDelay = 30000L;
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final String[] cookieTokens = new String[] { "blah", "", "whatever" };
final ExtendedUserDetails userDetails = context
.mock(ExtendedUserDetails.class);
final PersistentLogin login = context.mock(PersistentLogin.class);
final long cookieTime = System.currentTimeMillis() + cookieDelay;
cookieTokens[1] = String.valueOf(cookieTime);
context.checking(new Expectations()
{
{
oneOf(userDetailsService).loadUserByUsername("blah");
will(returnValue(userDetails));
oneOf(userDetails).getPersistentLogin();
will(returnValue(login));
oneOf(login).getTokenValue();
will(returnValue("abc123"));
oneOf(login).getTokenExpirationDate();
will(returnValue((cookieTime)));
}
});
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.processAutoLoginCookie(cookieTokens, request, response);
context.assertIsSatisfied();
}
/**
* Test mapper is called correctly.
*/
@Test
public void testOnLoginSuccess()
{
final UserDetails userDetails = context.mock(UserDetails.class);
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final Authentication auth = context.mock(Authentication.class);
context.checking(new Expectations()
{
{
exactly(2).of(auth).getPrincipal();
will(returnValue(userDetails));
oneOf(userDetails).getUsername();
will(returnValue("username"));
oneOf(loginRepo).createOrUpdatePersistentLogin(
with(any(PersistentLogin.class)));
oneOf(request).getContextPath();
will(returnValue(""));
oneOf(response).addCookie(with(any(Cookie.class)));
}
});
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.onLoginSuccess(request, response, auth);
context.assertIsSatisfied();
}
/**
* Test mapper not called with empty username.
*/
@Test
public void testOnLoginSuccessEmptyUsername()
{
final UserDetails userDetails = context.mock(UserDetails.class);
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final Authentication auth = context.mock(Authentication.class);
context.checking(new Expectations()
{
{
exactly(2).of(auth).getPrincipal();
will(returnValue(userDetails));
oneOf(userDetails).getUsername();
will(returnValue(""));
}
});
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.onLoginSuccess(request, response, auth);
context.assertIsSatisfied();
}
/**
* Test exception is swallowed and setCookie is not called on mapper
* exception.
*/
@Test
public void testOnLoginSuccessRepositoryException()
{
final UserDetails userDetails = context.mock(UserDetails.class);
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final Authentication auth = context.mock(Authentication.class);
context.checking(new Expectations()
{
{
exactly(2).of(auth).getPrincipal();
will(returnValue(userDetails));
oneOf(userDetails).getUsername();
will(returnValue("username"));
oneOf(loginRepo).createOrUpdatePersistentLogin(
with(any(PersistentLogin.class)));
will(throwException(new Exception()));
}
});
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.onLoginSuccess(request, response, auth);
context.assertIsSatisfied();
}
/**
* Test cancelCookie called and mapper called to remove data.
*/
@Test
public void testLogout()
{
final HttpServletRequest request = context
.mock(HttpServletRequest.class);
final HttpServletResponse response = context
.mock(HttpServletResponse.class);
final Authentication auth = context.mock(Authentication.class);
final UserDetails userDetails = context.mock(UserDetails.class);
final PersistentLoginRepository loginRepo = context
.mock(PersistentLoginRepository.class);
final UserDetailsService userDetailsService = context
.mock(UserDetailsService.class);
context.checking(new Expectations()
{
{
oneOf(auth).getName();
will(returnValue("foo"));
oneOf(request).getContextPath();
will(returnValue(""));
oneOf(response).addCookie(with(any(Cookie.class)));
oneOf(auth).getPrincipal();
will(returnValue(userDetails));
oneOf(userDetails).getUsername();
will(returnValue("username"));
oneOf(loginRepo).removePersistentLogin("username");
}
});
PersistentLoginService svc = new PersistentLoginService("key",
userDetailsService, loginRepo);
svc.logout(request, response, auth);
context.assertIsSatisfied();
}
}