blob: 3f7f97c2b5009054bdea5e4e63c3d9c213faf7c8 [file] [log] [blame]
/*
* 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.drill.exec.server;
import com.google.common.base.Joiner;
import com.typesafe.config.ConfigValueFactory;
import org.apache.drill.test.BaseTestQuery;
import org.apache.drill.common.config.DrillProperties;
import org.apache.drill.common.config.DrillConfig;
import org.apache.drill.common.util.DrillStringUtils;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl;
import org.apache.drill.exec.server.options.OptionManager;
import org.apache.drill.exec.util.ImpersonationUtil;
import org.apache.drill.test.ClientFixture;
import org.apache.drill.test.ClusterFixture;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl.ADMIN_GROUP;
import static org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl.ADMIN_USER;
import static org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl.ADMIN_USER_PASSWORD;
import static org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl.PROCESS_USER;
import static org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl.PROCESS_USER_PASSWORD;
import static org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl.TEST_USER_1;
import static org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl.TEST_USER_1_PASSWORD;
import static org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl.TEST_USER_2;
import static org.apache.drill.exec.rpc.user.security.testing.UserAuthenticatorTestImpl.TEST_USER_2_PASSWORD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import java.util.Properties;
/**
* Test setting system scoped options with user authentication enabled. (DRILL-3622)
*/
public class TestOptionsAuthEnabled extends BaseTestQuery {
private static final String setSysOptionQuery =
String.format("ALTER SYSTEM SET `%s` = %d;", ExecConstants.SLICE_TARGET, 200);
@BeforeClass
public static void setupCluster() throws Exception {
// Create a new DrillConfig which has user authentication enabled and test authenticator set
final DrillConfig config = new DrillConfig(DrillConfig.create(cloneDefaultTestConfigProperties())
.withValue(ExecConstants.USER_AUTHENTICATION_ENABLED, ConfigValueFactory.fromAnyRef(true))
.withValue(ExecConstants.USER_AUTHENTICATOR_IMPL,
ConfigValueFactory.fromAnyRef(UserAuthenticatorTestImpl.TYPE)));
final Properties connectionProps = new Properties();
connectionProps.setProperty(DrillProperties.USER, PROCESS_USER);
connectionProps.setProperty(DrillProperties.PASSWORD, PROCESS_USER_PASSWORD);
updateTestCluster(1, config, connectionProps);
// Add user "admin" to admin username list
test(String.format("ALTER SYSTEM SET `%s`='%s,%s'", ExecConstants.ADMIN_USERS_KEY, ADMIN_USER, PROCESS_USER));
// Set "admingrp" to admin username list
test(String.format("ALTER SYSTEM SET `%s`='%s'", ExecConstants.ADMIN_USER_GROUPS_KEY, ADMIN_GROUP));
}
@Test
public void updateSysOptAsAdminUser() throws Exception {
updateClient(ADMIN_USER, ADMIN_USER_PASSWORD);
setOptHelper();
}
@Test
public void updateSysOptAsNonAdminUser() throws Exception {
updateClient(TEST_USER_2, TEST_USER_2_PASSWORD);
errorMsgTestHelper(setSysOptionQuery, "Not authorized to change SYSTEM options.");
}
@Test
public void updateSysOptAsUserInAdminGroup() throws Exception {
updateClient(TEST_USER_1, TEST_USER_1_PASSWORD);
setOptHelper();
}
@Test
public void trySettingAdminOptsAtSessionScopeAsAdmin() throws Exception {
updateClient(ADMIN_USER, ADMIN_USER_PASSWORD);
final String setOptionQuery =
String.format("ALTER SESSION SET `%s`='%s,%s'", ExecConstants.ADMIN_USERS_KEY, ADMIN_USER, PROCESS_USER);
errorMsgTestHelper(setOptionQuery, "PERMISSION ERROR: Cannot change option security.admin.users in scope SESSION");
}
@Test
public void trySettingAdminOptsAtSessionScopeAsNonAdmin() throws Exception {
updateClient(TEST_USER_2, TEST_USER_2_PASSWORD);
final String setOptionQuery =
String.format("ALTER SESSION SET `%s`='%s,%s'", ExecConstants.ADMIN_USERS_KEY, ADMIN_USER, PROCESS_USER);
errorMsgTestHelper(setOptionQuery, "PERMISSION ERROR: Cannot change option security.admin.users in scope SESSION");
}
private void setOptHelper() throws Exception {
try {
test(setSysOptionQuery);
testBuilder()
.sqlQuery(String.format("SELECT val FROM sys.options WHERE name = '%s' AND optionScope = 'SYSTEM'",
ExecConstants.SLICE_TARGET))
.unOrdered()
.baselineColumns("val")
.baselineValues(String.valueOf(200L))
.go();
} finally {
test(String.format("ALTER SYSTEM SET `%s` = %d;", ExecConstants.SLICE_TARGET, ExecConstants.SLICE_TARGET_DEFAULT));
}
}
@Test
public void testAdminUserOptions() throws Exception {
try (ClusterFixture cluster = ClusterFixture.standardCluster(dirTestWatcher);
ClientFixture client = cluster.clientFixture()) {
OptionManager optionManager = cluster.drillbit().getContext().getOptionManager();
// Admin Users Tests
// config file should have the 'fake' default admin user and it should be returned
// by the option manager if the option has not been set by the user
String configAdminUser = optionManager.getOption(ExecConstants.ADMIN_USERS_VALIDATOR);
assertEquals(configAdminUser, ExecConstants.ADMIN_USERS_VALIDATOR.DEFAULT_ADMIN_USERS);
// Option accessor should never return the 'fake' default from the config
String adminUser1 = ExecConstants.ADMIN_USERS_VALIDATOR.getAdminUsers(optionManager);
assertNotEquals(adminUser1, ExecConstants.ADMIN_USERS_VALIDATOR.DEFAULT_ADMIN_USERS);
// Change testAdminUser if necessary
String testAdminUser = "ronswanson";
if (adminUser1.equals(testAdminUser)) {
testAdminUser += "thefirst";
}
// Check if the admin option accessor honors a user-supplied value
client.alterSystem(ExecConstants.ADMIN_USERS_KEY, testAdminUser);
String adminUser2 = ExecConstants.ADMIN_USERS_VALIDATOR.getAdminUsers(optionManager);
assertEquals(adminUser2, testAdminUser);
// Ensure that the default admin users have admin privileges
client.resetSystem(ExecConstants.ADMIN_USERS_KEY);
client.resetSystem(ExecConstants.ADMIN_USER_GROUPS_KEY);
String systemAdminUsersList0 = ExecConstants.ADMIN_USERS_VALIDATOR.getAdminUsers(optionManager);
String systemAdminUserGroupsList0 = ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.getAdminUserGroups(optionManager);
for (String user : systemAdminUsersList0.split(",")) {
assertTrue(ImpersonationUtil.hasAdminPrivileges(user, systemAdminUsersList0, systemAdminUserGroupsList0));
}
// test if admin users, set by the user, have admin privileges
// test if we can handle a user-supplied list that is not well formatted
String crummyTestAdminUsersList = " alice, bob bob, charlie ,, dave ";
client.alterSystem(ExecConstants.ADMIN_USERS_KEY, crummyTestAdminUsersList);
String[] sanitizedAdminUsers = {"alice", "bob bob", "charlie", "dave"};
// also test the CSV sanitizer
assertEquals(Joiner.on(",").join(sanitizedAdminUsers), DrillStringUtils.sanitizeCSV(crummyTestAdminUsersList));
String systemAdminUsersList1 = ExecConstants.ADMIN_USERS_VALIDATOR.getAdminUsers(optionManager);
String systemAdminUserGroupsList1 = ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.getAdminUserGroups(optionManager);
for (String user : sanitizedAdminUsers) {
assertTrue(ImpersonationUtil.hasAdminPrivileges(user, systemAdminUsersList1, systemAdminUserGroupsList1));
}
// Admin User Groups Tests
// config file should have the 'fake' default admin user and it should be returned
// by the option manager if the option has not been set by the user
String configAdminUserGroups = optionManager.getOption(ExecConstants.ADMIN_USER_GROUPS_VALIDATOR);
assertEquals(configAdminUserGroups, ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.DEFAULT_ADMIN_USER_GROUPS);
// Option accessor should never return the 'fake' default from the config
String adminUserGroups1 = ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.getAdminUserGroups(optionManager);
assertNotEquals(adminUserGroups1, ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.DEFAULT_ADMIN_USER_GROUPS);
// Change testAdminUserGroups if necessary
String testAdminUserGroups = "yakshavers";
if (adminUserGroups1.equals(testAdminUserGroups)) {
testAdminUserGroups += ",wormracers";
}
// Check if the admin option accessor honors a user-supplied values
client.alterSystem(ExecConstants.ADMIN_USER_GROUPS_KEY, testAdminUserGroups);
String adminUserGroups2 = ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.getAdminUserGroups(optionManager);
assertEquals(adminUserGroups2, testAdminUserGroups);
// Test if we can handle a user-supplied admin user groups list that is not well formatted
String crummyTestAdminUserGroupsList = " g1, g 2, g4 ,, g5 ";
client.alterSystem(ExecConstants.ADMIN_USER_GROUPS_KEY, crummyTestAdminUserGroupsList);
String systemAdminUserGroupsList2 = ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.getAdminUserGroups(optionManager);
// test if all the group tokens are well-formed
// Note: A hasAdminPrivilege() test cannot be done here, like in the tests for handling a crummy admin user list.
// This is because ImpersonationUtil currently does not implement an API that takes a group as an input to check
// for admin privileges
for (String group : systemAdminUserGroupsList2.split(",")) {
assertTrue(group.length() != 0);
assertTrue(group.trim().equals(group));
}
}
}
}