blob: fafe79ba01db25edaf6c3facb358b683c583eeba [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.sentry.provider.file;
import static org.apache.sentry.provider.file.PolicyFileConstants.DATABASES;
import static org.apache.sentry.provider.file.PolicyFileConstants.GROUPS;
import static org.apache.sentry.provider.file.PolicyFileConstants.ROLES;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;
/**
* PolicyFile creator. Written specifically to be used with tests. Specifically
* due to the fact that methods that would typically return true or false to
* indicate success or failure these methods throw an unchecked exception.
* This is because in a test if you mean to remove a user from the policy file,
* the user should absolutely be there. If not, the test is mis-behaving.
*/
@VisibleForTesting
public class PolicyFile {
private static final Logger LOGGER = LoggerFactory
.getLogger(PolicyFile.class);
private static final String NL = System.getProperty("line.separator", "\n");
private final Map<String, String> databasesToPolicyFiles = Maps.newHashMap();
private final Multimap<String, String> usersToGroups = ArrayListMultimap.create();
private final Multimap<String, String> groupsToRoles = ArrayListMultimap.create();
private final Multimap<String, String> rolesToPermissions = ArrayListMultimap.create();
public PolicyFile addRolesToGroup(String groupName, String... roleNames) {
return addRolesToGroup(groupName, false, roleNames);
}
public PolicyFile addRolesToGroup(String groupName, boolean allowDuplicates, String... roleNames) {
return add(groupsToRoles.get(groupName), allowDuplicates, roleNames);
}
public PolicyFile addPermissionsToRole(String roleName, String... permissionNames) {
return addPermissionsToRole(roleName, false, permissionNames);
}
public PolicyFile addPermissionsToRole(String roleName, boolean allowDuplicates, String... permissionNames) {
return add(rolesToPermissions.get(roleName), allowDuplicates, permissionNames);
}
public PolicyFile addGroupsToUser(String userName, String... groupNames) {
return addGroupsToUser(userName, false, groupNames);
}
public PolicyFile addGroupsToUser(String userName, boolean allowDuplicates, String... groupNames) {
return add(usersToGroups.get(userName), allowDuplicates, groupNames);
}
public PolicyFile addDatabase(String databaseName, String path) {
String oldPath;
if((oldPath = databasesToPolicyFiles.put(databaseName, path)) != null) {
throw new IllegalStateException("Database " + databaseName + " already existed in " +
databasesToPolicyFiles + " with value of " + oldPath);
}
databasesToPolicyFiles.put(databaseName, path);
return this;
}
public PolicyFile removeRolesFromGroup(String groupName, String... roleNames) {
return remove(groupsToRoles.get(groupName), roleNames);
}
public PolicyFile removePermissionsFromRole(String roleName, String... permissionNames) {
return remove(rolesToPermissions.get(roleName), permissionNames);
}
public PolicyFile removeGroupsFromUser(String userName, String... groupNames) {
return remove(usersToGroups.get(userName), groupNames);
}
public PolicyFile removeDatabase(String databaseName) {
if(databasesToPolicyFiles.remove(databaseName) == null) {
throw new IllegalStateException("Database " + databaseName + " did not exist in " +
databasesToPolicyFiles);
}
return this;
}
public PolicyFile copy() {
PolicyFile other = new PolicyFile();
other.databasesToPolicyFiles.putAll(databasesToPolicyFiles);
other.usersToGroups.putAll(usersToGroups);
other.groupsToRoles.putAll(groupsToRoles);
other.rolesToPermissions.putAll(rolesToPermissions);
return other;
}
public void write(File file) throws IOException {
if(file.exists() && !file.delete()) {
throw new IllegalStateException("Unable to delete " + file);
}
String contents = Joiner.on(NL)
.join(getSection(DATABASES, databasesToPolicyFiles),
getSection(PolicyFileConstants.USERS, usersToGroups),
getSection(GROUPS, groupsToRoles),
getSection(ROLES, rolesToPermissions),
"");
LOGGER.info("Writing policy file to " + file + ":\n" + contents);
Files.write(contents, file, Charsets.UTF_8);
}
private String getSection(String name, Map<String, String> mapping) {
if(mapping.isEmpty()) {
return "";
}
Joiner kvJoiner = Joiner.on(" = ");
List<String> lines = Lists.newArrayList();
lines.add("[" + name + "]");
for(String key : mapping.keySet()) {
lines.add(kvJoiner.join(key, mapping.get(key)));
}
return Joiner.on(NL).join(lines);
}
private String getSection(String name, Multimap<String, String> mapping) {
if(mapping.isEmpty()) {
return "";
}
Joiner kvJoiner = Joiner.on(" = ");
Joiner itemJoiner = Joiner.on(" , ");
List<String> lines = Lists.newArrayList();
lines.add("[" + name + "]");
for(String key : mapping.keySet()) {
lines.add(kvJoiner.join(key, itemJoiner.join(mapping.get(key))));
}
return Joiner.on(NL).join(lines);
}
private PolicyFile remove(Collection<String> exitingItems, String[] newItems) {
for(String newItem : newItems) {
if(!exitingItems.remove(newItem)) {
throw new IllegalStateException("Item " + newItem + " did not exist in " + exitingItems);
}
}
return this;
}
private PolicyFile add(Collection<String> exitingItems, boolean allowDuplicates, String[] newItems) {
for(String newItem : newItems) {
if(exitingItems.contains(newItem) && !allowDuplicates) {
throw new IllegalStateException("Item " + newItem + " already exists in " + exitingItems);
}
exitingItems.add(newItem);
}
return this;
}
public static PolicyFile createAdminOnServer1(String admin) {
return new PolicyFile()
.addGroupsToUser(admin, "admin")
.addRolesToGroup("admin", "admin_role")
.addPermissionsToRole("admin_role", "server=server1");
}
}