/*
* Copyright (C) 2015 hops.io.
*
* 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 io.hops.security;
import com.google.common.collect.Lists;
import io.hops.metadata.HdfsStorageFactory;
import io.hops.metadata.hdfs.dal.GroupDataAccess;
import io.hops.metadata.hdfs.dal.UserDataAccess;
import io.hops.metadata.hdfs.entity.Group;
import io.hops.metadata.hdfs.entity.User;
import io.hops.transaction.handler.HDFSOperationType;
import io.hops.transaction.handler.LightWeightRequestHandler;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.HdfsConfiguration;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.ipc.RemoteException;
import org.junit.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
public class TestUsersGroups {
@Test
public void testUsersGroupsCache(){
UsersGroupsCache cache = new UsersGroupsCache(10);
User currentUser = new User(1, "user0");
List<Group> groups = Lists.newArrayList();
for(int i=1; i< 10; i++){
groups.add(new Group(i, "group"+i));
}
//user1 -> {group1, group2}
cache.addUserGroups(currentUser, groups.subList(0, 2));
Integer userId = cache.getUserId(currentUser.getName());
assertNotNull(userId);
assertEquals((int)userId, currentUser.getId());
for(int i=0; i<2; i++){
Integer groupId = cache.getGroupId(groups.get(i).getName());
assertNotNull(groupId);
assertEquals((int)groupId, groups.get(i).getId());
}
assertNull(cache.getGroupId(groups.get(2).getName()));
List<String> cachedGroups = cache.getGroups(currentUser.getName());
assertNotNull(cachedGroups);
assertTrue(cachedGroups.equals(Arrays.asList(groups.get(0).getName(),
groups.get(1).getName())));
//remove group by name [group1]
cache.removeGroup(groups.get(0).getName());
Integer groupId = cache.getGroupId(groups.get(0).getName());
assertNull(groupId);
cachedGroups = cache.getGroups(currentUser.getName());
assertNotNull(cachedGroups);
assertTrue(cachedGroups.equals(Arrays.asList(groups.get(1).getName())));
//remove group by id [2]
cache.removeGroup(groups.get(1).getId());
String groupName = cache.getGroupName(groups.get(1).getId());
assertNull(groupName);
cachedGroups = cache.getGroups(currentUser.getName());
assertNull(cachedGroups);
//add group [3]
cache.addGroup(groups.get(2));
groupId = cache.getGroupId(groups.get(2).getName());
assertNotNull(groupId);
assertEquals((int)groupId, groups.get(2).getId());
cachedGroups = cache.getGroups(currentUser.getName());
assertNull(cachedGroups);
// append group to user: user1 -> {group3}
cache.appendUserGroups(currentUser.getName(), Arrays.asList(groups.get(2)
.getName()));
cachedGroups = cache.getGroups(currentUser.getName());
assertNotNull(cachedGroups);
assertTrue(cachedGroups.equals(Arrays.asList(groups.get(2).getName())));
UsersGroups.stop();
}
@Test
public void testCacheEviction(){
final int CACHE_SIZE = 5;
UsersGroupsCache cache = new UsersGroupsCache(CACHE_SIZE);
List<User> users = Lists.newArrayList();
List<Group> groups = Lists.newArrayList();
List<String> groupNames = Lists.newArrayList();
for(int i=1; i<=CACHE_SIZE; i++){
users.add(new User(i, "user"+ i));
String groupName = "group" + i;
groups.add(new Group(i, groupName));
groupNames.add(groupName);
}
for(int i=0; i<CACHE_SIZE; i++){
cache.addUserGroups(users.get(i), groups.subList(i, (i==CACHE_SIZE - 1 ?
i + 1 : i + 2)));
}
for(int i=0; i<CACHE_SIZE; i++){
List<String> cachedGroups = cache.getGroups(users.get(i).getName());
assertNotNull(cachedGroups);
assertTrue(cachedGroups.equals(groupNames.subList(i, (i==CACHE_SIZE - 1 ?
i + 1 : i + 2))));
}
// add a new user to check eviction
User newUser = new User(CACHE_SIZE + 1, "newUser");
cache.addUser(newUser);
Integer userId = cache.getUserId(newUser.getName());
assertNotNull(userId);
assertEquals((int)userId, newUser.getId());
userId = cache.getUserId(users.get(0).getName());
assertNull(userId);
List<String> cachedGroups = cache.getGroups(users.get(0).getName());
assertNull(cachedGroups);
// group1 should be removed since it is associated with only user1
Integer groupId = cache.getGroupId(groups.get(0).getName());
assertNull("Cache eviction should remove " + groups.get(0)
.getName(), groupId);
// group2 shouldn't be removed since it is associated with user1 and user2
groupId = cache.getGroupId(groups.get(1).getName());
assertNotNull("Cache eviction shouldn't remove " + groups.get(1)
.getName(), groupId);
//add 2 new group
Group newGroup1 = new Group(CACHE_SIZE+1, "newgroup1");
Group newGroup2 = new Group(CACHE_SIZE+2, "newgroup2");
cache.addGroup(newGroup1);
groupId = cache.getGroupId(newGroup1.getName());
assertNotNull(groupId);
assertEquals((int) groupId, newGroup1.getId());
cache.addGroup(newGroup2);
groupId = cache.getGroupId(newGroup2.getName());
assertNotNull(groupId);
assertEquals((int) groupId, newGroup2.getId());
// group2 should be removed
groupId = cache.getGroupId(groups.get(1).getName());
assertNull("Cache eviction should remove " + groups.get(1)
.getName(), groupId);
//user2 associated with group2 should be removed
userId = cache.getUserId(users.get(1).getName());
assertNull("Cache eviction should remove all users associated with " +
"a removed group ", userId);
// group3 shouldn't be removed since it is associated with user2 and user3
groupId = cache.getGroupId(groups.get(2).getName());
assertNotNull("Cache eviction shouldn't remove " + groups.get(2)
.getName(), groupId);
//user3 shouldn't be removed
userId = cache.getUserId(users.get(2).getName());
assertNotNull("Cache eviction shouldn't remove " + users.get(2).getName()
+" since it wasn't associated with " + groups.get(1).getName(),
userId);
cachedGroups = cache.getGroups(users.get(2).getName());
assertNotNull(cachedGroups);
assertEquals(cachedGroups, Arrays.asList(groups.get(2).getName(), groups
.get(3).getName()));
//add another group
Group newGroup3 = new Group(CACHE_SIZE+3, "newgroup3");
cache.addGroup(newGroup3);
groupId = cache.getGroupId(newGroup1.getName());
assertNotNull(groupId);
assertEquals((int) groupId, newGroup1.getId());
//group3 should be removed
groupId = cache.getGroupId(groups.get(2).getName());
assertNull("Cache eviction should remove " + groups.get(2)
.getName(), groupId);
//user3 should be removed
userId = cache.getUserId(users.get(2).getName());
assertNull("Cache eviction should remove all users associated with " +
"a removed group ", userId);
}
@Test
public void testUsersGroupsNotConfigurad() throws IOException {
UsersGroups.addUserToGroups("user", new String[]{"group1", "group2"});
assertEquals(UsersGroups.getGroupID("group1"), 0);
assertEquals(UsersGroups.getUserID("user"), 0);
UsersGroups.stop();
}
@Test
public void testAddUsers() throws IOException {
Configuration conf = new Configuration();
conf.setInt(CommonConfigurationKeys.HOPS_GROUPS_UPDATER_ROUND, 10);
HdfsStorageFactory.resetDALInitialized();
HdfsStorageFactory.setConfiguration(conf);
HdfsStorageFactory.formatStorage();
UsersGroups.addUserToGroupsTx("user", new String[]{"group1", "group2"});
int userId = UsersGroups.getUserID("user");
assertNotSame(0, userId);
assertEquals(UsersGroups.getUser(userId), "user");
int groupId = UsersGroups.getGroupID("group1");
assertNotSame(0, groupId);
assertEquals(UsersGroups.getGroup(groupId), "group1");
assertEquals(UsersGroups.getGroups("user"), Arrays.asList("group1",
"group2"));
removeUser(userId);
userId = UsersGroups.getUserID("user");
assertNotSame(0, userId);
//Wait for the group updater to kick in
try {
Thread.sleep(10500);
} catch (InterruptedException e) {
e.printStackTrace();
}
userId = UsersGroups.getUserID("user");
assertEquals(0, userId);
assertNull(UsersGroups.getGroups("user"));
UsersGroups.addUserToGroupsTx("user", new String[]{"group1",
"group2"});
userId = UsersGroups.getUserID("user");
assertNotSame(0, userId);
assertEquals(Arrays.asList("group1", "group2"), UsersGroups.getGroups("user"));
removeUser(userId);
UsersGroups.addUserToGroupsTx("user", new String[]{"group3"});
int newUserId = UsersGroups.getUserID("user");
assertNotSame(0, userId);
//Auto incremented Ids
assertTrue(newUserId > userId);
UsersGroups.addUserToGroupsTx("user", new String[]{"group1",
"group2"});
assertEquals(Arrays.asList("group3",
"group1", "group2"), UsersGroups.getGroups("user"));
UsersGroups.stop();
}
@Test
public void testGroupMappingsRefresh() throws IOException {
Configuration conf = new HdfsConfiguration();
MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1)
.build();
cluster.waitActive();
cluster.getNameNode().getRpcServer().refreshUserToGroupsMappings();
UsersGroups.addUserToGroupsTx("user", new String[]{"group1", "group2"});
int userId = UsersGroups.getUserID("user");
assertNotSame(0, userId);
assertEquals(UsersGroups.getUser(userId), "user");
int groupId = UsersGroups.getGroupID("group1");
assertNotSame(0, groupId);
assertEquals(UsersGroups.getGroup(groupId), "group1");
assertEquals(UsersGroups.getGroups("user"), Arrays.asList("group1",
"group2"));
removeUser(userId);
userId = UsersGroups.getUserID("user");
assertNotSame(0, userId);
cluster.getNameNode().getRpcServer().refreshUserToGroupsMappings();
userId = UsersGroups.getUserID("user");
assertEquals(0, userId);
assertNull(UsersGroups.getGroups("user"));
UsersGroups.addUserToGroupsTx("user", new String[]{"group1",
"group2"});
userId = UsersGroups.getUserID("user");
assertNotSame(0, userId);
assertEquals(Arrays.asList("group1", "group2"), UsersGroups.getGroups("user"));
removeUser(userId);
UsersGroups.addUserToGroupsTx("user", new String[]{"group3"});
int newUserId = UsersGroups.getUserID("user");
assertNotSame(0, userId);
//Auto incremented Ids
assertTrue(newUserId > userId);
UsersGroups.addUserToGroupsTx("user", new String[]{"group1",
"group2"});
assertEquals(Arrays.asList("group3",
"group1", "group2"), UsersGroups.getGroups("user"));
cluster.shutdown();
}
@Test
public void setOwnerMultipleTimes() throws IOException {
Configuration conf = new HdfsConfiguration();
MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1)
.build();
cluster.waitActive();
DistributedFileSystem dfs = cluster.getFileSystem();
Path base = new Path("/projects/project1");
dfs.mkdirs(base);
Path child = new Path(base, "dataset");
dfs.mkdirs(child);
dfs.setOwner(base, "testUser", "testGroup");
removeGroup(UsersGroups.getGroupID("testGroup"));
dfs.flushCacheGroup("testGroup");
dfs.setOwner(base, "testUser", "testGroup");
cluster.shutdown();
}
private void removeUser(final int userId) throws IOException {
new LightWeightRequestHandler(
HDFSOperationType.TEST) {
@Override
public Object performTask() throws IOException {
UserDataAccess da = (UserDataAccess) HdfsStorageFactory.getDataAccess(UserDataAccess
.class);
da.removeUser(userId);
return null;
}
}.handle();
}
private void removeGroup(final int groupId) throws IOException {
new LightWeightRequestHandler(
HDFSOperationType.TEST) {
@Override
public Object performTask() throws IOException {
GroupDataAccess da = (GroupDataAccess) HdfsStorageFactory.getDataAccess
(GroupDataAccess.class);
da.removeGroup(groupId);
return null;
}
}.handle();
}
}