/*
* 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.nifi.authorization;
import org.apache.nifi.authorization.file.generated.Authorizations;
import org.apache.nifi.authorization.file.generated.Policies;
import org.apache.nifi.authorization.file.tenants.generated.Groups;
import org.apache.nifi.authorization.file.tenants.generated.Tenants;
import org.apache.nifi.authorization.file.tenants.generated.Users;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* A holder to provide atomic access to data structures.
*/
public class AuthorizationsHolder implements UsersAndAccessPolicies {
private final Tenants tenants;
private final Authorizations authorizations;
private final Set<AccessPolicy> allPolicies;
private final Map<String, Set<AccessPolicy>> policiesByResource;
private final Map<String, AccessPolicy> policiesById;
private final Set<User> allUsers;
private final Map<String,User> usersById;
private final Map<String,User> usersByIdentity;
private final Set<Group> allGroups;
private final Map<String,Group> groupsById;
private final Map<String, Set<Group>> groupsByUserIdentity;
/**
* Creates a new holder and populates all convenience data structures.
*
* @param authorizations the current authorizations instance
*/
public AuthorizationsHolder(final Authorizations authorizations, final Tenants tenants) {
this.authorizations = authorizations;
this.tenants = tenants;
// load all users
final Users users = tenants.getUsers();
final Set<User> allUsers = Collections.unmodifiableSet(createUsers(users));
// load all groups
final Groups groups = tenants.getGroups();
final Set<Group> allGroups = Collections.unmodifiableSet(createGroups(groups, users));
// load all access policies
final Policies policies = authorizations.getPolicies();
final Set<AccessPolicy> allPolicies = Collections.unmodifiableSet(createAccessPolicies(policies));
// create a convenience map to retrieve a user by id
final Map<String, User> userByIdMap = Collections.unmodifiableMap(createUserByIdMap(allUsers));
// create a convenience map to retrieve a user by identity
final Map<String, User> userByIdentityMap = Collections.unmodifiableMap(createUserByIdentityMap(allUsers));
// create a convenience map to retrieve a group by id
final Map<String, Group> groupByIdMap = Collections.unmodifiableMap(createGroupByIdMap(allGroups));
// create a convenience map to retrieve the groups for a user identity
final Map<String, Set<Group>> groupsByUserIdentityMap = Collections.unmodifiableMap(createGroupsByUserIdentityMap(allGroups, allUsers));
// create a convenience map from resource id to policies
final Map<String, Set<AccessPolicy>> policiesByResourceMap = Collections.unmodifiableMap(createResourcePolicyMap(allPolicies));
// create a convenience map from policy id to policy
final Map<String, AccessPolicy> policiesByIdMap = Collections.unmodifiableMap(createPoliciesByIdMap(allPolicies));
// set all the holders
this.allUsers = allUsers;
this.allGroups = allGroups;
this.allPolicies = allPolicies;
this.usersById = userByIdMap;
this.usersByIdentity = userByIdentityMap;
this.groupsById = groupByIdMap;
this.groupsByUserIdentity = groupsByUserIdentityMap;
this.policiesByResource = policiesByResourceMap;
this.policiesById = policiesByIdMap;
}
/**
* Creates AccessPolicies from the JAXB Policies.
*
* @param policies the JAXB Policies element
* @return a set of AccessPolicies corresponding to the provided Resources
*/
private Set<AccessPolicy> createAccessPolicies(org.apache.nifi.authorization.file.generated.Policies policies) {
Set<AccessPolicy> allPolicies = new HashSet<>();
if (policies == null || policies.getPolicy() == null) {
return allPolicies;
}
// load the new authorizations
for (final org.apache.nifi.authorization.file.generated.Policy policy : policies.getPolicy()) {
final String policyIdentifier = policy.getIdentifier();
final String resourceIdentifier = policy.getResource();
// start a new builder and set the policy and resource identifiers
final AccessPolicy.Builder builder = new AccessPolicy.Builder()
.identifier(policyIdentifier)
.resource(resourceIdentifier);
// add each user identifier
for (org.apache.nifi.authorization.file.generated.Policy.User user : policy.getUser()) {
builder.addUser(user.getIdentifier());
}
// add each group identifier
for (org.apache.nifi.authorization.file.generated.Policy.Group group : policy.getGroup()) {
builder.addGroup(group.getIdentifier());
}
// add the appropriate request actions
final String authorizationCode = policy.getAction();
if (authorizationCode.equals(FileAuthorizer.READ_CODE)) {
builder.action(RequestAction.READ);
} else if (authorizationCode.equals(FileAuthorizer.WRITE_CODE)){
builder.action(RequestAction.WRITE);
} else {
throw new IllegalStateException("Unknown Policy Action: " + authorizationCode);
}
// build the policy and add it to the map
allPolicies.add(builder.build());
}
return allPolicies;
}
/**
* Creates a set of Users from the JAXB Users.
*
* @param users the JAXB Users
* @return a set of API Users matching the provided JAXB Users
*/
private Set<User> createUsers(org.apache.nifi.authorization.file.tenants.generated.Users users) {
Set<User> allUsers = new HashSet<>();
if (users == null || users.getUser() == null) {
return allUsers;
}
for (org.apache.nifi.authorization.file.tenants.generated.User user : users.getUser()) {
final User.Builder builder = new User.Builder()
.identity(user.getIdentity())
.identifier(user.getIdentifier());
allUsers.add(builder.build());
}
return allUsers;
}
/**
* Creates a set of Groups from the JAXB Groups.
*
* @param groups the JAXB Groups
* @return a set of API Groups matching the provided JAXB Groups
*/
private Set<Group> createGroups(org.apache.nifi.authorization.file.tenants.generated.Groups groups,
org.apache.nifi.authorization.file.tenants.generated.Users users) {
Set<Group> allGroups = new HashSet<>();
if (groups == null || groups.getGroup() == null) {
return allGroups;
}
for (org.apache.nifi.authorization.file.tenants.generated.Group group : groups.getGroup()) {
final Group.Builder builder = new Group.Builder()
.identifier(group.getIdentifier())
.name(group.getName());
for (org.apache.nifi.authorization.file.tenants.generated.Group.User groupUser : group.getUser()) {
builder.addUser(groupUser.getIdentifier());
}
allGroups.add(builder.build());
}
return allGroups;
}
/**
* Creates a map from resource identifier to the set of policies for the given resource.
*
* @param allPolicies the set of all policies
* @return a map from resource identifier to policies
*/
private Map<String, Set<AccessPolicy>> createResourcePolicyMap(final Set<AccessPolicy> allPolicies) {
Map<String, Set<AccessPolicy>> resourcePolicies = new HashMap<>();
for (AccessPolicy policy : allPolicies) {
Set<AccessPolicy> policies = resourcePolicies.get(policy.getResource());
if (policies == null) {
policies = new HashSet<>();
resourcePolicies.put(policy.getResource(), policies);
}
policies.add(policy);
}
return resourcePolicies;
}
/**
* Creates a Map from user identifier to User.
*
* @param users the set of all users
* @return the Map from user identifier to User
*/
private Map<String,User> createUserByIdMap(final Set<User> users) {
Map<String,User> usersMap = new HashMap<>();
for (User user : users) {
usersMap.put(user.getIdentifier(), user);
}
return usersMap;
}
/**
* Creates a Map from user identity to User.
*
* @param users the set of all users
* @return the Map from user identity to User
*/
private Map<String,User> createUserByIdentityMap(final Set<User> users) {
Map<String,User> usersMap = new HashMap<>();
for (User user : users) {
usersMap.put(user.getIdentity(), user);
}
return usersMap;
}
/**
* Creates a Map from group identifier to Group.
*
* @param groups the set of all groups
* @return the Map from group identifier to Group
*/
private Map<String,Group> createGroupByIdMap(final Set<Group> groups) {
Map<String,Group> groupsMap = new HashMap<>();
for (Group group : groups) {
groupsMap.put(group.getIdentifier(), group);
}
return groupsMap;
}
/**
* Creates a Map from user identity to the set of Groups for that identity.
*
* @param groups all groups
* @param users all users
* @return a Map from User identity to the set of Groups for that identity
*/
private Map<String, Set<Group>> createGroupsByUserIdentityMap(final Set<Group> groups, final Set<User> users) {
Map<String, Set<Group>> groupsByUserIdentity = new HashMap<>();
for (User user : users) {
Set<Group> userGroups = new HashSet<>();
for (Group group : groups) {
for (String groupUser : group.getUsers()) {
if (groupUser.equals(user.getIdentifier())) {
userGroups.add(group);
}
}
}
groupsByUserIdentity.put(user.getIdentity(), userGroups);
}
return groupsByUserIdentity;
}
/**
* Creates a Map from policy identifier to AccessPolicy.
*
* @param policies the set of all access policies
* @return the Map from policy identifier to AccessPolicy
*/
private Map<String, AccessPolicy> createPoliciesByIdMap(final Set<AccessPolicy> policies) {
Map<String,AccessPolicy> policyMap = new HashMap<>();
for (AccessPolicy policy : policies) {
policyMap.put(policy.getIdentifier(), policy);
}
return policyMap;
}
public Authorizations getAuthorizations() {
return authorizations;
}
public Tenants getTenants() {
return tenants;
}
public Set<AccessPolicy> getAllPolicies() {
return allPolicies;
}
public Map<String, Set<AccessPolicy>> getPoliciesByResource() {
return policiesByResource;
}
public Map<String, AccessPolicy> getPoliciesById() {
return policiesById;
}
public Set<User> getAllUsers() {
return allUsers;
}
public Map<String, User> getUsersById() {
return usersById;
}
public Map<String, User> getUsersByIdentity() {
return usersByIdentity;
}
public Set<Group> getAllGroups() {
return allGroups;
}
public Map<String, Group> getGroupsById() {
return groupsById;
}
@Override
public AccessPolicy getAccessPolicy(final String resourceIdentifier, final RequestAction action) {
if (resourceIdentifier == null) {
throw new IllegalArgumentException("Resource Identifier cannot be null");
}
final Set<AccessPolicy> resourcePolicies = policiesByResource.get(resourceIdentifier);
if (resourcePolicies == null) {
return null;
}
for (AccessPolicy accessPolicy : resourcePolicies) {
if (accessPolicy.getAction() == action) {
return accessPolicy;
}
}
return null;
}
@Override
public User getUser(String identity) {
if (identity == null) {
throw new IllegalArgumentException("Identity cannot be null");
}
return usersByIdentity.get(identity);
}
@Override
public Set<Group> getGroups(String userIdentity) {
if (userIdentity == null) {
throw new IllegalArgumentException("User Identity cannot be null");
}
return groupsByUserIdentity.get(userIdentity);
}
}