/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.ambari.server.controller.internal;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.H2DatabaseCleaner;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.spi.Predicate;
import org.apache.ambari.server.controller.spi.Request;
import org.apache.ambari.server.controller.spi.RequestStatus;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.controller.utilities.PredicateBuilder;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
import org.apache.ambari.server.security.TestAuthenticationFactory;
import org.apache.ambari.server.security.authorization.AuthorizationHelper;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.persist.PersistService;
/**
* Tests creation, retrieval and deletion of users using an in-memory database.
* Also tests user creation and retrieval using usernames that differ only by case.
* Verifies that usernames are stored as provided.
*/
@PrepareForTest({AuthorizationHelper.class})
public class UserResourceProviderDBTest {
private static Injector injector;
private static AmbariManagementController amc;
private static Resource.Type userType = Resource.Type.User;
private static UserResourceProvider userResourceProvider;
private static String JDBC_IN_MEMORY_URL_CREATE =
String.format("jdbc:derby:memory:myDB/%s;create=true", Configuration.DEFAULT_DERBY_SCHEMA);
private static String JDBC_IN_MEMORY_URL_DROP =
String.format("jdbc:derby:memory:myDB/%s;drop=true", Configuration.DEFAULT_DERBY_SCHEMA);
/**
* Sets up the in-memory database for the test suite.
*/
@BeforeClass
public static void setupInMemoryDB() {
InMemoryDefaultTestModule testModule = new InMemoryDefaultTestModule();
Properties properties = testModule.getProperties();
properties.setProperty(Configuration.SERVER_JDBC_URL.getKey(), JDBC_IN_MEMORY_URL_CREATE);
properties.setProperty(Configuration.SERVER_JDBC_DRIVER.getKey(), Configuration.JDBC_IN_MEMORY_DRIVER);
injector = Guice.createInjector(testModule);
injector.getInstance(PersistService.class).start();
amc = injector.getInstance(AmbariManagementController.class);
Set<String> propertyIds = PropertyHelper.getPropertyIds(userType);
Map<Resource.Type,String> keyPropertyIds = PropertyHelper.getKeyPropertyIds(userType);
userResourceProvider = new UserResourceProvider(propertyIds, keyPropertyIds, amc);
}
/**
* Closes the JPA connection after executing the test suite.
*/
@AfterClass
public static void teardownInMemoryDB() throws AmbariException, SQLException {
if (injector != null) {
H2DatabaseCleaner.clearDatabaseAndStopPersistenceService(injector);
}
}
/**
* Creates a user, retrieves it and verifies that the username matches the one that was
* created. Deletes the created user and verifies that the username was deleted.
*
* @throws Exception
*/
@Test
public void createUserTest() throws Exception {
Authentication authentication = TestAuthenticationFactory.createAdministrator();
SecurityContextHolder.getContext().setAuthentication(authentication);
// create a new user viewUser
Map<String, Object> requestProperties = new HashMap<>();
requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "viewUser");
requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
RequestStatus requestStatus = userResourceProvider.createResources(request);
assertNotNull(requestStatus);
// verify the created username
Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
Predicate predicate = new PredicateBuilder()
.property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals("viewUser").toPredicate();
Set<Resource> resources = userResourceProvider.getResources(getRequest, predicate);
assertEquals(resources.size(), 1);
Resource resource = resources.iterator().next();
String userName = resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString();
assertEquals(userName, "viewUser");
// delete the created username
requestStatus = userResourceProvider.deleteResources(request, predicate);
assertNotNull(requestStatus);
// verify that the username was deleted
resources = userResourceProvider.getResources(getRequest, null);
assertEquals(resources.size(), 0);
}
/**
* Creates a username in all lowercase. Attempt to add another user whose username differs only
* by case to the previously added user. Verifies that the user cannot be added.
*
* @throws Exception
*/
@Test
public void createExistingUserTest() throws Exception {
Authentication authentication = TestAuthenticationFactory.createAdministrator();
SecurityContextHolder.getContext().setAuthentication(authentication);
/* add a new user */
Map<String, Object> requestProperties = new HashMap<>();
requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "abcd");
requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
RequestStatus requestStatus = userResourceProvider.createResources(request);
assertNotNull(requestStatus);
/* try with uppercase version of an existing user */
requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "ABCD");
request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
try {
requestStatus = userResourceProvider.createResources(request);
assertTrue("Should fail with user exists", false);
}
catch(Exception ex) {
assertTrue(ex.getMessage().contains("User abcd already exists"));
}
// delete the created username
Predicate predicate = new PredicateBuilder()
.property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals("abcd").toPredicate();
requestStatus = userResourceProvider.deleteResources(request, predicate);
assertNotNull(requestStatus);
// verify that the username was deleted
Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
Set<Resource> resources = userResourceProvider.getResources(getRequest, null);
assertEquals(resources.size(), 0);
}
/**
* Creates a user and retrieves the user using the same username but in lowercase. Verifies
* that the retrieval is successful and that the retrieved username is the same as the one
* that was used during creation.
*
* @throws Exception
*/
@Test
public void getExistingUserCaseInsensitiveTest() throws Exception {
Authentication authentication = TestAuthenticationFactory.createAdministrator();
SecurityContextHolder.getContext().setAuthentication(authentication);
// create a new user viewUser
Map<String, Object> requestProperties = new HashMap<>();
requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "viewUser");
requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
RequestStatus requestStatus = userResourceProvider.createResources(request);
assertNotNull(requestStatus);
// verify the created username
Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
Predicate predicate = new PredicateBuilder()
.property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals("viewuser").toPredicate();
Set<Resource> resources = userResourceProvider.getResources(getRequest, predicate);
assertEquals(resources.size(), 1);
Resource resource = resources.iterator().next();
String userName = resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString();
assertEquals(userName, "viewUser");
// delete the created username
requestStatus = userResourceProvider.deleteResources(request, predicate);
assertNotNull(requestStatus);
// verify that the username was deleted
resources = userResourceProvider.getResources(getRequest, null);
assertEquals(resources.size(), 0);
}
/**
* Adds an array of users, retrieves the users and verifies that the usernames do not differ
* from the ones that were used during creation.
*
* @throws Exception
*/
@Test
public void getAllUserTest() throws Exception {
Authentication authentication = TestAuthenticationFactory.createAdministrator();
SecurityContextHolder.getContext().setAuthentication(authentication);
List<String> userNames = Arrays.asList("user1", "uSer2", "User3", "useR4");
for (String userName : userNames) {
Map<String, Object> requestProperties = new HashMap<>();
requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, userName);
requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
RequestStatus requestStatus = userResourceProvider.createResources(request);
assertNotNull(requestStatus);
}
// verify the created username
Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
Set<Resource> resources = userResourceProvider.getResources(getRequest, null);
assertEquals(resources.size(), userNames.size());
for (Resource resource : resources) {
String userName = resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString();
assertTrue(userNames.contains(userName));
}
// delete the users
for (String userName : userNames) {
Predicate predicate = new PredicateBuilder()
.property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals(userName).toPredicate();
RequestStatus requestStatus = userResourceProvider.deleteResources(null /* not used */, predicate);
assertNotNull(requestStatus);
}
// verify that the username was deleted
resources = userResourceProvider.getResources(getRequest, null);
assertEquals(resources.size(), 0);
}
}