/*
* Copyright (C) 2007-2014 Crafter Software Corporation.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.craftercms.security.authentication.impl;
import java.util.Date;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.craftercms.profile.api.Profile;
import org.craftercms.profile.api.Ticket;
import org.craftercms.profile.api.exceptions.ErrorCode;
import org.craftercms.profile.api.services.AuthenticationService;
import org.craftercms.profile.api.services.ProfileService;
import org.craftercms.profile.exceptions.ProfileRestServiceException;
import org.craftercms.security.authentication.Authentication;
import org.craftercms.security.authentication.AuthenticationCache;
import org.craftercms.security.exception.BadCredentialsException;
import org.craftercms.security.exception.DisabledUserException;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Unit tests for {@link org.craftercms.security.authentication.impl.AuthenticationManagerImpl}.
*
* @author avasquez
*/
public class AuthenticationManagerImplTest {
private static final String TENANT1 = "default";
private static final String TENANT2 = "mysite";
private static final String USERNAME1 = "avasquez";
private static final String USERNAME2 = "avasquez2";
private static final String DISABLED_USERNAME = "jdoe";
private static final String PASSWORD1 = "1234";
private static final String PASSWORD2 = "4321";
private static final ObjectId PROFILE_ID1 = new ObjectId();
private static final ObjectId PROFILE_ID2 = new ObjectId();
private static final String TICKET_ID1 = UUID.randomUUID().toString();
private static final String TICKET_ID2 = UUID.randomUUID().toString();
private static final String INVALID_TICKET_ID = UUID.randomUUID().toString();
private AuthenticationManagerImpl authenticationManager;
@Mock
private AuthenticationService authenticationService;
@Mock
private ProfileService profileService;
@Mock
private AuthenticationCache authenticationCache;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(authenticationService.authenticate(TENANT1, USERNAME1, PASSWORD1)).thenReturn(getTicket1());
when(authenticationService.authenticate(TENANT2, USERNAME2, PASSWORD2)).thenReturn(getTicket2());
doThrow(new ProfileRestServiceException(HttpStatus.UNAUTHORIZED, ErrorCode.BAD_CREDENTIALS, ""))
.when(authenticationService).authenticate(TENANT1, USERNAME2, PASSWORD2);
doThrow(new ProfileRestServiceException(HttpStatus.FORBIDDEN, ErrorCode.DISABLED_PROFILE, ""))
.when(authenticationService).authenticate(TENANT1, DISABLED_USERNAME, PASSWORD1);
when(profileService.getProfile(PROFILE_ID1.toString(), new String[0])).thenReturn(getProfile1());
when(profileService.getProfile(PROFILE_ID2.toString(), new String[0])).thenReturn(getProfile2());
when(profileService.getProfileByTicket(TICKET_ID1, new String[0])).thenReturn(getProfile1());
doThrow(new ProfileRestServiceException(HttpStatus.BAD_REQUEST, ErrorCode.NO_SUCH_TICKET, ""))
.when(profileService).getProfileByTicket(INVALID_TICKET_ID, new String[0]);
when(authenticationCache.getAuthentication(TICKET_ID1)).thenReturn(getAuthentication1());
authenticationManager = new AuthenticationManagerImpl();
authenticationManager.setAuthenticationService(authenticationService);
authenticationManager.setProfileService(profileService);
authenticationManager.setAuthenticationCache(authenticationCache);
}
@Test
public void testAuthenticateUser() throws Exception {
Authentication authentication = authenticationManager.authenticateUser(TENANT1, USERNAME1, PASSWORD1);
Authentication expected = getAuthentication1();
assertNotNull(authentication);
assertEquals(expected.getTicket(), authentication.getTicket());
assertEquals(expected.getProfile().getId(), authentication.getProfile().getId());
verify(authenticationService).authenticate(TENANT1, USERNAME1, PASSWORD1);
verify(profileService).getProfile(PROFILE_ID1.toString(), new String[0]);
}
@Test
public void testAuthenticateUserWithMultipleTenants() throws Exception {
Authentication authentication = authenticationManager.authenticateUser(new String[] {TENANT1, TENANT2},
USERNAME2, PASSWORD2);
Authentication expected = getAuthentication2();
assertNotNull(authentication);
assertEquals(expected.getTicket(), authentication.getTicket());
assertEquals(expected.getProfile().getId(), authentication.getProfile().getId());
verify(authenticationService).authenticate(TENANT1, USERNAME2, PASSWORD2);
verify(authenticationService).authenticate(TENANT2, USERNAME2, PASSWORD2);
verify(profileService).getProfile(PROFILE_ID2.toString(), new String[0]);
}
@Test(expected = DisabledUserException.class)
public void testAuthenticateDisabledUser() throws Exception {
authenticationManager.authenticateUser(TENANT1, DISABLED_USERNAME, PASSWORD1);
}
@Test(expected = BadCredentialsException.class)
public void testAuthenticateUserBadCredentials() throws Exception {
authenticationManager.authenticateUser(TENANT1, USERNAME2, PASSWORD2);
}
@Test
public void testGetAuthentication() throws Exception {
Authentication authentication = authenticationManager.getAuthentication(TICKET_ID1, false);
Authentication expected = getAuthentication1();
assertNotNull(authentication);
assertEquals(expected.getTicket(), authentication.getTicket());
assertEquals(expected.getProfile().getId(), authentication.getProfile().getId());
verify(authenticationCache).getAuthentication(TICKET_ID1);
authentication = authenticationManager.getAuthentication(TICKET_ID1, true);
assertNotNull(authentication);
assertEquals(expected.getTicket(), authentication.getTicket());
assertEquals(expected.getProfile().getId(), authentication.getProfile().getId());
verify(authenticationCache).putAuthentication(authentication);
}
@Test
public void testGetAuthenticationInvalidTicket() throws Exception {
Authentication auth = authenticationManager.getAuthentication(INVALID_TICKET_ID, false);
assertNull(auth);
}
@Test
public void testInvalidateAuthentication() throws Exception {
Authentication auth = getAuthentication1();
authenticationManager.invalidateAuthentication(auth);
verify(authenticationCache).removeAuthentication(auth.getTicket());
verify(authenticationService).invalidateTicket(auth.getTicket());
}
private Ticket getTicket1() {
Ticket ticket = new Ticket();
ticket.setId(TICKET_ID1);
ticket.setTenant(TENANT1);
ticket.setProfileId(PROFILE_ID1.toString());
ticket.setLastRequestTime(new Date());
return ticket;
}
private Ticket getTicket2() {
Ticket ticket = new Ticket();
ticket.setId(TICKET_ID2);
ticket.setTenant(TENANT2);
ticket.setProfileId(PROFILE_ID2.toString());
ticket.setLastRequestTime(new Date());
return ticket;
}
private Profile getProfile1() {
Profile profile = new Profile();
profile.setId(PROFILE_ID1);
return profile;
}
private Profile getProfile2() {
Profile profile = new Profile();
profile.setId(PROFILE_ID2);
return profile;
}
private Authentication getAuthentication1() {
return new DefaultAuthentication(TICKET_ID1, getProfile1());
}
private Authentication getAuthentication2() {
return new DefaultAuthentication(TICKET_ID2, getProfile2());
}
}