/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Jakob Hendeß
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.xlrnet.metadict.web.auth.services;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Test;
import org.xlrnet.metadict.api.auth.User;
import org.xlrnet.metadict.api.storage.StorageBackendException;
import org.xlrnet.metadict.api.storage.StorageService;
import org.xlrnet.metadict.core.services.storage.InMemoryStorage;
import org.xlrnet.metadict.web.auth.entities.*;
import org.xlrnet.metadict.web.middleware.services.SequenceService;
import org.xlrnet.metadict.web.middleware.util.CryptoUtils;
import javax.xml.bind.DatatypeConverter;
import java.util.Optional;
import static junit.framework.TestCase.*;
import static org.mockito.Mockito.*;
public class UserServiceTest {
private static final String TEST_USER_NAME = "testUser";
private static final String TEST_PASSWORD = "testPassword";
private StorageService storageService;
private UserService userService;
private UserFactory userFactory;
@Before
public void setup() {
this.storageService = spy(new InMemoryStorage());
this.userFactory = new UserFactory(new SequenceService());
this.userService = spy(new UserService(this.storageService, this.userFactory));
}
@Test
public void testCreateNewUserWithPassword() throws Exception {
Optional<User> newUserWithPassword = this.userService.createNewUser(TEST_USER_NAME, TEST_PASSWORD);
assertTrue(newUserWithPassword.isPresent());
User user = newUserWithPassword.get();
assertEquals("testUser", user.getName());
assertNotNull(user.getRoles());
assertTrue("User must have REGULAR role", user.getRoles().contains(UserRole.REGULAR_USER));
assertTrue("User id may not be empty", StringUtils.isNotEmpty(user.getId()));
verify(this.storageService).create(eq(UserService.BASIC_AUTH_NAMESPACE), anyString(), anyString());
verify(this.storageService).create(eq(UserService.GENERAL_USER_NAMESPACE), anyString(), anyString());
}
@Test
public void testCreateNewTechUserWithPassword() throws Exception {
User user = this.userService.createTechnicalUser(TEST_PASSWORD);
assertNotNull(user);
assertTrue("User name may not be empty", StringUtils.isNotEmpty(user.getName()));
assertNotNull(user.getRoles());
assertTrue("User must have TECHNICAL role", user.getRoles().contains(UserRole.TECH_USER));
assertTrue("User id may not be empty", StringUtils.isNotEmpty(user.getId()));
verify(this.storageService).create(eq(UserService.BASIC_AUTH_NAMESPACE), anyString(), anyString());
verify(this.storageService).create(eq(UserService.GENERAL_USER_NAMESPACE), anyString(), anyString());
}
@Test
public void testCreateNewUserWithPassword_existing() throws Exception {
Optional<User> existingUser = Optional.of(this.userFactory.newDefaultUser(TEST_USER_NAME));
doReturn(existingUser).when(this.userService).findUserDataByName(TEST_USER_NAME);
Optional<User> newUser = this.userService.createNewUser(TEST_USER_NAME, TEST_PASSWORD);
assertFalse("New user must be non-existing", newUser.isPresent());
verify(this.storageService, never()).create(anyString(), anyString(), anyString());
verify(this.storageService, never()).put(anyString(), anyString(), anyString());
}
@Test
public void testAuthenticateWithPassword_correct() throws Exception {
prepareAuthDataMock();
Optional<User> user = this.userService.authenticateWithPassword(TEST_USER_NAME, TEST_PASSWORD);
assertTrue("User should be present but isn't (i.e. password check doesn't work)", user.isPresent());
}
@Test
public void testAuthenticateWithPassword_wrong() throws Exception {
prepareAuthDataMock();
Optional<User> user = this.userService.authenticateWithPassword(TEST_USER_NAME, "Some_Wrong_Password");
assertFalse("User shouldn't be present but is (i.e. password check doesn't work)", user.isPresent());
}
@Test
public void testHasRole_false() throws Exception {
User user = this.userFactory.newDefaultUser(TEST_USER_NAME);
boolean b = this.userService.hasRole(user, Roles.ADMIN_ROLE_ID);
assertFalse("New user may not have role " + Roles.ADMIN_ROLE_ID, b);
}
@Test
public void testHasRole_true() throws Exception {
User user = new BasicUser("", TEST_USER_NAME, ImmutableSet.of(UserRole.ADMIN));
boolean b = this.userService.hasRole(user, Roles.ADMIN_ROLE_ID);
assertTrue("User must have role " + Roles.ADMIN_ROLE_ID + " but hasn't", b);
}
@Test
public void testRemoveUser() throws StorageBackendException {
// Prepare user for test
User user = this.userService.createTechnicalUser(TEST_PASSWORD);
assertTrue("User should exist, but doesn't", this.userService.findUserDataByName(user.getName()).isPresent());
// Remove the user
boolean status = this.userService.removeUser(user.getName());
assertTrue("Removing user should have been successful", status);
assertFalse("User shouldn't exist, but does", this.userService.findUserDataByName(user.getName()).isPresent());
verify(this.storageService).delete(eq(UserService.BASIC_AUTH_NAMESPACE), eq(user.getName()));
verify(this.storageService).delete(eq(UserService.GENERAL_USER_NAMESPACE), eq(user.getName()));
}
@Test
public void testRemoveUser_failed() throws StorageBackendException {
String username = DatatypeConverter.printHexBinary(CryptoUtils.generateRandom(16));
// Remove the user
boolean status = this.userService.removeUser(username);
assertFalse("Removing user should fail, but didn't", status);
}
private void prepareAuthDataMock() throws org.xlrnet.metadict.api.storage.StorageBackendException, org.xlrnet.metadict.api.storage.StorageOperationException {
byte[] salt = CryptoUtils.generateRandom(CryptoUtils.DEFAULT_SALT_LENGTH);
byte[] hashedPassword = this.userService.hashPassword(TEST_PASSWORD, salt);
Optional<BasicAuthData> authData = Optional.of(new BasicAuthData(hashedPassword, salt));
Optional<User> user = Optional.of(this.userFactory.newDefaultUser(TEST_USER_NAME));
doReturn(authData).when(this.storageService).read(UserService.BASIC_AUTH_NAMESPACE, TEST_USER_NAME, BasicAuthData.class);
doReturn(authData).when(this.storageService).read(UserService.GENERAL_USER_NAMESPACE, TEST_USER_NAME, User.class);
}
}