| /* |
| * 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"); |
| } |
| } |