NIFI-1952 Create REST endpoints for user/group/policy management

created REST Resources for users, groups, and access policies
added Authorizables for users, groups, and access policies
added methods to DtoFactory and EntityFactory to create objects for users, groups, and access policies
extracted anonymous AuthorizableLookup impl in StandardNiFiServiceFacade.java to a protected class to make the lookup call mockable in tests
added methods to manage users/groups/access policies to StandardNiFiServiceFacade
added StandardNiFiServiceFacadeSpec to unit-test management of users/groups/access policies
added implementations for UserDAO, GroupDAO, AccessPolicyDAO.
added spring config for user/group/policy resources and daos
Updated user/group/policy creation via REST resources, no longer requires the use of the revision manager
updated StandardNiFiServiceFacadeSpec based on user/group/policy creation changes
condensed user/group/policy DAOs to a single DAO (StandardPolicyBasedAuthorizerDAO)
fixed spring config of user/group/policy REST resources
Updated to return ComponentEntity objects instead of just their IDs
mid-progress on updating tests
updated code and tests to return component entities from REST endpoints for users, groups, policies
This closes #526
This commit is contained in:
Jeff Storck 2016-06-02 16:33:05 -04:00 committed by Matt Gilman
parent 32facaedb4
commit f47be77b6a
29 changed files with 3879 additions and 347 deletions

View File

@ -24,7 +24,7 @@ import java.util.Set;
/**
* A group that users can belong to.
*/
public class Group {
public class Group { // TODO rename to UserGroup
private final String identifier;

View File

@ -47,6 +47,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Factory bean for loading the configured authorizer.
@ -287,35 +288,180 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho
* @return authorizer
*/
public Authorizer withNarLoader(final Authorizer baseAuthorizer) {
return new Authorizer() {
@Override
public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseAuthorizer.authorize(request);
if (baseAuthorizer instanceof AbstractPolicyBasedAuthorizer) {
AbstractPolicyBasedAuthorizer policyBasedAuthorizer = (AbstractPolicyBasedAuthorizer) baseAuthorizer;
return new AbstractPolicyBasedAuthorizer() {
@Override
public Group addGroup(Group group) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.addGroup(group);
}
}
}
@Override
public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAuthorizer.initialize(initializationContext);
@Override
public Group getGroup(String identifier) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.getGroup(identifier);
}
}
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAuthorizer.onConfigured(configurationContext);
@Override
public Group updateGroup(Group group) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.updateGroup(group);
}
}
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAuthorizer.preDestruction();
@Override
public Group deleteGroup(Group group) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.deleteGroup(group);
}
}
}
};
@Override
public Set<Group> getGroups() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.getGroups();
}
}
@Override
public User addUser(User user) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.addUser(user);
}
}
@Override
public User getUser(String identifier) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.getUser(identifier);
}
}
@Override
public User getUserByIdentity(String identity) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.getUserByIdentity(identity);
}
}
@Override
public User updateUser(User user) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.updateUser(user);
}
}
@Override
public User deleteUser(User user) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.deleteUser(user);
}
}
@Override
public Set<User> getUsers() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.getUsers();
}
}
@Override
public AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.addAccessPolicy(accessPolicy);
}
}
@Override
public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.getAccessPolicy(identifier);
}
}
@Override
public AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.updateAccessPolicy(accessPolicy);
}
}
@Override
public AccessPolicy deleteAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.deleteAccessPolicy(accessPolicy);
}
}
@Override
public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.getAccessPolicies();
}
}
@Override
public UsersAndAccessPolicies getUsersAndAccessPolicies() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return policyBasedAuthorizer.getUsersAndAccessPolicies();
}
}
@Override
public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
policyBasedAuthorizer.initialize(initializationContext);
}
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
policyBasedAuthorizer.onConfigured(configurationContext);
}
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAuthorizer.preDestruction();
}
}
};
} else {
return new Authorizer() {
@Override
public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseAuthorizer.authorize(request);
}
}
@Override
public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAuthorizer.initialize(initializationContext);
}
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAuthorizer.onConfigured(configurationContext);
}
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAuthorizer.preDestruction();
}
}
};
}
}
@Override

View File

@ -17,15 +17,21 @@
package org.apache.nifi.web.api.dto;
import com.wordnik.swagger.annotations.ApiModelProperty;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import javax.xml.bind.annotation.XmlType;
import java.util.Set;
/**
* Details for the access configuration.
*/
@XmlType(name = "accessPolicy")
public class AccessPolicyDTO {
public class AccessPolicyDTO extends ComponentDTO {
private String resource;
private Set<UserEntity> users;
private Set<UserGroupEntity> userGroups;
private Boolean canRead;
private Boolean canWrite;
@ -59,4 +65,39 @@ public class AccessPolicyDTO {
this.canWrite = canWrite;
}
/**
* @return The resource ID for this access policy.
*/
@ApiModelProperty(value="The resource ID for this access policy.")
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
/**
* @return The set of user IDs associated with this access policy.
*/
@ApiModelProperty(value = "The set of user IDs associated with this access policy.")
public Set<UserEntity> getUsers() {
return users;
}
public void setUsers(Set<UserEntity> users) {
this.users = users;
}
/**
* @return The set of user group IDs associated with this access policy.
*/
@ApiModelProperty(value = "The set of user group IDs associated with this access policy.")
public Set<UserGroupEntity> getUserGroups() {
return userGroups;
}
public void setUserGroups(Set<UserGroupEntity> userGroups) {
this.userGroups = userGroups;
}
}

View File

@ -17,171 +17,43 @@
package org.apache.nifi.web.api.dto;
import com.wordnik.swagger.annotations.ApiModelProperty;
import java.util.Date;
import java.util.Set;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.nifi.web.api.dto.util.DateTimeAdapter;
import java.util.Set;
/**
* A user of this NiFi.
*/
@XmlType(name = "user")
public class UserDTO {
public class UserDTO extends ComponentDTO {
private String id;
private String dn;
private String userName;
private String userGroup;
private String justification;
private Date creation;
private String status;
private Date lastVerified;
private Date lastAccessed;
private Set<String> authorities;
private String identity;
private Set<UserGroupEntity> groups;
/**
* @return user id
* @return users identity
*/
@ApiModelProperty(
value = "The id of the user."
value = "The identity of the user."
)
public String getId() {
return id;
public String getIdentity() {
return identity;
}
public void setId(String id) {
this.id = id;
public void setIdentity(String identity) {
this.identity = identity;
}
/**
* @return users authorities
* @return groups to which the user belongs
*/
@ApiModelProperty(
value = "The users authorities."
)
public Set<String> getAuthorities() {
return authorities;
@ApiModelProperty(value = "The groups to which the user belongs.")
public Set<UserGroupEntity> getGroups() {
return groups;
}
public void setAuthorities(Set<String> authorities) {
this.authorities = authorities;
public void setGroups(Set<UserGroupEntity> groups) {
this.groups = groups;
}
/**
* @return creation time for this users account
*/
@XmlJavaTypeAdapter(DateTimeAdapter.class)
@ApiModelProperty(
value = "The timestamp when the user was created."
)
public Date getCreation() {
return creation;
}
public void setCreation(Date creation) {
this.creation = creation;
}
/**
* @return users DN
*/
@ApiModelProperty(
value = "The dn of the user."
)
public String getDn() {
return dn;
}
public void setDn(String dn) {
this.dn = dn;
}
/**
* @return users name. If the name could not be extracted from the DN, this value will be the entire DN
*/
@ApiModelProperty(
value = "The username. If it could not be extracted from the DN, this value will be the entire DN."
)
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
/**
* @return user group
*/
@ApiModelProperty(
value = "The group this user belongs to."
)
public String getUserGroup() {
return userGroup;
}
public void setUserGroup(String userGroup) {
this.userGroup = userGroup;
}
/**
* @return users account justification
*/
@ApiModelProperty(
value = "The justification for the user account."
)
public String getJustification() {
return justification;
}
public void setJustification(String justification) {
this.justification = justification;
}
/**
* @return time that the user last accessed the system
*/
@XmlJavaTypeAdapter(DateTimeAdapter.class)
@ApiModelProperty(
value = "The timestamp the user last accessed the system."
)
public Date getLastAccessed() {
return lastAccessed;
}
public void setLastAccessed(Date lastAccessed) {
this.lastAccessed = lastAccessed;
}
/**
* @return time that the users credentials were last verified
*/
@XmlJavaTypeAdapter(DateTimeAdapter.class)
@ApiModelProperty(
value = "The timestamp the user authorities were verified."
)
public Date getLastVerified() {
return lastVerified;
}
public void setLastVerified(Date lastVerified) {
this.lastVerified = lastVerified;
}
/**
* @return status of the users account
*/
@ApiModelProperty(
value = "The user status."
)
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@ -17,73 +17,44 @@
package org.apache.nifi.web.api.dto;
import com.wordnik.swagger.annotations.ApiModelProperty;
import java.util.Set;
import org.apache.nifi.web.api.entity.UserEntity;
import javax.xml.bind.annotation.XmlType;
import java.util.Set;
/**
* A user group in this NiFi.
*/
@XmlType(name = "userGroup")
public class UserGroupDTO {
public class UserGroupDTO extends ComponentDTO {
private String group;
private Set<String> userIds;
private Set<String> authorities;
private String status;
/**
* @return user group
*/
@ApiModelProperty(
value = "The user group."
)
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
private String name;
private Set<UserEntity> users;
/**
* @return users in this group
*/
@ApiModelProperty(
value = "The users that belong to the group."
value = "The users that belong to the user group."
)
public Set<String> getUserIds() {
return userIds;
public Set<UserEntity> getUsers() {
return users;
}
public void setUserIds(Set<String> userIds) {
this.userIds = userIds;
public void setUsers(Set<UserEntity> users) {
this.users = users;
}
/**
* @return status of the users account
*
* @return name of the user group
*/
@ApiModelProperty(
value = "The status of the users accounts."
)
public String getStatus() {
return status;
@ApiModelProperty(value = "The name of the user group.")
public String getName() {
return name;
}
public void setStatus(String status) {
this.status = status;
}
/**
* @return users authorities
*/
@ApiModelProperty(
value = "The authorities of the users."
)
public Set<String> getAuthorities() {
return authorities;
}
public void setAuthorities(Set<String> authorities) {
this.authorities = authorities;
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.web.api.entity;
import org.apache.nifi.web.api.dto.AccessPolicyDTO;
import javax.xml.bind.annotation.XmlRootElement;
/**
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to an {@link AccessPolicyDTO}.
*/
@XmlRootElement(name = "accessPolicyEntity")
public class AccessPolicyEntity extends ComponentEntity {
private AccessPolicyDTO component;
/**
* The {@link AccessPolicyDTO} that is being serialized.
*
* @return The {@link AccessPolicyDTO} object
*/
public AccessPolicyDTO getComponent() {
return component;
}
public void setComponent(AccessPolicyDTO component) {
this.component = component;
}
}

View File

@ -16,28 +16,29 @@
*/
package org.apache.nifi.web.api.entity;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.nifi.web.api.dto.UserDTO;
import javax.xml.bind.annotation.XmlRootElement;
/**
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a UserDTO.
*/
@XmlRootElement(name = "userEntity")
public class UserEntity extends Entity {
public class UserEntity extends ComponentEntity {
private UserDTO user;
private UserDTO component;
/**
* The UserDTO that is being serialized.
*
* @return The UserDTO object
*/
public UserDTO getUser() {
return user;
public UserDTO getComponent() {
return component;
}
public void setUser(UserDTO user) {
this.user = user;
public void setComponent(UserDTO component) {
this.component = component;
}
}

View File

@ -23,21 +23,21 @@ import org.apache.nifi.web.api.dto.UserGroupDTO;
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a UserGroupDTO.
*/
@XmlRootElement(name = "userGroupEntity")
public class UserGroupEntity extends Entity {
public class UserGroupEntity extends ComponentEntity {
private UserGroupDTO userGroup;
private UserGroupDTO component;
/**
* The UserGroupDTO that is being serialized.
*
* @return The UserGroupDTO object
*/
public UserGroupDTO getUserGroup() {
return userGroup;
public UserGroupDTO getComponent() {
return component;
}
public void setUserGroup(UserGroupDTO userGroup) {
this.userGroup = userGroup;
public void setComponent(UserGroupDTO component) {
this.component = component;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.resource;
import org.apache.nifi.authorization.Resource;
public class AccessPoliciesAuthorizable implements Authorizable {
@Override
public Authorizable getParentAuthorizable() {
return null;
}
@Override
public Resource getResource() {
return ResourceFactory.getPoliciesResource();
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.resource;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.Resource;
public class AccessPolicyAuthorizable implements Authorizable {
private final AccessPolicy policy;
public AccessPolicyAuthorizable(AccessPolicy policy) {
this.policy = policy;
}
@Override
public Authorizable getParentAuthorizable() {
return new Authorizable() {
@Override
public Authorizable getParentAuthorizable() {
return null;
}
@Override
public Resource getResource() {
return ResourceFactory.getPoliciesResource();
}
};
}
@Override
public Resource getResource() {
return ResourceFactory.getPolicyResource(policy.getIdentifier());
}
public AccessPolicy getPolicy() {
return policy;
}
}

View File

@ -16,7 +16,10 @@
*/
package org.apache.nifi.authorization.resource;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.Resource;
import org.apache.nifi.authorization.User;
import java.util.Objects;
@ -286,6 +289,45 @@ public final class ResourceFactory {
}
};
private final static Resource POLICIES_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
return "/policies";
}
@Override
public String getName() {
return "Access Policies";
}
};
private final static Resource USERS_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
return "/users";
}
@Override
public String getName() {
return "Users";
}
};
private final static Resource USERGROUPS_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
return "/user-groups";
}
@Override
public String getName() {
return "User Groups";
}
};
/**
* Gets the Resource for accessing Connections.
*
@ -486,6 +528,54 @@ public final class ResourceFactory {
return USER_RESOURCE;
}
/**
* Gets the {@link Resource} for accessing {@link AccessPolicy}s.
* @return The policies resource
*/
public static Resource getPoliciesResource() {
return POLICIES_RESOURCE;
}
/**
* Gets a Resource for accessing an {@link AccessPolicy} configuration.
*
* @param identifier The identifier of the component being accessed
* @return The resource
*/
public static Resource getPolicyResource(final String identifier) {
Objects.requireNonNull(identifier, "The component identifier must be specified.");
return new Resource() {
@Override
public String getIdentifier() {
return String.format("%s/%s", POLICIES_RESOURCE.getIdentifier(), identifier);
}
@Override
public String getName() {
return identifier;
}
};
}
/**
* Gets a Resource for accessing {@link User} configurations.
*
* @return The resource
*/
public static Resource getUsersResource() {
return USERS_RESOURCE;
}
/**
* Gets a Resource for accessing {@link Group}s configuration.
*
* @return The resource
*/
public static Resource getUserGroupsResource() {
return USERGROUPS_RESOURCE;
}
/**
* Gets a Resource for accessing a component configuration.
*

View File

@ -0,0 +1,31 @@
/*
* 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.resource;
import org.apache.nifi.authorization.Resource;
public class UserGroupsAuthorizable implements Authorizable {
@Override
public Authorizable getParentAuthorizable() {
return null;
}
@Override
public Resource getResource() {
return ResourceFactory.getUserGroupsResource();
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.resource;
import org.apache.nifi.authorization.Resource;
public class UsersAuthorizable implements Authorizable {
@Override
public Authorizable getParentAuthorizable() {
return null;
}
@Override
public Resource getResource() {
return ResourceFactory.getUsersResource();
}
}

View File

@ -16,6 +16,9 @@
*/
package org.apache.nifi.web;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.User;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.controller.Snippet;
@ -151,4 +154,29 @@ public interface AuthorizableLookup {
* @return snippet of authorizable's
*/
Snippet getSnippet(String id);
/**
* Get the {@link Authorizable} that represents the resource of {@link User}s.
* @return authorizable
*/
Authorizable getUsersAuthorizable();
/**
* Get the {@link Authorizable} that represents the resource of {@link Group}s.
* @return authorizable
*/
Authorizable getUserGroupsAuthorizable();
/**
* Get the {@link Authorizable} the represents the parent resource of {@link AccessPolicy} resources.
* @return authorizable
*/
Authorizable getAccessPoliciesAuthorizable();
/**
* Get the {@link Authorizable} the represents the {@link AccessPolicy} with the given ID.
* @param id access policy ID
* @return authorizable
*/
Authorizable getAccessPolicyAuthorizable(String id);
}

View File

@ -21,6 +21,7 @@ import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.repository.claim.ContentDirection;
import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.web.api.dto.AccessPolicyDTO;
import org.apache.nifi.web.api.dto.BulletinBoardDTO;
import org.apache.nifi.web.api.dto.BulletinQueryDTO;
import org.apache.nifi.web.api.dto.ClusterDTO;
@ -50,6 +51,8 @@ import org.apache.nifi.web.api.dto.ResourceDTO;
import org.apache.nifi.web.api.dto.SnippetDTO;
import org.apache.nifi.web.api.dto.SystemDiagnosticsDTO;
import org.apache.nifi.web.api.dto.TemplateDTO;
import org.apache.nifi.web.api.dto.UserDTO;
import org.apache.nifi.web.api.dto.UserGroupDTO;
import org.apache.nifi.web.api.dto.action.ActionDTO;
import org.apache.nifi.web.api.dto.action.HistoryDTO;
import org.apache.nifi.web.api.dto.action.HistoryQueryDTO;
@ -65,6 +68,7 @@ import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
import org.apache.nifi.web.api.entity.AccessPolicyEntity;
import org.apache.nifi.web.api.entity.ConnectionEntity;
import org.apache.nifi.web.api.entity.ControllerConfigurationEntity;
import org.apache.nifi.web.api.entity.ControllerServiceEntity;
@ -81,6 +85,8 @@ import org.apache.nifi.web.api.entity.RemoteProcessGroupPortEntity;
import org.apache.nifi.web.api.entity.ReportingTaskEntity;
import org.apache.nifi.web.api.entity.ScheduleComponentsEntity;
import org.apache.nifi.web.api.entity.SnippetEntity;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import java.util.Date;
import java.util.List;
@ -1179,6 +1185,110 @@ public interface NiFiServiceFacade {
*/
LabelEntity deleteLabel(Revision revision, String labelId);
// ----------------------------------------
// User methods
// ----------------------------------------
/**
* Creates a user.
* @param revision The starting revision
* @param userDTO The user DTO
* @return The user transfer object
*/
UserEntity createUser(Revision revision, UserDTO userDTO);
/**
* Gets the user with the specified ID.
* @param userId The user ID
* @param prune If true, the users in the groups to which this user belongs will not be returned
* @return The user transfer object
*/
UserEntity getUser(String userId, boolean prune);
/**
* Updates the specified user.
* @param revision Revision to compare with current base revision
* @param userDTO The user DTO
* @return The user transfer object
*/
UpdateResult<UserEntity> updateUser(Revision revision, UserDTO userDTO);
/**
* Deletes the specified user.
* @param revision Revision to compare with current base revision
* @param userId The user ID
* @return The user transfer object of the deleted user
*/
UserEntity deleteUser(Revision revision, String userId);
// ----------------------------------------
// Group methods
// ----------------------------------------
/**
* Creates a user group.
* @param revision The starting revision
* @param userGroupDTO The user group DTO
* @return The user group transfer object
*/
UserGroupEntity createUserGroup(Revision revision, UserGroupDTO userGroupDTO);
/**
* Gets the user group with the specified ID.
* @param userGroupId The user group ID
* @param prune If true, the user groups of the users in this user group will not be returned
* @return The user group transfer object
*/
UserGroupEntity getUserGroup(String userGroupId, boolean prune);
/**
* Updates the specified user group.
* @param revision Revision to compare with current base revision
* @param userGroupDTO The user group DTO
* @return The user group transfer object
*/
UpdateResult<UserGroupEntity> updateUserGroup(Revision revision, UserGroupDTO userGroupDTO);
/**
* Deletes the specified user group.
* @param revision Revision to compare with current base revision
* @param userGroupId The user group ID
* @return The user group transfer object of the deleted user group
*/
UserGroupEntity deleteUserGroup(Revision revision, String userGroupId);
// ----------------------------------------
// AccessPolicy methods
// ----------------------------------------
/**
* Creates an access policy.
* @param revision The starting revision
* @param accessPolicyDTO The access policy DTO
* @return The access policy transfer object
*/
AccessPolicyEntity createAccessPolicy(Revision revision, AccessPolicyDTO accessPolicyDTO);
/**
* Gets the access policy with the specified ID.
* @param accessPolicyId access policy ID
* @return The access policy transfer object
*/
AccessPolicyEntity getAccessPolicy(String accessPolicyId);
/**
* Updates the specified access policy.
* @param revision Revision to compare with current base revision
* @param accessPolicyDTO The access policy DTO
* @return The access policy transfer object
*/
UpdateResult<AccessPolicyEntity> updateAccessPolicy(Revision revision, AccessPolicyDTO accessPolicyDTO);
/**
* Deletes the specified access policy.
* @param revision Revision to compare with current base revision
* @param accessPolicyId The access policy ID
* @return The access policy transfer object of the deleted access policy
*/
AccessPolicyEntity deleteAccessPolicy(Revision revision, String accessPolicyId);
// ----------------------------------------
// Controller Services methods
// ----------------------------------------

View File

@ -0,0 +1,242 @@
/*
* 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.web;
import org.apache.nifi.authorization.resource.AccessPoliciesAuthorizable;
import org.apache.nifi.authorization.resource.AccessPolicyAuthorizable;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.resource.UserGroupsAuthorizable;
import org.apache.nifi.authorization.resource.UsersAuthorizable;
import org.apache.nifi.controller.ConfiguredComponent;
import org.apache.nifi.controller.Snippet;
import org.apache.nifi.controller.service.ControllerServiceNode;
import org.apache.nifi.controller.service.ControllerServiceReference;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.groups.RemoteProcessGroup;
import org.apache.nifi.web.controller.ControllerFacade;
import org.apache.nifi.web.dao.AccessPolicyDAO;
import org.apache.nifi.web.dao.ConnectionDAO;
import org.apache.nifi.web.dao.ControllerServiceDAO;
import org.apache.nifi.web.dao.FunnelDAO;
import org.apache.nifi.web.dao.LabelDAO;
import org.apache.nifi.web.dao.PortDAO;
import org.apache.nifi.web.dao.ProcessGroupDAO;
import org.apache.nifi.web.dao.ProcessorDAO;
import org.apache.nifi.web.dao.RemoteProcessGroupDAO;
import org.apache.nifi.web.dao.ReportingTaskDAO;
import org.apache.nifi.web.dao.SnippetDAO;
import org.apache.nifi.web.dao.TemplateDAO;
class StandardAuthorizableLookup implements AuthorizableLookup {
private static final UsersAuthorizable USERS_AUTHORIZABLE = new UsersAuthorizable();
private static final UserGroupsAuthorizable USER_GROUPS_AUTHORIZABLE = new UserGroupsAuthorizable();
private static final Authorizable ACCESS_POLICIES_AUTHORIZABLE = new AccessPoliciesAuthorizable();
// nifi core components
private ControllerFacade controllerFacade;
// data access objects
private ProcessorDAO processorDAO;
private ProcessGroupDAO processGroupDAO;
private RemoteProcessGroupDAO remoteProcessGroupDAO;
private LabelDAO labelDAO;
private FunnelDAO funnelDAO;
private SnippetDAO snippetDAO;
private PortDAO inputPortDAO;
private PortDAO outputPortDAO;
private ConnectionDAO connectionDAO;
private ControllerServiceDAO controllerServiceDAO;
private ReportingTaskDAO reportingTaskDAO;
private TemplateDAO templateDAO;
private AccessPolicyDAO accessPolicyDAO;
@Override
public Authorizable getProcessor(final String id) {
return processorDAO.getProcessor(id);
}
@Override
public Authorizable getInputPort(final String id) {
return inputPortDAO.getPort(id);
}
@Override
public Authorizable getOutputPort(final String id) {
return outputPortDAO.getPort(id);
}
@Override
public Authorizable getConnection(final String id) {
return connectionDAO.getConnection(id);
}
@Override
public Authorizable getProcessGroup(final String id) {
return processGroupDAO.getProcessGroup(id);
}
@Override
public Authorizable getRemoteProcessGroup(final String id) {
return remoteProcessGroupDAO.getRemoteProcessGroup(id);
}
@Override
public Authorizable getRemoteProcessGroupInputPort(final String remoteProcessGroupId, final String id) {
final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupId);
return remoteProcessGroup.getInputPort(id);
}
@Override
public Authorizable getRemoteProcessGroupOutputPort(final String remoteProcessGroupId, final String id) {
final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupId);
return remoteProcessGroup.getOutputPort(id);
}
@Override
public Authorizable getLabel(final String id) {
return labelDAO.getLabel(id);
}
@Override
public Authorizable getFunnel(final String id) {
return funnelDAO.getFunnel(id);
}
@Override
public Authorizable getControllerService(final String id) {
return controllerServiceDAO.getControllerService(id);
}
@Override
public Authorizable getControllerServiceReferencingComponent(String controllerSeriveId, String id) {
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerSeriveId);
final ControllerServiceReference referencingComponents = controllerService.getReferences();
ConfiguredComponent reference = null;
for (final ConfiguredComponent component : referencingComponents.getReferencingComponents()) {
if (component.getIdentifier().equals(id)) {
reference = component;
break;
}
}
if (reference == null) {
throw new ResourceNotFoundException("Unable to find referencing component with id " + id);
}
return reference;
}
@Override
public Authorizable getReportingTask(final String id) {
return reportingTaskDAO.getReportingTask(id);
}
@Override
public Snippet getSnippet(final String id) {
return snippetDAO.getSnippet(id);
}
@Override
public Authorizable getUsersAuthorizable() {
return USERS_AUTHORIZABLE;
}
@Override
public Authorizable getUserGroupsAuthorizable() {
return USER_GROUPS_AUTHORIZABLE;
}
@Override
public Authorizable getAccessPoliciesAuthorizable() {
return ACCESS_POLICIES_AUTHORIZABLE;
}
@Override
public Authorizable getAccessPolicyAuthorizable(String id) {
return new AccessPolicyAuthorizable(accessPolicyDAO.getAccessPolicy(id));
}
@Override
public Authorizable getTemplate(final String id) {
return templateDAO.getTemplate(id);
}
@Override
public Authorizable getConnectable(String id) {
final ProcessGroup group = processGroupDAO.getProcessGroup(controllerFacade.getRootGroupId());
return group.findConnectable(id);
}
public void setProcessorDAO(ProcessorDAO processorDAO) {
this.processorDAO = processorDAO;
}
public void setProcessGroupDAO(ProcessGroupDAO processGroupDAO) {
this.processGroupDAO = processGroupDAO;
}
public void setRemoteProcessGroupDAO(RemoteProcessGroupDAO remoteProcessGroupDAO) {
this.remoteProcessGroupDAO = remoteProcessGroupDAO;
}
public void setLabelDAO(LabelDAO labelDAO) {
this.labelDAO = labelDAO;
}
public void setFunnelDAO(FunnelDAO funnelDAO) {
this.funnelDAO = funnelDAO;
}
public void setSnippetDAO(SnippetDAO snippetDAO) {
this.snippetDAO = snippetDAO;
}
public void setInputPortDAO(PortDAO inputPortDAO) {
this.inputPortDAO = inputPortDAO;
}
public void setOutputPortDAO(PortDAO outputPortDAO) {
this.outputPortDAO = outputPortDAO;
}
public void setConnectionDAO(ConnectionDAO connectionDAO) {
this.connectionDAO = connectionDAO;
}
public void setControllerServiceDAO(ControllerServiceDAO controllerServiceDAO) {
this.controllerServiceDAO = controllerServiceDAO;
}
public void setReportingTaskDAO(ReportingTaskDAO reportingTaskDAO) {
this.reportingTaskDAO = reportingTaskDAO;
}
public void setTemplateDAO(TemplateDAO templateDAO) {
this.templateDAO = templateDAO;
}
public void setAccessPolicyDAO(AccessPolicyDAO accessPolicyDAO) {
this.accessPolicyDAO = accessPolicyDAO;
}
public void setControllerFacade(ControllerFacade controllerFacade) {
this.controllerFacade = controllerFacade;
}
}

View File

@ -25,9 +25,12 @@ import org.apache.nifi.action.Operation;
import org.apache.nifi.action.details.FlowChangePurgeDetails;
import org.apache.nifi.admin.service.AuditService;
import org.apache.nifi.admin.service.KeyService;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.Resource;
import org.apache.nifi.authorization.User;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
@ -114,6 +117,8 @@ import org.apache.nifi.web.api.dto.RevisionDTO;
import org.apache.nifi.web.api.dto.SnippetDTO;
import org.apache.nifi.web.api.dto.SystemDiagnosticsDTO;
import org.apache.nifi.web.api.dto.TemplateDTO;
import org.apache.nifi.web.api.dto.UserDTO;
import org.apache.nifi.web.api.dto.UserGroupDTO;
import org.apache.nifi.web.api.dto.action.ActionDTO;
import org.apache.nifi.web.api.dto.action.HistoryDTO;
import org.apache.nifi.web.api.dto.action.HistoryQueryDTO;
@ -130,6 +135,7 @@ import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
import org.apache.nifi.web.api.entity.AccessPolicyEntity;
import org.apache.nifi.web.api.entity.ConnectionEntity;
import org.apache.nifi.web.api.entity.ControllerConfigurationEntity;
import org.apache.nifi.web.api.entity.ControllerServiceEntity;
@ -147,7 +153,10 @@ import org.apache.nifi.web.api.entity.RemoteProcessGroupPortEntity;
import org.apache.nifi.web.api.entity.ReportingTaskEntity;
import org.apache.nifi.web.api.entity.ScheduleComponentsEntity;
import org.apache.nifi.web.api.entity.SnippetEntity;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import org.apache.nifi.web.controller.ControllerFacade;
import org.apache.nifi.web.dao.AccessPolicyDAO;
import org.apache.nifi.web.dao.ConnectionDAO;
import org.apache.nifi.web.dao.ControllerServiceDAO;
import org.apache.nifi.web.dao.FunnelDAO;
@ -159,6 +168,8 @@ import org.apache.nifi.web.dao.RemoteProcessGroupDAO;
import org.apache.nifi.web.dao.ReportingTaskDAO;
import org.apache.nifi.web.dao.SnippetDAO;
import org.apache.nifi.web.dao.TemplateDAO;
import org.apache.nifi.web.dao.UserDAO;
import org.apache.nifi.web.dao.UserGroupDAO;
import org.apache.nifi.web.revision.DeleteRevisionTask;
import org.apache.nifi.web.revision.ExpiredRevisionClaimException;
import org.apache.nifi.web.revision.ReadOnlyRevisionCallback;
@ -178,6 +189,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@ -220,6 +232,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
private ControllerServiceDAO controllerServiceDAO;
private ReportingTaskDAO reportingTaskDAO;
private TemplateDAO templateDAO;
private UserDAO userDAO;
private UserGroupDAO userGroupDAO;
private AccessPolicyDAO accessPolicyDAO;
private ClusterCoordinator clusterCoordinator;
private HeartbeatMonitor heartbeatMonitor;
@ -234,105 +249,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
private Authorizer authorizer;
private final AuthorizableLookup authorizableLookup = new AuthorizableLookup() {
@Override
public Authorizable getProcessor(final String id) {
return processorDAO.getProcessor(id);
}
@Override
public Authorizable getInputPort(final String id) {
return inputPortDAO.getPort(id);
}
@Override
public Authorizable getOutputPort(final String id) {
return outputPortDAO.getPort(id);
}
@Override
public Authorizable getConnection(final String id) {
return connectionDAO.getConnection(id);
}
@Override
public Authorizable getProcessGroup(final String id) {
return processGroupDAO.getProcessGroup(id);
}
@Override
public Authorizable getRemoteProcessGroup(final String id) {
return remoteProcessGroupDAO.getRemoteProcessGroup(id);
}
@Override
public Authorizable getRemoteProcessGroupInputPort(final String remoteProcessGroupId, final String id) {
final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupId);
return remoteProcessGroup.getInputPort(id);
}
@Override
public Authorizable getRemoteProcessGroupOutputPort(final String remoteProcessGroupId, final String id) {
final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupId);
return remoteProcessGroup.getOutputPort(id);
}
@Override
public Authorizable getLabel(final String id) {
return labelDAO.getLabel(id);
}
@Override
public Authorizable getFunnel(final String id) {
return funnelDAO.getFunnel(id);
}
@Override
public Authorizable getControllerService(final String id) {
return controllerServiceDAO.getControllerService(id);
}
@Override
public Authorizable getControllerServiceReferencingComponent(final String controllerSeriveId, final String id) {
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerSeriveId);
final ControllerServiceReference referencingComponents = controllerService.getReferences();
ConfiguredComponent reference = null;
for (final ConfiguredComponent component : referencingComponents.getReferencingComponents()) {
if (component.getIdentifier().equals(id)) {
reference = component;
break;
}
}
if (reference == null) {
throw new ResourceNotFoundException("Unable to find referencing component with id " + id);
}
return reference;
}
@Override
public Authorizable getReportingTask(final String id) {
return reportingTaskDAO.getReportingTask(id);
}
@Override
public Snippet getSnippet(final String id) {
return snippetDAO.getSnippet(id);
}
@Override
public Authorizable getTemplate(final String id) {
return templateDAO.getTemplate(id);
}
@Override
public Authorizable getConnectable(final String id) {
final ProcessGroup group = processGroupDAO.getProcessGroup(controllerFacade.getRootGroupId());
return group.findConnectable(id);
}
};
private AuthorizableLookup authorizableLookup;
// -----------------------------------------
// Synchronization methods
@ -597,6 +514,61 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
// -----------------------------------------
// Write Operations
// -----------------------------------------
@Override
public UpdateResult<AccessPolicyEntity> updateAccessPolicy(final Revision revision, final AccessPolicyDTO accessPolicyDTO) {
// if access policy does not exist, then create new access policy
if (!accessPolicyDAO.hasAccessPolicy(accessPolicyDTO.getId())) {
return new UpdateResult<>(createAccessPolicy(revision, accessPolicyDTO), false);
}
final Authorizable accessPolicyAuthorizable = authorizableLookup.getAccessPolicyAuthorizable(accessPolicyDTO.getId());
final RevisionUpdate<AccessPolicyDTO> snapshot = updateComponent(revision,
accessPolicyAuthorizable,
() -> accessPolicyDAO.updateAccessPolicy(accessPolicyDTO),
accessPolicy -> {
final Set<UserEntity> users = accessPolicy.getUsers().stream().map(userId -> getUser(userId, true) ).collect(Collectors.toSet());
final Set<UserGroupEntity> userGroups = accessPolicy.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true) ).collect(Collectors.toSet());
return dtoFactory.createAccessPolicyDto(accessPolicy, userGroups, users);
});
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(accessPolicyAuthorizable);
return new UpdateResult<>(entityFactory.createAccessPolicyEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy), false);
}
@Override
public UpdateResult<UserEntity> updateUser(final Revision revision, final UserDTO userDTO) {
// if user does not exist, then create new user
if (!userDAO.hasUser(userDTO.getId())) {
return new UpdateResult<>(createUser(revision, userDTO), false);
}
final Authorizable usersAuthorizable = authorizableLookup.getUsersAuthorizable();
final RevisionUpdate<UserDTO> snapshot = updateComponent(revision,
usersAuthorizable,
() -> userDAO.updateUser(userDTO),
user -> dtoFactory.createUserDto(user, user.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet())));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable);
return new UpdateResult<>(entityFactory.createUserEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy), false);
}
@Override
public UpdateResult<UserGroupEntity> updateUserGroup(final Revision revision, final UserGroupDTO userGroupDTO) {
// if user group does not exist, then create new user group
if (!userGroupDAO.hasUserGroup(userGroupDTO.getId())) {
return new UpdateResult<>(createUserGroup(revision, userGroupDTO), false);
}
final Authorizable userGroupsAuthorizable = authorizableLookup.getUserGroupsAuthorizable();
final RevisionUpdate<UserGroupDTO> snapshot = updateComponent(revision,
userGroupsAuthorizable,
() -> userGroupDAO.updateUserGroup(userGroupDTO),
userGroup -> dtoFactory.createUserGroupDto(userGroup, userGroup.getUsers().stream().map(userId -> getUser(userId, true)).collect(Collectors.toSet())));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userGroupsAuthorizable);
return new UpdateResult<>(entityFactory.createUserGroupEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy), false);
}
@Override
public UpdateResult<ConnectionEntity> updateConnection(final Revision revision, final ConnectionDTO connectionDTO) {
// if connection does not exist, then create new connection
@ -685,7 +657,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
*/
private <D, C> RevisionUpdate<D> updateComponent(final Revision revision, final Authorizable authorizable, final Supplier<C> daoUpdate, final Function<C, D> dtoCreation) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final String modifier = user.getUserName();
final String userName = NiFiUserUtils.getNiFiUserName();
try {
final RevisionUpdate<D> updatedComponent = revisionManager.updateRevision(new StandardRevisionClaim(revision), user, new UpdateRevisionTask<D>() {
@Override
@ -699,7 +671,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
final Revision updatedRevision = incrementRevision(revision);
final D dto = dtoCreation.apply(component);
final FlowModification lastModification = new FlowModification(updatedRevision, modifier);
final FlowModification lastModification = new FlowModification(updatedRevision, userName);
return new StandardRevisionUpdate<>(dto, lastModification);
}
});
@ -730,7 +702,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final RevisionClaim revisionClaim = new StandardRevisionClaim(revisions);
RevisionUpdate<SnippetDTO> snapshot;
final RevisionUpdate<SnippetDTO> snapshot;
try {
snapshot = revisionManager.updateRevision(revisionClaim, user, new UpdateRevisionTask<SnippetDTO>() {
@Override
@ -905,19 +877,19 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
@Override
public ControllerConfigurationEntity updateControllerConfiguration(final Revision revision, final ControllerConfigurationDTO controllerConfigurationDTO) {
final RevisionUpdate<ControllerConfigurationDTO> updatedComponent = updateComponent(
revision,
controllerFacade,
() -> {
if (controllerConfigurationDTO.getMaxTimerDrivenThreadCount() != null) {
controllerFacade.setMaxTimerDrivenThreadCount(controllerConfigurationDTO.getMaxTimerDrivenThreadCount());
}
if (controllerConfigurationDTO.getMaxEventDrivenThreadCount() != null) {
controllerFacade.setMaxEventDrivenThreadCount(controllerConfigurationDTO.getMaxEventDrivenThreadCount());
}
revision,
controllerFacade,
() -> {
if (controllerConfigurationDTO.getMaxTimerDrivenThreadCount() != null) {
controllerFacade.setMaxTimerDrivenThreadCount(controllerConfigurationDTO.getMaxTimerDrivenThreadCount());
}
if (controllerConfigurationDTO.getMaxEventDrivenThreadCount() != null) {
controllerFacade.setMaxEventDrivenThreadCount(controllerConfigurationDTO.getMaxEventDrivenThreadCount());
}
return controllerConfigurationDTO;
},
controller -> dtoFactory.createControllerConfigurationDto(controllerFacade, properties.getAutoRefreshInterval()));
return controllerConfigurationDTO;
},
controller -> dtoFactory.createControllerConfigurationDto(controllerFacade, properties.getAutoRefreshInterval()));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(controllerFacade);
final RevisionDTO updateRevision = dtoFactory.createRevisionDTO(updatedComponent.getLastModification());
@ -1067,6 +1039,48 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
return entityFactory.createLabelEntity(snapshot, null, null);
}
@Override
public UserEntity deleteUser(final Revision revision, final String userId) {
final User user = userDAO.getUser(userId);
final Set<UserGroupEntity> userGroups = user != null ? user.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet()) : null;
final UserDTO snapshot = deleteComponent(
revision,
authorizableLookup.getUsersAuthorizable(),
() -> userDAO.deleteUser(userId),
dtoFactory.createUserDto(user, userGroups));
return entityFactory.createUserEntity(snapshot, null, null);
}
@Override
public UserGroupEntity deleteUserGroup(final Revision revision, final String userGroupId) {
final Group userGroup = userGroupDAO.getUserGroup(userGroupId);
final Set<UserEntity> users = userGroup != null ? userGroup.getUsers().stream().map(userId -> getUser(userId, true)).collect(Collectors.toSet()) :
null;
final UserGroupDTO snapshot = deleteComponent(
revision,
authorizableLookup.getUserGroupsAuthorizable(),
() -> userGroupDAO.deleteUserGroup(userGroupId),
dtoFactory.createUserGroupDto(userGroup, users));
return entityFactory.createUserGroupEntity(snapshot, null, null);
}
@Override
public AccessPolicyEntity deleteAccessPolicy(final Revision revision, final String accessPolicyId) {
final AccessPolicy accessPolicy = accessPolicyDAO.getAccessPolicy(accessPolicyId);
final Set<UserGroupEntity> userGroups = accessPolicy != null ? accessPolicy.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet()) : null;
final Set<UserEntity> users = accessPolicy != null ? accessPolicy.getUsers().stream().map(userId -> getUser(userId, true)).collect(Collectors.toSet()) : null;
final AccessPolicyDTO snapshot = deleteComponent(
revision,
authorizableLookup.getAccessPolicyAuthorizable(accessPolicyId),
() -> accessPolicyDAO.deleteAccessPolicy(accessPolicyId),
dtoFactory.createAccessPolicyDto(accessPolicy, userGroups,
users));
return entityFactory.createAccessPolicyEntity(snapshot, null, null);
}
@Override
public FunnelEntity deleteFunnel(final Revision revision, final String funnelId) {
final Funnel funnel = funnelDAO.getFunnel(funnelId);
@ -1306,6 +1320,47 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
return entityFactory.createFunnelEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy);
}
@Override
public AccessPolicyEntity createAccessPolicy(final Revision revision, final AccessPolicyDTO accessPolicyDTO) {
final String creator = NiFiUserUtils.getNiFiUserName();
if (revision.getVersion() != 0) {
throw new IllegalArgumentException("The revision must start at 0.");
}
final AccessPolicy newAccessPolicy = accessPolicyDAO.createAccessPolicy(accessPolicyDTO);
final AccessPolicyDTO newAccessPolicyDto = dtoFactory.createAccessPolicyDto(newAccessPolicy,
newAccessPolicy.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet()),
newAccessPolicy.getUsers().stream().map(userId -> getUser(userId, true)).collect(Collectors.toSet()));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getAccessPolicyAuthorizable(newAccessPolicy.getIdentifier()));
return entityFactory.createAccessPolicyEntity(newAccessPolicyDto, dtoFactory.createRevisionDTO(new FlowModification(revision, creator)), accessPolicy);
}
@Override
public UserEntity createUser(final Revision revision, final UserDTO userDTO) {
final String creator = NiFiUserUtils.getNiFiUserName();
if (revision.getVersion() != 0) {
throw new IllegalArgumentException("The revision must start at 0.");
}
final User newUser = userDAO.createUser(userDTO);
final UserDTO newUserDto = dtoFactory.createUserDto(newUser, newUser.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet()));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getUsersAuthorizable());
return entityFactory.createUserEntity(newUserDto, dtoFactory.createRevisionDTO(new FlowModification(revision, creator)), accessPolicy);
}
@Override
public UserGroupEntity createUserGroup(final Revision revision, final UserGroupDTO userGroupDTO) {
final String creator = NiFiUserUtils.getNiFiUserName();
if (revision.getVersion() != 0) {
throw new IllegalArgumentException("The revision must start at 0.");
}
final Group newUserGroup = userGroupDAO.createUserGroup(userGroupDTO);
final UserGroupDTO newUserGroupDto = dtoFactory.createUserGroupDto(newUserGroup, newUserGroup.getUsers().stream().map(userId -> getUser(userId, true)).collect(Collectors.toSet()));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getUserGroupsAuthorizable());
return entityFactory.createUserGroupEntity(newUserGroupDto, dtoFactory.createRevisionDTO(new FlowModification(revision, creator)), accessPolicy);
}
private void validateSnippetContents(final FlowSnippetDTO flow) {
// validate any processors
if (flow.getProcessors() != null) {
@ -2348,6 +2403,78 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
});
}
@Override
public AccessPolicyEntity getAccessPolicy(final String accessPolicyId) {
return revisionManager.get(accessPolicyId, rev -> {
final Authorizable accessPolicyAuthorizable = authorizableLookup.getAccessPolicyAuthorizable(accessPolicyId);
accessPolicyAuthorizable.authorize(authorizer, RequestAction.READ);
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(accessPolicyAuthorizable);
final AccessPolicy requestedAccessPolicy = accessPolicyDAO.getAccessPolicy(accessPolicyId);
return entityFactory.createAccessPolicyEntity(
dtoFactory.createAccessPolicyDto(requestedAccessPolicy,
requestedAccessPolicy.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet()),
requestedAccessPolicy.getUsers().stream().map(userId -> getUser(userId, true)).collect(Collectors.toSet())),
revision, accessPolicy);
});
}
@Override
public UserEntity getUser(final String userId, final boolean prune) {
return revisionManager.get(userId, rev -> {
final Authorizable usersAuthorizable = authorizableLookup.getUsersAuthorizable();
usersAuthorizable.authorize(authorizer, RequestAction.READ);
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable);
final User user = userDAO.getUser(userId);
final Set<UserGroupEntity> userGroups = user.getGroups().stream()
.map(userGroupId -> prune ? getUserGroupPruned(userGroupId) : getUserGroup(userGroupId, false))
.collect(Collectors.toSet());
return entityFactory.createUserEntity(dtoFactory.createUserDto(user, userGroups), revision, accessPolicy);
});
}
private UserEntity getUserPruned(final String userId) {
return revisionManager.get(userId, rev -> {
final Authorizable usersAuthorizable = authorizableLookup.getUsersAuthorizable();
usersAuthorizable.authorize(authorizer, RequestAction.READ);
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable);
final User user = userDAO.getUser(userId);
return entityFactory.createUserEntity(dtoFactory.createUserDto(user, Collections.emptySet()), revision, accessPolicy);
});
}
@Override
public UserGroupEntity getUserGroup(final String userGroupId, final boolean prune) {
return revisionManager.get(userGroupId, rev -> {
final Authorizable userGroupsAuthorizable = authorizableLookup.getUserGroupsAuthorizable();
userGroupsAuthorizable.authorize(authorizer, RequestAction.READ);
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userGroupsAuthorizable);
final Group userGroup = userGroupDAO.getUserGroup(userGroupId);
final Set<UserEntity> users = userGroup.getUsers().stream().map(userId -> prune ? getUserPruned(userId) : getUser(userId, false)).collect(Collectors.toSet());
return entityFactory.createUserGroupEntity(dtoFactory.createUserGroupDto(userGroup, users),
revision, accessPolicy);
});
}
private UserGroupEntity getUserGroupPruned(final String userGroupId) {
return revisionManager.get(userGroupId, rev -> {
final Authorizable userGroupsAuthorizable = authorizableLookup.getUserGroupsAuthorizable();
userGroupsAuthorizable.authorize(authorizer, RequestAction.READ);
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userGroupsAuthorizable);
final Group userGroup = userGroupDAO.getUserGroup(userGroupId);
return entityFactory.createUserGroupEntity(dtoFactory.createUserGroupDto(userGroup, Collections.emptySet()), revision, accessPolicy);
});
}
@Override
public Set<LabelEntity> getLabels(final String groupId) {
final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
@ -2944,10 +3071,25 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
this.snippetUtils = snippetUtils;
}
public void setAuthorizableLookup(final AuthorizableLookup authorizableLookup) {
this.authorizableLookup = authorizableLookup;
}
public void setAuthorizer(final Authorizer authorizer) {
this.authorizer = authorizer;
}
public void setUserDAO(final UserDAO userDAO) {
this.userDAO = userDAO;
}
public void setUserGroupDAO(final UserGroupDAO userGroupDAO) {
this.userGroupDAO = userGroupDAO;
}
public void setAccessPolicyDAO(final AccessPolicyDAO accessPolicyDAO) {
this.accessPolicyDAO = accessPolicyDAO;
}
public void setClusterCoordinator(final ClusterCoordinator coordinator) {
this.clusterCoordinator = coordinator;
}
@ -2956,7 +3098,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
this.heartbeatMonitor = heartbeatMonitor;
}
public void setBulletinRepository(BulletinRepository bulletinRepository) {
public void setBulletinRepository(final BulletinRepository bulletinRepository) {
this.bulletinRepository = bulletinRepository;
}
}

View File

@ -0,0 +1,440 @@
/*
* 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.web.api;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.Revision;
import org.apache.nifi.web.UpdateResult;
import org.apache.nifi.web.api.dto.AccessPolicyDTO;
import org.apache.nifi.web.api.dto.RevisionDTO;
import org.apache.nifi.web.api.entity.AccessPolicyEntity;
import org.apache.nifi.web.api.request.ClientIdParameter;
import org.apache.nifi.web.api.request.LongParameter;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
/**
* RESTful endpoint for managing access policies.
*/
@Path("/policies")
@Api(
value = "/policies",
description = "Endpoint for managing access policies."
)
public class AccessPolicyResource extends ApplicationResource {
private final NiFiServiceFacade serviceFacade;
private final Authorizer authorizer;
public AccessPolicyResource(NiFiServiceFacade serviceFacade, Authorizer authorizer, NiFiProperties properties, RequestReplicator requestReplicator, ClusterCoordinator clusterCoordinator) {
this.serviceFacade = serviceFacade;
this.authorizer = authorizer;
setProperties(properties);
setRequestReplicator(requestReplicator);
setClusterCoordinator(clusterCoordinator);
}
/**
* Populates the uri for the specified access policy.
*
* @param accessPolicyEntity accessPolicyEntity
* @return accessPolicyEntity
*/
public AccessPolicyEntity populateRemainingAccessPolicyEntityContent(AccessPolicyEntity accessPolicyEntity) {
if (accessPolicyEntity.getComponent() != null) {
populateRemainingAccessPolicyContent(accessPolicyEntity.getComponent());
}
return accessPolicyEntity;
}
/**
* Populates the uri for the specified accessPolicy.
*/
public AccessPolicyDTO populateRemainingAccessPolicyContent(AccessPolicyDTO accessPolicy) {
// populate the access policy href
accessPolicy.setUri(generateResourceUri("policies", accessPolicy.getId()));
return accessPolicy;
}
/**
* Creates a new access policy.
*
* @param httpServletRequest request
* @param accessPolicyEntity An accessPolicyEntity.
* @return An accessPolicyEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Creates an access policy",
notes = " Available resources:\n" +
" /flow - READ - allows user/entity to load the UI and see the flow structure\n" +
" - WRITE - NA\n" +
" /resource - READ - allows user/entity to retrieve the available resources\n" +
" - WRITE - NA\n" +
" /system - READ - allows user/entity to retrieve system level diagnostics (CPU load, disk utilization, etc)\n" +
" - WRITE - NA\n" +
" /controller - READ - allows user/entity to retrieve configuration details for the controller (controller bulletins, thread pool, reporting tasks, etc)\n" +
" - WRITE - allows user/entity to modify configuration details for the controller\n" +
" /provenance - READ - allows user/entity to perform provenance requests. results will be filtered based on access to provenance data per component\n" +
" - WRITE - NA\n" +
" /token - READ - NA\n" +
" - WRITE - allows user/entity to create a token for access the REST API\n" +
" /site-to-site - READ - allows user/entity to retrieve configuration details for performing site to site data transfers with this NiFi\n" +
" - WRITE - NA\n" +
" /proxy - READ - NA\n" +
" - WRITE - allows user/entity to create a proxy request on behalf of another user\n" +
" /process-groups/{id} - READ - allows user/entity to retrieve configuration details for the process group and all descendant components without explicit " +
"access policies\n" +
" - WRITE - allows user/entity to create/update/delete configuration details for the process group and all descendant components without " +
"explicit access policies\n" +
" /processors/{id} - READ - allows user/entity to retrieve configuration details for the processor overriding any inherited authorizations from an ancestor " +
"process group\n" +
" - WRITE - allows user/entity to update/delete the processor overriding any inherited authorizations from an ancestor process group\n" +
" /input-ports/{id} - READ - allows user/entity to retrieve configuration details for the input port overriding any inherited authorizations from an ancestor " +
"process group\n" +
" - WRITE - allows user/entity to update/delete the input port overriding any inherited authorizations from an ancestor process group\n" +
" /output-ports/{id} - READ - allows user/entity to retrieve configuration details for the output port overriding any inherited authorizations from an ancestor " +
"process group\n" +
" - WRITE - allows user/entity to update/delete the output port overriding any inherited authorizations from an ancestor process group\n" +
" /labels/{id} - READ - allows user/entity to retrieve configuration details for the label overriding any inherited authorizations from an ancestor " +
"process group\n" +
" - WRITE - allows user/entity to update/delete the label overriding any inherited authorizations from an ancestor process group\n" +
" /connections/{id} - READ - allows user/entity to retrieve configuration details for the connection overriding any inherited authorizations from an ancestor " +
"process group\n" +
" - WRITE - allows user/entity to update/delete the label overriding any inherited authorizations from an ancestor process group\n" +
" /remote-process-groups/{id} - READ - allows user/entity to retrieve configuration details for the remote process group overriding any inherited authorizations from an " +
"ancestor process group\n" +
" - WRITE - allows user/entity to update/delete the remote process group overriding any inherited authorizations from an ancestor process " +
"group\n" +
" /templates/{id} - READ - allows user/entity to retrieve configuration details for the template overriding any inherited authorizations from an ancestor " +
"process group\n" +
" - WRITE - allows user/entity to create/update/delete the template overriding any inherited authorizations from an ancestor process group\n" +
" /controller-services/{id} - READ - allows user/entity to retrieve configuration details for the controller service overriding any inherited authorizations from an " +
"ancestor process group\n" +
" - WRITE - allows user/entity to update/delete the controller service overriding any inherited authorizations from an ancestor process " +
"group\n" +
" /reporting-tasks/{id} - READ - allows user/entity to retrieve configuration details for the reporting tasks overriding any inherited authorizations from the " +
"controller\n" +
" - WRITE - allows user/entity to create/update/delete the reporting tasks overriding any inherited authorizations from the controller\n" +
" /{type}/{id}/provenance - READ - allows user/entity to view provenance data from the underlying component\n" +
" - WRITE - NA\n",
response = AccessPolicyEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response createAccessPolicy(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The access policy configuration details.",
required = true
) final AccessPolicyEntity accessPolicyEntity) {
if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) {
throw new IllegalArgumentException("Access policy details must be specified.");
}
if (accessPolicyEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Access policy ID cannot be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, accessPolicyEntity);
}
// handle expects request (usually from the cluster manager)
final boolean validationPhase = isValidationPhase(httpServletRequest);
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable accessPolicies = lookup.getAccessPoliciesAuthorizable();
accessPolicies.authorize(authorizer, RequestAction.WRITE);
});
}
if (validationPhase) {
return generateContinueResponse().build();
}
// set the access policy id as appropriate
accessPolicyEntity.getComponent().setId(generateUuid());
// get revision from the config
final RevisionDTO revisionDTO = accessPolicyEntity.getRevision();
Revision revision = new Revision(revisionDTO.getVersion(), revisionDTO.getClientId(), accessPolicyEntity.getComponent().getId());
// create the access policy and generate the json
final AccessPolicyEntity entity = serviceFacade.createAccessPolicy(revision, accessPolicyEntity.getComponent());
populateRemainingAccessPolicyEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
}
/**
* Retrieves the specified access policy.
*
* @param id The id of the access policy to retrieve
* @return An accessPolicyEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets an access policy",
response = AccessPolicyEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getAccessPolicy(
@ApiParam(
value = "The access policy id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable accessPolicy = lookup.getAccessPolicyAuthorizable(id);
accessPolicy.authorize(authorizer, RequestAction.READ);
});
// get the access policy
final AccessPolicyEntity entity = serviceFacade.getAccessPolicy(id);
populateRemainingAccessPolicyEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Updates an access policy.
*
* @param httpServletRequest request
* @param id The id of the access policy to update.
* @param accessPolicyEntity An accessPolicyEntity.
* @return An accessPolicyEntity.
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Updates a access policy",
response = AccessPolicyEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response updateAccessPolicy(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The access policy id.",
required = true
)
@PathParam("id") final String id,
@ApiParam(
value = "The access policy configuration details.",
required = true
) final AccessPolicyEntity accessPolicyEntity) {
if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) {
throw new IllegalArgumentException("Access policy details must be specified.");
}
if (accessPolicyEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
// ensure the ids are the same
final AccessPolicyDTO accessPolicyDTO = accessPolicyEntity.getComponent();
if (!id.equals(accessPolicyDTO.getId())) {
throw new IllegalArgumentException(String.format("The access policy id (%s) in the request body does not equal the "
+ "access policy id of the requested resource (%s).", accessPolicyDTO.getId(), id));
}
if (isReplicateRequest()) {
return replicate(HttpMethod.PUT, accessPolicyEntity);
}
// Extract the revision
final Revision revision = getRevision(accessPolicyEntity, id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable accessPolicy = lookup.getAccessPolicyAuthorizable(id);
accessPolicy.authorize(authorizer, RequestAction.WRITE);
},
null,
() -> {
// update the access policy
final UpdateResult<AccessPolicyEntity> updateResult = serviceFacade.updateAccessPolicy(revision, accessPolicyDTO);
// get the results
final AccessPolicyEntity entity = updateResult.getResult();
populateRemainingAccessPolicyEntityContent(entity);
if (updateResult.isNew()) {
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
} else {
return clusterContext(generateOkResponse(entity)).build();
}
}
);
}
/**
* Removes the specified access policy.
*
* @param httpServletRequest request
* @param version The revision is used to verify the client is working with
* the latest version of the flow.
* @param clientId Optional client id. If the client id is not specified, a
* new one will be generated. This value (whether specified or generated) is
* included in the response.
* @param id The id of the access policy to remove.
* @return A entity containing the client id and an updated revision.
*/
@DELETE
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Deletes an access policy",
response = AccessPolicyEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response removeAccessPolicy(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The revision is used to verify the client is working with the latest version of the flow.",
required = false
)
@QueryParam(VERSION) final LongParameter version,
@ApiParam(
value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
required = false
)
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) final ClientIdParameter clientId,
@ApiParam(
value = "The access policy id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.DELETE);
}
// handle expects request (usually from the cluster manager)
final Revision revision = new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable accessPolicy = lookup.getAccessPolicyAuthorizable(id);
accessPolicy.authorize(authorizer, RequestAction.READ);
},
() -> {
},
() -> {
// delete the specified access policy
final AccessPolicyEntity entity = serviceFacade.deleteAccessPolicy(revision, id);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
}

View File

@ -0,0 +1,385 @@
/*
* 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.web.api;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.Revision;
import org.apache.nifi.web.UpdateResult;
import org.apache.nifi.web.api.dto.RevisionDTO;
import org.apache.nifi.web.api.dto.UserGroupDTO;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import org.apache.nifi.web.api.request.ClientIdParameter;
import org.apache.nifi.web.api.request.LongParameter;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
@Path("/user-groups")
@Api(
value = "/user-groups",
description = "Endpoint for managing user groups."
)
public class UserGroupsResource extends ApplicationResource {
private final NiFiServiceFacade serviceFacade;
private final Authorizer authorizer;
public UserGroupsResource(NiFiServiceFacade serviceFacade, Authorizer authorizer, NiFiProperties properties, RequestReplicator requestReplicator, ClusterCoordinator clusterCoordinator) {
this.serviceFacade = serviceFacade;
this.authorizer = authorizer;
setProperties(properties);
setRequestReplicator(requestReplicator);
setClusterCoordinator(clusterCoordinator);
}
/**
* Populates the uri for the specified user group.
*
* @param userGroupEntity userGroupEntity
* @return userGroupEntity
*/
public UserGroupEntity populateRemainingUserGroupEntityContent(UserGroupEntity userGroupEntity) {
if (userGroupEntity.getComponent() != null) {
populateRemainingUserGroupContent(userGroupEntity.getComponent());
}
return userGroupEntity;
}
/**
* Populates the uri for the specified userGroup.
*/
public UserGroupDTO populateRemainingUserGroupContent(UserGroupDTO userGroup) {
// populate the user group href
userGroup.setUri(generateResourceUri("user-groups", userGroup.getId()));
return userGroup;
}
/**
* Creates a new user group.
*
* @param httpServletRequest request
* @param userGroupEntity An userGroupEntity.
* @return An userGroupEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Creates a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response createUserGroup(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user group configuration details.",
required = true
) final UserGroupEntity userGroupEntity) {
if (userGroupEntity == null || userGroupEntity.getComponent() == null) {
throw new IllegalArgumentException("User group details must be specified.");
}
if (userGroupEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("User group ID cannot be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, userGroupEntity);
}
// handle expects request (usually from the cluster manager)
final boolean validationPhase = isValidationPhase(httpServletRequest);
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable userGroups = lookup.getUserGroupsAuthorizable();
userGroups.authorize(authorizer, RequestAction.WRITE);
});
}
if (validationPhase) {
return generateContinueResponse().build();
}
// set the user group id as appropriate
userGroupEntity.getComponent().setId(generateUuid());
// get revision from the config
final RevisionDTO revisionDTO = userGroupEntity.getRevision();
Revision revision = new Revision(revisionDTO.getVersion(), revisionDTO.getClientId(), userGroupEntity.getComponent().getId());
// create the user group and generate the json
final UserGroupEntity entity = serviceFacade.createUserGroup(revision, userGroupEntity.getComponent());
populateRemainingUserGroupEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
}
/**
* Retrieves the specified user group.
*
* @param id The id of the user group to retrieve
* @return An userGroupEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getUserGroup(
@ApiParam(
value = "The user group id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable userGroups = lookup.getUserGroupsAuthorizable();
userGroups.authorize(authorizer, RequestAction.READ);
});
// get the user group
final UserGroupEntity entity = serviceFacade.getUserGroup(id, true);
populateRemainingUserGroupEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Updates a user group.
*
* @param httpServletRequest request
* @param id The id of the user group to update.
* @param userGroupEntity An userGroupEntity.
* @return An userGroupEntity.
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Updates a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response updateUserGroup(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user group id.",
required = true
)
@PathParam("id") final String id,
@ApiParam(
value = "The user group configuration details.",
required = true
) final UserGroupEntity userGroupEntity) {
if (userGroupEntity == null || userGroupEntity.getComponent() == null) {
throw new IllegalArgumentException("User group details must be specified.");
}
if (userGroupEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
// ensure the ids are the same
final UserGroupDTO userGroupDTO = userGroupEntity.getComponent();
if (!id.equals(userGroupDTO.getId())) {
throw new IllegalArgumentException(String.format("The user group id (%s) in the request body does not equal the "
+ "user group id of the requested resource (%s).", userGroupDTO.getId(), id));
}
if (isReplicateRequest()) {
return replicate(HttpMethod.PUT, userGroupEntity);
}
// Extract the revision
final Revision revision = getRevision(userGroupEntity, id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable userGroups = lookup.getUserGroupsAuthorizable();
userGroups.authorize(authorizer, RequestAction.WRITE);
},
null,
() -> {
// update the user group
final UpdateResult<UserGroupEntity> updateResult = serviceFacade.updateUserGroup(revision, userGroupDTO);
// get the results
final UserGroupEntity entity = updateResult.getResult();
populateRemainingUserGroupEntityContent(entity);
if (updateResult.isNew()) {
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
} else {
return clusterContext(generateOkResponse(entity)).build();
}
}
);
}
/**
* Removes the specified user group.
*
* @param httpServletRequest request
* @param version The revision is used to verify the client is working with
* the latest version of the flow.
* @param clientId Optional client id. If the client id is not specified, a
* new one will be generated. This value (whether specified or generated) is
* included in the response.
* @param id The id of the user group to remove.
* @return A entity containing the client id and an updated revision.
*/
@DELETE
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Deletes a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response removeUserGroup(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The revision is used to verify the client is working with the latest version of the flow.",
required = false
)
@QueryParam(VERSION) final LongParameter version,
@ApiParam(
value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
required = false
)
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) final ClientIdParameter clientId,
@ApiParam(
value = "The user group id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.DELETE);
}
// handle expects request (usually from the cluster manager)
final Revision revision = new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable userGroups = lookup.getUserGroupsAuthorizable();
userGroups.authorize(authorizer, RequestAction.READ);
},
() -> {
},
() -> {
// delete the specified user group
final UserGroupEntity entity = serviceFacade.deleteUserGroup(revision, id);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
}

View File

@ -0,0 +1,385 @@
/*
* 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.web.api;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.Revision;
import org.apache.nifi.web.UpdateResult;
import org.apache.nifi.web.api.dto.RevisionDTO;
import org.apache.nifi.web.api.dto.UserDTO;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.request.ClientIdParameter;
import org.apache.nifi.web.api.request.LongParameter;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
@Path("/users")
@Api(
value = "/users",
description = "Endpoint for managing users."
)
public class UsersResource extends ApplicationResource {
private final NiFiServiceFacade serviceFacade;
private final Authorizer authorizer;
public UsersResource(NiFiServiceFacade serviceFacade, Authorizer authorizer, NiFiProperties properties, RequestReplicator requestReplicator, ClusterCoordinator clusterCoordinator) {
this.serviceFacade = serviceFacade;
this.authorizer = authorizer;
setProperties(properties);
setRequestReplicator(requestReplicator);
setClusterCoordinator(clusterCoordinator);
}
/**
* Populates the uri for the specified user.
*
* @param userEntity userEntity
* @return userEntity
*/
public UserEntity populateRemainingUserEntityContent(UserEntity userEntity) {
if (userEntity.getComponent() != null) {
populateRemainingUserContent(userEntity.getComponent());
}
return userEntity;
}
/**
* Populates the uri for the specified user.
*/
public UserDTO populateRemainingUserContent(UserDTO user) {
// populate the user href
user.setUri(generateResourceUri("users", user.getId()));
return user;
}
/**
* Creates a new user.
*
* @param httpServletRequest request
* @param userEntity An userEntity.
* @return An userEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Creates a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response createUser(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user configuration details.",
required = true
) final UserEntity userEntity) {
if (userEntity == null || userEntity.getComponent() == null) {
throw new IllegalArgumentException("User details must be specified.");
}
if (userEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("User ID cannot be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, userEntity);
}
// handle expects request (usually from the cluster manager)
final boolean validationPhase = isValidationPhase(httpServletRequest);
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable users = lookup.getUsersAuthorizable();
users.authorize(authorizer, RequestAction.WRITE);
});
}
if (validationPhase) {
return generateContinueResponse().build();
}
// set the user id as appropriate
userEntity.getComponent().setId(generateUuid());
// get revision from the config
final RevisionDTO revisionDTO = userEntity.getRevision();
Revision revision = new Revision(revisionDTO.getVersion(), revisionDTO.getClientId(), userEntity.getComponent().getId());
// create the user and generate the json
final UserEntity entity = serviceFacade.createUser(revision, userEntity.getComponent());
populateRemainingUserEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
}
/**
* Retrieves the specified user.
*
* @param id The id of the user to retrieve
* @return An userEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getUser(
@ApiParam(
value = "The user id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable users = lookup.getUsersAuthorizable();
users.authorize(authorizer, RequestAction.READ);
});
// get the user
final UserEntity entity = serviceFacade.getUser(id, true);
populateRemainingUserEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Updates a user.
*
* @param httpServletRequest request
* @param id The id of the user to update.
* @param userEntity An userEntity.
* @return An userEntity.
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Updates a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response updateUser(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user id.",
required = true
)
@PathParam("id") final String id,
@ApiParam(
value = "The user configuration details.",
required = true
) final UserEntity userEntity) {
if (userEntity == null || userEntity.getComponent() == null) {
throw new IllegalArgumentException("User details must be specified.");
}
if (userEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
// ensure the ids are the same
final UserDTO userDTO = userEntity.getComponent();
if (!id.equals(userDTO.getId())) {
throw new IllegalArgumentException(String.format("The user id (%s) in the request body does not equal the "
+ "user id of the requested resource (%s).", userDTO.getId(), id));
}
if (isReplicateRequest()) {
return replicate(HttpMethod.PUT, userEntity);
}
// Extract the revision
final Revision revision = getRevision(userEntity, id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable users = lookup.getUsersAuthorizable();
users.authorize(authorizer, RequestAction.WRITE);
},
null,
() -> {
// update the user
final UpdateResult<UserEntity> updateResult = serviceFacade.updateUser(revision, userDTO);
// get the results
final UserEntity entity = updateResult.getResult();
populateRemainingUserEntityContent(entity);
if (updateResult.isNew()) {
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
} else {
return clusterContext(generateOkResponse(entity)).build();
}
}
);
}
/**
* Removes the specified user.
*
* @param httpServletRequest request
* @param version The revision is used to verify the client is working with
* the latest version of the flow.
* @param clientId Optional client id. If the client id is not specified, a
* new one will be generated. This value (whether specified or generated) is
* included in the response.
* @param id The id of the user to remove.
* @return A entity containing the client id and an updated revision.
*/
@DELETE
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Deletes a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response removeUser(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The revision is used to verify the client is working with the latest version of the flow.",
required = false
)
@QueryParam(VERSION) final LongParameter version,
@ApiParam(
value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
required = false
)
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) final ClientIdParameter clientId,
@ApiParam(
value = "The user id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.DELETE);
}
// handle expects request (usually from the cluster manager)
final Revision revision = new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable users = lookup.getUsersAuthorizable();
users.authorize(authorizer, RequestAction.READ);
},
() -> {
},
() -> {
// delete the specified user
final UserEntity entity = serviceFacade.deleteUser(revision, id);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
}

View File

@ -34,9 +34,12 @@ import org.apache.nifi.action.details.PurgeDetails;
import org.apache.nifi.annotation.behavior.Stateful;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.Resource;
import org.apache.nifi.authorization.User;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.cluster.coordination.heartbeat.NodeHeartbeat;
import org.apache.nifi.cluster.coordination.node.NodeConnectionStatus;
@ -136,6 +139,8 @@ import org.apache.nifi.web.api.dto.status.ProcessorStatusSnapshotDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusSnapshotDTO;
import org.apache.nifi.web.api.entity.FlowBreadcrumbEntity;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import org.apache.nifi.web.controller.ControllerFacade;
import org.apache.nifi.web.revision.RevisionManager;
@ -675,6 +680,44 @@ public final class DtoFactory {
return dto;
}
/**
* Creates a {@link UserDTO} from the specified {@link User}.
*
* @param user user
* @return dto
*/
public UserDTO createUserDto(final User user, final Set<UserGroupEntity> groups) {
if (user == null) {
return null;
}
final UserDTO dto = new UserDTO();
dto.setId(user.getIdentifier());
dto.setGroups(groups);
dto.setIdentity(user.getIdentity());
return dto;
}
/**
* Creates a {@link UserGroupDTO} from the specified {@link Group}.
*
* @param userGroup user group
* @return dto
*/
public UserGroupDTO createUserGroupDto(final Group userGroup, Set<UserEntity> users) {
if (userGroup == null) {
return null;
}
final UserGroupDTO dto = new UserGroupDTO();
dto.setId(userGroup.getIdentifier());
dto.setUsers(users);
dto.setName(userGroup.getName());
return dto;
}
/**
* Creates a FunnelDTO from the specified Funnel.
*
@ -1469,6 +1512,23 @@ public final class DtoFactory {
return dto;
}
public AccessPolicyDTO createAccessPolicyDto(final AccessPolicy accessPolicy, Set<UserGroupEntity> userGroups, Set<UserEntity> users) {
if (accessPolicy == null) {
return null;
}
final AccessPolicyDTO dto = new AccessPolicyDTO();
dto.setUserGroups(userGroups);
dto.setUsers(users);
dto.setId(accessPolicy.getIdentifier());
dto.setResource(accessPolicy.getResource());
Set<RequestAction> accessPolicyActions = accessPolicy.getActions();
dto.setCanRead(accessPolicyActions.contains(RequestAction.READ));
dto.setCanWrite(accessPolicyActions.contains(RequestAction.WRITE));
return dto;
}
/**
* Creates the AccessPolicyDTO based on the specified Authorizable.
*

View File

@ -23,6 +23,7 @@ import org.apache.nifi.web.api.dto.status.PortStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
import org.apache.nifi.web.api.entity.AccessPolicyEntity;
import org.apache.nifi.web.api.entity.ConnectionEntity;
import org.apache.nifi.web.api.entity.ControllerConfigurationEntity;
import org.apache.nifi.web.api.entity.ControllerServiceEntity;
@ -38,6 +39,8 @@ import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupPortEntity;
import org.apache.nifi.web.api.entity.ReportingTaskEntity;
import org.apache.nifi.web.api.entity.SnippetEntity;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import java.util.List;
@ -144,6 +147,48 @@ public final class EntityFactory {
return entity;
}
public UserEntity createUserEntity(final UserDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
final UserEntity entity = new UserEntity();
entity.setRevision(revision);
if (dto != null) {
entity.setAccessPolicy(accessPolicy);
entity.setId(dto.getId());
if (accessPolicy != null && accessPolicy.getCanRead()) {
entity.setComponent(dto);
}
}
return entity;
}
public UserGroupEntity createUserGroupEntity(final UserGroupDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
final UserGroupEntity entity = new UserGroupEntity();
entity.setRevision(revision);
if (dto != null) {
entity.setAccessPolicy(accessPolicy);
entity.setId(dto.getId());
if (accessPolicy != null && accessPolicy.getCanRead()) {
entity.setComponent(dto);
}
}
return entity;
}
public AccessPolicyEntity createAccessPolicyEntity(final AccessPolicyDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
final AccessPolicyEntity entity = new AccessPolicyEntity();
entity.setRevision(revision);
if (dto != null) {
entity.setAccessPolicy(accessPolicy);
entity.setId(dto.getId());
if (accessPolicy != null && accessPolicy.getCanRead()) {
entity.setComponent(dto);
}
}
return entity;
}
public FunnelEntity createFunnelEntity(final FunnelDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
final FunnelEntity entity = new FunnelEntity();
entity.setRevision(revision);

View File

@ -0,0 +1,63 @@
/*
* 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.web.dao;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.web.api.dto.AccessPolicyDTO;
public interface AccessPolicyDAO {
/**
* @param accessPolicyId access policy ID
* @return Determines if the specified access policy exists
*/
boolean hasAccessPolicy(String accessPolicyId);
/**
* Creates an access policy.
*
* @param accessPolicyDTO The access policy DTO
* @return The access policy transfer object
*/
AccessPolicy createAccessPolicy(AccessPolicyDTO accessPolicyDTO);
/**
* Gets the acess policy with the specified ID.
*
* @param accessPolicyId The access policy ID
* @return The access policy transfer object
*/
AccessPolicy getAccessPolicy(String accessPolicyId);
/**
* Updates the specified access policy.
*
* @param accessPolicyDTO The access policy DTO
* @return The access policy transfer object
*/
AccessPolicy updateAccessPolicy(AccessPolicyDTO accessPolicyDTO);
/**
* Deletes the specified access policy.
*
* @param accessPolicyId The access policy ID
* @return The access policy transfer object of the deleted access policy
*/
AccessPolicy deleteAccessPolicy(String accessPolicyId);
}

View File

@ -0,0 +1,62 @@
/*
* 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.web.dao;
import org.apache.nifi.authorization.User;
import org.apache.nifi.web.api.dto.UserDTO;
public interface UserDAO {
/**
* @param userId user ID
* @return Determines if the specified user exists
*/
boolean hasUser(String userId);
/**
* Creates a user.
*
* @param userDTO The user DTO
* @return The user transfer object
*/
User createUser(UserDTO userDTO);
/**
* Gets the user with the specified ID.
*
* @param userId The user ID
* @return The user transfer object
*/
User getUser(String userId);
/**
* Updates the specified user.
*
* @param userDTO The user DTO
* @return The user transfer object
*/
User updateUser(UserDTO userDTO);
/**
* Deletes the specified user.
*
* @param userId The user ID
* @return The user transfer object of the deleted user
*/
User deleteUser(String userId);
}

View File

@ -0,0 +1,62 @@
/*
* 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.web.dao;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.web.api.dto.UserGroupDTO;
public interface UserGroupDAO {
/**
* @param userGroupId user group ID
* @return Determines if the specified user group exists
*/
boolean hasUserGroup(String userGroupId);
/**
* Creates a user group.
*
* @param userGroupDTO The user group DTO
* @return The user group transfer object
*/
Group createUserGroup(UserGroupDTO userGroupDTO);
/**
* Gets the user group with the specified ID.
*
* @param userGroupId The user group ID
* @return The user group transfer object
*/
Group getUserGroup(String userGroupId);
/**
* Updates the specified user group.
*
* @param userGroupDTO The user group DTO
* @return The user group transfer object
*/
Group updateUserGroup(UserGroupDTO userGroupDTO);
/**
* Deletes the specified user group.
*
* @param userGroupId The user group ID
* @return The user group transfer object of the deleted user group
*/
Group deleteUserGroup(String userGroupId);
}

View File

@ -0,0 +1,255 @@
/*
* 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.web.dao.impl;
import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.AuthorizerConfigurationContext;
import org.apache.nifi.authorization.AuthorizerInitializationContext;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.User;
import org.apache.nifi.authorization.UsersAndAccessPolicies;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.web.api.dto.AccessPolicyDTO;
import org.apache.nifi.web.api.dto.UserDTO;
import org.apache.nifi.web.api.dto.UserGroupDTO;
import org.apache.nifi.web.api.entity.ComponentEntity;
import org.apache.nifi.web.dao.AccessPolicyDAO;
import org.apache.nifi.web.dao.UserDAO;
import org.apache.nifi.web.dao.UserGroupDAO;
import java.util.Set;
import java.util.stream.Collectors;
public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGroupDAO, UserDAO {
private static final String MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER = "authorizer is not of type AbstractPolicyBasedAuthorizer";
private final AbstractPolicyBasedAuthorizer authorizer;
public StandardPolicyBasedAuthorizerDAO(final Authorizer authorizer) {
if (authorizer instanceof AbstractPolicyBasedAuthorizer) {
this.authorizer = (AbstractPolicyBasedAuthorizer) authorizer;
} else {
this.authorizer = new AbstractPolicyBasedAuthorizer() {
@Override
public Group addGroup(final Group group) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public Group getGroup(final String identifier) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public Group updateGroup(final Group group) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public Group deleteGroup(final Group group) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public Set<Group> getGroups() throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public User addUser(final User user) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public User getUser(final String identifier) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public User getUserByIdentity(final String identity) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public User updateUser(final User user) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public User deleteUser(final User user) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public Set<User> getUsers() throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public AccessPolicy addAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public AccessPolicy getAccessPolicy(final String identifier) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public AccessPolicy updateAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public AccessPolicy deleteAccessPolicy(final AccessPolicy policy) throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public UsersAndAccessPolicies getUsersAndAccessPolicies() throws AuthorizationAccessException {
throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
}
@Override
public void initialize(final AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
}
@Override
public void onConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
}
};
}
}
@Override
public boolean hasAccessPolicy(final String accessPolicyId) {
return authorizer.getAccessPolicy(accessPolicyId) != null;
}
@Override
public AccessPolicy createAccessPolicy(final AccessPolicyDTO accessPolicyDTO) {
return authorizer.addAccessPolicy(buildAccessPolicy(accessPolicyDTO));
}
@Override
public AccessPolicy getAccessPolicy(final String accessPolicyId) {
return authorizer.getAccessPolicy(accessPolicyId);
}
@Override
public AccessPolicy updateAccessPolicy(final AccessPolicyDTO accessPolicyDTO) {
return authorizer.updateAccessPolicy(buildAccessPolicy(accessPolicyDTO));
}
@Override
public AccessPolicy deleteAccessPolicy(final String accessPolicyId) {
return authorizer.deleteAccessPolicy(authorizer.getAccessPolicy(accessPolicyId));
}
private AccessPolicy buildAccessPolicy(final AccessPolicyDTO accessPolicyDTO) {
final AccessPolicy.Builder builder = new AccessPolicy.Builder()
.identifier(accessPolicyDTO.getId())
.addGroups(accessPolicyDTO.getUserGroups().stream().map(ComponentEntity::getId).collect(Collectors.toSet()))
.addUsers(accessPolicyDTO.getUsers().stream().map(ComponentEntity::getId).collect(Collectors.toSet()))
.resource(accessPolicyDTO.getResource());
if (accessPolicyDTO.getCanRead()) {
builder.addAction(RequestAction.READ);
}
if (accessPolicyDTO.getCanWrite()) {
builder.addAction(RequestAction.WRITE);
}
return builder.build();
}
@Override
public boolean hasUserGroup(final String userGroupId) {
return authorizer.getGroup(userGroupId) != null;
}
@Override
public Group createUserGroup(final UserGroupDTO userGroupDTO) {
return authorizer.addGroup(buildUserGroup(userGroupDTO));
}
@Override
public Group getUserGroup(final String userGroupId) {
return authorizer.getGroup(userGroupId);
}
@Override
public Group updateUserGroup(final UserGroupDTO userGroupDTO) {
return authorizer.updateGroup(buildUserGroup(userGroupDTO));
}
@Override
public Group deleteUserGroup(final String userGroupId) {
return authorizer.deleteGroup(authorizer.getGroup(userGroupId));
}
private Group buildUserGroup(final UserGroupDTO userGroupDTO) {
return new Group.Builder()
.addUsers(userGroupDTO.getUsers().stream().map(ComponentEntity::getId).collect(Collectors.toSet()))
.identifier(userGroupDTO.getId()).name(userGroupDTO.getName()).build();
}
@Override
public boolean hasUser(final String userId) {
return authorizer.getUser(userId) != null;
}
@Override
public User createUser(final UserDTO userDTO) {
final User user = buildUser(userDTO);
return authorizer.addUser(user);
}
@Override
public User getUser(final String userId) {
return authorizer.getUser(userId);
}
@Override
public User updateUser(final UserDTO userDTO) {
return authorizer.updateUser(buildUser(userDTO));
}
@Override
public User deleteUser(final String userId) {
return authorizer.deleteUser(authorizer.getUser(userId));
}
private User buildUser(final UserDTO userDTO) {
return new User.Builder()
.addGroups(userDTO.getGroups().stream().map(ComponentEntity::getId).collect(Collectors.toSet()))
.identifier(userDTO.getIdentity()).identity(userDTO.getIdentity()).build();
}
}

View File

@ -108,6 +108,9 @@
<property name="flowController" ref="flowController"/>
<property name="snippetUtils" ref="snippetUtils"/>
</bean>
<bean id="policyBasedAuthorizerDAO" class="org.apache.nifi.web.dao.impl.StandardPolicyBasedAuthorizerDAO">
<constructor-arg ref="authorizer"/>
</bean>
<bean id="controllerFacade" class="org.apache.nifi.web.controller.ControllerFacade">
<property name="properties" ref="nifiProperties"/>
<property name="flowController" ref="flowController"/>
@ -117,7 +120,24 @@
<property name="dtoFactory" ref="dtoFactory"/>
<property name="bulletinRepository" ref="bulletinRepository"/>
</bean>
<bean id="authorizableLookup" class="org.apache.nifi.web.StandardAuthorizableLookup">
<property name="controllerFacade" ref="controllerFacade"/>
<property name="processorDAO" ref="processorDAO"/>
<property name="inputPortDAO" ref="inputPortDAO"/>
<property name="outputPortDAO" ref="outputPortDAO"/>
<property name="processGroupDAO" ref="processGroupDAO"/>
<property name="remoteProcessGroupDAO" ref="remoteProcessGroupDAO"/>
<property name="labelDAO" ref="labelDAO"/>
<property name="funnelDAO" ref="funnelDAO"/>
<property name="connectionDAO" ref="connectionDAO"/>
<property name="controllerServiceDAO" ref="controllerServiceDAO"/>
<property name="reportingTaskDAO" ref="reportingTaskDAO"/>
<property name="templateDAO" ref="templateDAO"/>
<property name="snippetDAO" ref="snippetDAO"/>
<property name="accessPolicyDAO" ref="policyBasedAuthorizerDAO"/>
</bean>
<bean id="serviceFacade" class="org.apache.nifi.web.StandardNiFiServiceFacade">
<property name="authorizableLookup" ref="authorizableLookup" />
<property name="properties" ref="nifiProperties"/>
<property name="authorizer" ref="authorizer"/>
<property name="controllerFacade" ref="controllerFacade"/>
@ -133,6 +153,9 @@
<property name="reportingTaskDAO" ref="reportingTaskDAO"/>
<property name="templateDAO" ref="templateDAO"/>
<property name="snippetDAO" ref="snippetDAO"/>
<property name="accessPolicyDAO" ref="policyBasedAuthorizerDAO"/>
<property name="userGroupDAO" ref="policyBasedAuthorizerDAO"/>
<property name="userDAO" ref="policyBasedAuthorizerDAO"/>
<property name="auditService" ref="auditService"/>
<property name="keyService" ref="keyService"/>
<property name="snippetUtils" ref="snippetUtils"/>
@ -342,6 +365,27 @@
<property name="clusterCoordinator" ref="clusterCoordinator"/>
<property name="requestReplicator" ref="requestReplicator" />
</bean>
<bean id="accessPolicyResource" class="org.apache.nifi.web.api.AccessPolicyResource" scope="singleton">
<constructor-arg ref="serviceFacade"/>
<constructor-arg ref="authorizer"/>
<constructor-arg ref="nifiProperties"/>
<constructor-arg ref="clusterCoordinator"/>
<constructor-arg ref="requestReplicator" />
</bean>
<bean id="userGroupsResource" class="org.apache.nifi.web.api.UserGroupsResource" scope="singleton">
<constructor-arg ref="serviceFacade"/>
<constructor-arg ref="authorizer"/>
<constructor-arg ref="nifiProperties"/>
<constructor-arg ref="clusterCoordinator"/>
<constructor-arg ref="requestReplicator" />
</bean>
<bean id="usersResource" class="org.apache.nifi.web.api.UsersResource" scope="singleton">
<constructor-arg ref="serviceFacade"/>
<constructor-arg ref="authorizer"/>
<constructor-arg ref="nifiProperties"/>
<constructor-arg ref="clusterCoordinator"/>
<constructor-arg ref="requestReplicator" />
</bean>
<!-- configuration for jaxb serialization -->
<bean class="org.apache.nifi.web.util.ObjectMapperResolver" scope="singleton"/>

View File

@ -0,0 +1,896 @@
/*
* 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.web
import org.apache.nifi.authorization.*
import org.apache.nifi.authorization.resource.Authorizable
import org.apache.nifi.authorization.resource.ResourceFactory
import org.apache.nifi.authorization.user.NiFiUser
import org.apache.nifi.controller.service.ControllerServiceProvider
import org.apache.nifi.web.api.dto.*
import org.apache.nifi.web.api.entity.UserEntity
import org.apache.nifi.web.controller.ControllerFacade
import org.apache.nifi.web.dao.AccessPolicyDAO
import org.apache.nifi.web.dao.UserDAO
import org.apache.nifi.web.dao.UserGroupDAO
import org.apache.nifi.web.revision.*
import spock.lang.Specification
import spock.lang.Unroll
class StandardNiFiServiceFacadeSpec extends Specification {
@Unroll
def "CreateUser: isAuthorized: #isAuthorized"() {
given:
def userDao = Mock UserDAO
def entityFactory = new EntityFactory()
def dtoFactory = new DtoFactory()
def authorizableLookup = Mock AuthorizableLookup
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setUserDAO userDao
niFiServiceFacade.setEntityFactory entityFactory
def newUser = new User.Builder().identifier(userDto.id).identity(userDto.identity).build()
when:
def userEntity = niFiServiceFacade.createUser(new Revision(0L, 'client-1'), userDto)
then:
1 * userDao.createUser(_) >> newUser
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(parentAuthorizable, resource, isAuthorized, authorizationResult)
0 * _
userEntity != null
if (isAuthorized) {
assert userEntity?.component?.id == userDto.id
assert userEntity?.component?.identity?.equals(userDto.identity)
assert userEntity?.accessPolicy?.canRead
assert userEntity?.accessPolicy?.canWrite
} else {
assert userEntity.component == null
}
where:
userDto | parentAuthorizable | resource | isAuthorized | authorizationResult
createUserDTO() | null | ResourceFactory.usersResource | true | AuthorizationResult.approved()
createUserDTO() | null | ResourceFactory.usersResource | false | AuthorizationResult.denied()
}
@Unroll
def "GetUser: isAuthorized: #isAuthorized"() {
given:
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def authorizableLookup = Mock AuthorizableLookup
def dtoFactory = new DtoFactory()
def entityFactory = new EntityFactory()
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setUserDAO userDao
def requestedUser = new User.Builder().identifier(userDto.id).identity(userDto.identity).build()
def exception = null
def userEntity = null
when:
try {
userEntity = niFiServiceFacade.getUser(userDto.id, true)
} catch (AccessDeniedException e) {
exception = e
}
then:
if (isAuthorized) {
1 * userDao.getUser(userDto.id) >> requestedUser
}
1 * revisionManager.get(_, _) >> { String id, ReadOnlyRevisionCallback callback ->
callback.withRevision(new Revision(1L, 'client1', 'root'))
}
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.getUsersResource(),
isAuthorized, authorizationResult)
0 * _
if (isAuthorized) {
assert userEntity?.component?.id?.equals(userDto.id)
} else {
assert exception instanceof AccessDeniedException
}
where:
userDto | isAuthorized | authorizationResult
createUserDTO() | true | AuthorizationResult.approved()
createUserDTO() | false | AuthorizationResult.denied()
}
@Unroll
def "UpdateUser: isAuthorized: #isAuthorized, policy exists: #userExists"() {
given:
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def entityFactory = new EntityFactory()
def dtoFactory = new DtoFactory()
def authorizableLookup = Mock AuthorizableLookup
def controllerFacade = Mock ControllerFacade
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setUserDAO userDao
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setControllerFacade controllerFacade
def user = new User.Builder().identifier(userDto.id).identity(userDto.identity).build()
when:
def userEntityUpdateResult = niFiServiceFacade.updateUser(currentRevision, userDto)
then:
1 * userDao.hasUser(userDto.id) >> userExists
if (!userExists) {
1 * userDao.createUser(userDto) >> user
} else {
1 * controllerFacade.save()
1 * userDao.updateUser(userDto) >> user
1 * revisionManager.updateRevision(_, _, _) >> { RevisionClaim revisionClaim, NiFiUser niFiUser, UpdateRevisionTask callback ->
callback.update()
}
}
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.getUsersResource(),
isAuthorized, authorizationResult)
0 * _
userEntityUpdateResult != null
def userEntity = userEntityUpdateResult?.result
if (isAuthorized) {
assert userEntity?.component?.id?.equals(userDto.id)
assert userEntity?.accessPolicy?.canRead
assert userEntity?.accessPolicy?.canWrite
} else {
assert userEntity.component == null
}
where:
userExists | currentRevision | userDto | isAuthorized | authorizationResult
false | new Revision(0L, 'client1', 'root') | createUserDTO() | true | AuthorizationResult.approved()
true | new Revision(1L, 'client1', 'root') | createUserDTO() | true | AuthorizationResult.approved()
false | new Revision(0L, 'client1', 'root') | createUserDTO() | false | AuthorizationResult.denied()
true | new Revision(1L, 'client1', 'root') | createUserDTO() | false | AuthorizationResult.denied()
}
@Unroll
def "DeleteUser: isAuthorized: #isAuthorized, user exists: #userExists"() {
given:
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def authorizableLookup = Mock AuthorizableLookup
def dtoFactory = new DtoFactory()
def entityFactory = new EntityFactory()
def controllerFacade = Mock ControllerFacade
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setUserDAO userDao
niFiServiceFacade.setControllerFacade controllerFacade
def user = new User.Builder().identifier(userDto.id).identity(userDto.identity).build()
when:
def userEntity = niFiServiceFacade.deleteUser(currentRevision, userDto.id)
then:
if (userExists) {
1 * userDao.getUser(userDto.id) >> user
1 * userDao.deleteUser(userDto.id) >> user
} else {
1 * userDao.getUser(userDto.id) >> null
1 * userDao.deleteUser(userDto.id) >> null
}
1 * controllerFacade.save()
1 * revisionManager.deleteRevision(_, _, _) >> { RevisionClaim revisionClaim, NiFiUser nifiUser, DeleteRevisionTask task ->
task.performTask()
}
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.usersResource,
isAuthorized, authorizationResult)
0 * _
userEntity?.component?.id == null
if (userExists) {
assert userEntity?.id?.equals(userDto.id)
} else {
assert userEntity?.id == null
}
where:
userExists | currentRevision | userDto | isAuthorized | authorizationResult
true | new Revision(1L, 'client1') | createUserDTO() | true | AuthorizationResult.approved()
false | null | createUserDTO() | true | AuthorizationResult.approved()
true | new Revision(1L, 'client1') | createUserDTO() | false | AuthorizationResult.denied()
false | null | createUserDTO() | false | AuthorizationResult.denied()
}
@Unroll
def "CreateUserGroup: isAuthorized: #isAuthorized"() {
given:
def userGroupDao = Mock UserGroupDAO
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def controllerServiceProvider = Mock ControllerServiceProvider
def entityFactory = new EntityFactory()
def dtoFactory = new DtoFactory()
dtoFactory.setControllerServiceProvider controllerServiceProvider
dtoFactory.setEntityFactory entityFactory
def authorizableLookup = Mock AuthorizableLookup
def controllerFacade = Mock ControllerFacade
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setUserGroupDAO userGroupDao
niFiServiceFacade.setUserDAO userDao
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setControllerFacade controllerFacade
def newUserGroup = new Group.Builder().identifier(userGroupDto.id).name(userGroupDto.name).addUsers(userGroupDto.users.collect { it.id } as Set).build()
def exception = null
def userGroupEntity = null
when:
try {
userGroupEntity = niFiServiceFacade.createUserGroup(new Revision(0L, 'client-1'), userGroupDto)
} catch (AccessDeniedException e) {
exception = e
}
then:
if (isAuthorized) {
1 * authorizableLookup.getUserGroupsAuthorizable() >>
new SimpleAuthorizable(null, ResourceFactory.userGroupsResource, isAuthorized, authorizationResult.get(ResourceFactory.userGroupsResource))
}
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.usersResource, isAuthorized, authorizationResult.get(ResourceFactory.usersResource))
1 * userGroupDao.createUserGroup(_) >> newUserGroup
if (authorizationResult.get(ResourceFactory.usersResource) == AuthorizationResult.approved()) {
1 * userDao.getUser(_) >> { String userId ->
def userEntity = userGroupDto.users.find { it.id.equals(userId) }?.component
assert userEntity != null
new User.Builder().identifier(userEntity.id).identity(userEntity.identity)
.addGroups(userEntity.groups.collect { it.id } as Set)
.build()
}
}
userGroupDto.users.size() * revisionManager.get(_, _) >> { String id, ReadOnlyRevisionCallback callback ->
assert userGroupDto.users.collect { it.id }.contains(id)
def revisionDTO = userGroupDto.users.find { it.id.equals(id) }.revision
callback.withRevision new Revision(revisionDTO.version, revisionDTO.clientId, id)
}
0 * _
if (isAuthorized) {
assert userGroupEntity?.component?.id == userGroupDto.id
assert userGroupEntity?.component?.users?.equals(userGroupDto.users)
assert userGroupEntity?.accessPolicy?.canRead
assert userGroupEntity?.accessPolicy?.canWrite
} else {
assert userGroupEntity?.component == null
assert exception instanceof AccessDeniedException
}
where: // TODO add more use cases, specifically with varied authorization results, and the assertions to check them, to all spec methods that use AuthorizationResult
userGroupDto | isAuthorized | authorizationResult
createUserGroupDTO() | true | [(ResourceFactory.userGroupsResource): AuthorizationResult.approved(), (ResourceFactory.usersResource): AuthorizationResult.approved()]
createUserGroupDTO() | false | [(ResourceFactory.userGroupsResource): AuthorizationResult.denied(), (ResourceFactory.usersResource): AuthorizationResult.denied()]
}
@Unroll
def "GetUserGroup: isAuthorized: #isAuthorized"() {
given:
def userGroupDao = Mock UserGroupDAO
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def authorizableLookup = Mock AuthorizableLookup
def dtoFactory = new DtoFactory()
def entityFactory = new EntityFactory()
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setUserGroupDAO userGroupDao
niFiServiceFacade.setUserDAO userDao
def requestedUserGroup = new Group.Builder().identifier(userGroupDto.id).name(userGroupDto.name)
.addUsers(userGroupDto.users.collect { it.id } as Set).build()
def exception = null
def userGroupEntity = null
when:
try {
userGroupEntity = niFiServiceFacade.getUserGroup(userGroupDto.id, true)
} catch (AccessDeniedException e) {
exception = e
}
then:
if (isAuthorized) {
1 * userGroupDao.getUserGroup(userGroupDto.id) >> requestedUserGroup
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.usersResource, isAuthorized, authorizationResult)
}
1 * authorizableLookup.getUserGroupsAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.getUserGroupsResource(),
isAuthorized, authorizationResult)
_ * revisionManager.get(_, _) >> { String id, ReadOnlyRevisionCallback callback ->
callback.withRevision(new Revision(1L, 'client1', 'root'))
}
if (authorizationResult == AuthorizationResult.approved()) {
1 * userDao.getUser(_) >> { String userId ->
def userEntity = userGroupDto.users.find { it.id.equals(userId) }?.component
assert userEntity != null
new User.Builder().identifier(userEntity.id).identity(userEntity.identity).build()
}
}
0 * _
if (isAuthorized) {
assert userGroupEntity?.component?.id?.equals(userGroupDto.id)
} else {
assert exception instanceof AccessDeniedException
}
where:
userGroupDto | isAuthorized | authorizationResult
new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | true | AuthorizationResult.approved()
new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | false | AuthorizationResult.denied()
}
@Unroll
def "UpdateUserGroup: isAuthorized: #isAuthorized, userGroupExists exists: #userGroupExists"() {
given:
def userGroupDao = Mock UserGroupDAO
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def entityFactory = new EntityFactory()
def dtoFactory = new DtoFactory()
def authorizableLookup = Mock AuthorizableLookup
def controllerFacade = Mock ControllerFacade
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setUserGroupDAO userGroupDao
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setControllerFacade controllerFacade
niFiServiceFacade.setUserDAO userDao
def userGroup = new Group.Builder().identifier(userGroupDto.id).name(userGroupDto.name)
.addUsers(userGroupDto.users.collect { it.id } as Set).build()
def userGroupsEntityUpdateResult = null
def exception = null
when:
try {
userGroupsEntityUpdateResult = niFiServiceFacade.updateUserGroup(currentRevision, userGroupDto)
} catch (AccessDeniedException e) {
exception = e
}
then:
1 * userGroupDao.hasUserGroup(userGroupDto.id) >> userGroupExists
if (!userGroupExists) {
1 * userGroupDao.createUserGroup(userGroupDto) >> userGroup
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.getUsersResource(),
isAuthorized, authorizationResult.get(ResourceFactory.getUsersResource()))
} else {
1 * controllerFacade.save()
1 * userGroupDao.updateUserGroup(userGroupDto) >> userGroup
1 * revisionManager.updateRevision(_, _, _) >> { RevisionClaim revisionClaim, NiFiUser niFiUser, UpdateRevisionTask callback ->
callback.update()
}
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.usersResource,
isAuthorized, authorizationResult.get(ResourceFactory.usersResource))
}
if (isAuthorized || userGroupExists) {
1 * authorizableLookup.getUserGroupsAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.userGroupsResource,
isAuthorized, authorizationResult.get(ResourceFactory.userGroupsResource))
}
_ * revisionManager.get(_, _) >> { String id, ReadOnlyRevisionCallback callback ->
callback.withRevision(new Revision(1L, 'client1', 'root'))
}
if (authorizationResult.get(ResourceFactory.userGroupsResource) == AuthorizationResult.approved()) {
1 * userDao.getUser(_) >> { String userId ->
def userEntity = userGroupDto.users.find { it.id.equals(userId) }?.component
assert userEntity != null
new User.Builder().identifier(userEntity.id).identity(userEntity.identity).build()
}
}
0 * _
def userGroupEntity = userGroupsEntityUpdateResult?.result
if (isAuthorized) {
assert userGroupEntity?.component?.id?.equals(userGroupDto.id)
assert userGroupEntity?.accessPolicy?.canRead
assert userGroupEntity?.accessPolicy?.canWrite
} else {
assert userGroupEntity?.component == null
assert exception instanceof AccessDeniedException
}
where:
userGroupExists | currentRevision | userGroupDto | isAuthorized |
authorizationResult
false | new Revision(0L, 'client1', 'root') | new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | true |
[(ResourceFactory.userGroupsResource): AuthorizationResult.approved(), (ResourceFactory.usersResource): AuthorizationResult.approved()]
true | new Revision(1L, 'client1', 'root') | new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | true |
[(ResourceFactory.userGroupsResource): AuthorizationResult.approved(), (ResourceFactory.usersResource): AuthorizationResult.approved()]
false | new Revision(0L, 'client1', 'root') | new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | false |
[(ResourceFactory.userGroupsResource): AuthorizationResult.denied(), (ResourceFactory.usersResource): AuthorizationResult.denied()]
true | new Revision(1L, 'client1', 'root') | new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | false |
[(ResourceFactory.userGroupsResource): AuthorizationResult.denied(), (ResourceFactory.usersResource): AuthorizationResult.denied()]
}
@Unroll
def "DeleteUserGroup: isAuthorized: #isAuthorized, userGroup exists: #userGroupExists"() {
given:
def userGroupDao = Mock UserGroupDAO
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def authorizableLookup = Mock AuthorizableLookup
def dtoFactory = new DtoFactory()
def entityFactory = new EntityFactory()
def controllerFacade = Mock ControllerFacade
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setUserGroupDAO userGroupDao
niFiServiceFacade.setControllerFacade controllerFacade
niFiServiceFacade.setUserDAO userDao
def userGroup = new Group.Builder().identifier(userGroupDto.id).name(userGroupDto.name)
.addUsers(userGroupDto.users.collect { it.id } as Set).build()
def userGroupEntity = null
def exception = null
when:
try {
userGroupEntity = niFiServiceFacade.deleteUserGroup(currentRevision, userGroupDto.id)
} catch (AccessDeniedException e) {
exception = e
}
then:
if (userGroupExists) {
1 * userGroupDao.getUserGroup(userGroupDto.id) >> userGroup
if (isAuthorized) {
1 * userGroupDao.deleteUserGroup(userGroupDto.id) >> userGroup
}
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.getUsersResource(),
isAuthorized, authorizationResult.get(ResourceFactory.getUsersResource()))
} else {
1 * userGroupDao.getUserGroup(userGroupDto.id) >> null
1 * userGroupDao.deleteUserGroup(userGroupDto.id) >> null
}
if (!(!isAuthorized && userGroupExists)) {
1 * authorizableLookup.getUserGroupsAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.userGroupsResource,
isAuthorized, authorizationResult.get(ResourceFactory.userGroupsResource))
1 * revisionManager.deleteRevision(_, _, _) >> { RevisionClaim revisionClaim, NiFiUser nifiUser, DeleteRevisionTask task ->
task.performTask()
}
1 * controllerFacade.save()
}
_ * revisionManager.get(_, _) >> { String id, ReadOnlyRevisionCallback callback ->
callback.withRevision(new Revision(1L, 'client1', 'root'))
}
if (authorizationResult.get(ResourceFactory.userGroupsResource) == AuthorizationResult.approved() && userGroupExists) {
1 * userDao.getUser(_) >> { String userId ->
def userEntity = userGroupDto.users.find { it.id.equals(userId) }?.component
assert userEntity != null
new User.Builder().identifier(userEntity.id).identity(userEntity.identity).build()
}
}
0 * _
userGroupEntity?.component?.id == null
if (userGroupExists && isAuthorized) {
assert userGroupEntity?.id?.equals(userGroupDto.id)
} else {
assert userGroupEntity?.id == null
}
if (authorizationResult.get(ResourceFactory.usersResource) == AuthorizationResult.denied()) {
assert exception instanceof AccessDeniedException
}
where:
userGroupExists | currentRevision | userGroupDto | isAuthorized |
authorizationResult
true | new Revision(1L, 'client1', 'root') | new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | true |
[(ResourceFactory.userGroupsResource): AuthorizationResult.approved(), (ResourceFactory.usersResource): AuthorizationResult.approved()]
false | null | new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | true |
[(ResourceFactory.userGroupsResource): AuthorizationResult.approved(), (ResourceFactory.usersResource): AuthorizationResult.approved()]
true | new Revision(1L, 'client1', 'root') | new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | false |
[(ResourceFactory.userGroupsResource): AuthorizationResult.denied(), (ResourceFactory.usersResource): AuthorizationResult.denied()]
false | null | new UserGroupDTO(id: '1', name: 'test group', users: [createUserEntity()]) | false |
[(ResourceFactory.userGroupsResource): AuthorizationResult.denied(), (ResourceFactory.usersResource): AuthorizationResult.denied()]
}
@Unroll
def "CreateAccessPolicy: #isAuthorized"() {
given:
def accessPolicyDao = Mock AccessPolicyDAO
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def entityFactory = new EntityFactory()
def dtoFactory = new DtoFactory()
dtoFactory.setEntityFactory entityFactory
def authorizableLookup = Mock AuthorizableLookup
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setAccessPolicyDAO accessPolicyDao
niFiServiceFacade.setUserDAO userDao
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setRevisionManager revisionManager
def builder = new AccessPolicy.Builder().identifier(accessPolicyDto.id).resource(accessPolicyDto.resource)
.addUsers(accessPolicyDto.users.collect { it.id } as Set)
.addGroups(accessPolicyDto.userGroups.collect { it.id } as Set)
if (accessPolicyDto.canRead) {
builder.addAction(RequestAction.READ)
}
if (accessPolicyDto.canWrite) {
builder.addAction(RequestAction.WRITE)
}
def newAccessPolicy = builder.build()
def accessPolicyEntity = null
def exception = null
when:
try {
accessPolicyEntity = niFiServiceFacade.createAccessPolicy(new Revision(0L, 'client-1'), accessPolicyDto)
} catch (AccessDeniedException e) {
exception = e
}
then:
1 * accessPolicyDao.createAccessPolicy(accessPolicyDto) >> newAccessPolicy
if (isAuthorized) {
1 * authorizableLookup.getAccessPolicyAuthorizable(accessPolicyDto.id) >> new SimpleAuthorizable(null, ResourceFactory.getPolicyResource(accessPolicyDto.id),
isAuthorized, authorizationResult)
}
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.getUsersResource(),
isAuthorized, authorizationResult)
if (authorizationResult == AuthorizationResult.approved()) {
1 * userDao.getUser(_) >> { String userId ->
def userEntity = accessPolicyDto.users.find { it.id.equals(userId) }?.component
assert userEntity != null
new User.Builder().identifier(userEntity.id).identity(userEntity.identity).build()
}
}
1 * revisionManager.get(_, _) >> { String id, ReadOnlyRevisionCallback callback ->
callback.withRevision(new Revision(1L, 'client1', 'root'))
}
0 * _
if (isAuthorized) {
assert accessPolicyEntity?.component?.id?.equals(accessPolicyDto.id)
assert accessPolicyEntity?.accessPolicy?.canRead
assert accessPolicyEntity?.accessPolicy?.canWrite
} else {
assert accessPolicyEntity?.component == null
assert exception instanceof AccessDeniedException
}
where:
accessPolicyDto | isAuthorized | authorizationResult
new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | true | AuthorizationResult.approved()
new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | false | AuthorizationResult.denied()
}
@Unroll
def "GetAccessPolicy: isAuthorized: #isAuthorized"() {
given:
def accessPolicyDao = Mock AccessPolicyDAO
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def authorizableLookup = Mock AuthorizableLookup
def dtoFactory = new DtoFactory()
def entityFactory = new EntityFactory()
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setAccessPolicyDAO accessPolicyDao
niFiServiceFacade.setUserDAO userDao
def builder = new AccessPolicy.Builder().identifier(accessPolicyDto.id).resource(accessPolicyDto.resource)
.addUsers(accessPolicyDto.users.collect { it.id } as Set)
.addGroups(accessPolicyDto.userGroups.collect { it.id } as Set)
if (accessPolicyDto.canRead) {
builder.addAction(RequestAction.READ)
}
if (accessPolicyDto.canWrite) {
builder.addAction(RequestAction.WRITE)
}
def requestedAccessPolicy = builder.build()
def exception = null
def accessPolicyEntity = null
when:
try {
accessPolicyEntity = niFiServiceFacade.getAccessPolicy(accessPolicyDto.id)
} catch (AccessDeniedException e) {
exception = e
}
then:
if (isAuthorized) {
1 * accessPolicyDao.getAccessPolicy(accessPolicyDto.id) >> requestedAccessPolicy
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.getUsersResource(),
isAuthorized, authorizationResult)
}
_ * revisionManager.get(_, _) >> { String id, ReadOnlyRevisionCallback callback ->
callback.withRevision(new Revision(1L, 'client1', 'root'))
}
1 * authorizableLookup.getAccessPolicyAuthorizable(accessPolicyDto.id) >> new SimpleAuthorizable(null, ResourceFactory.getPolicyResource(accessPolicyDto.id),
isAuthorized, authorizationResult)
if (authorizationResult == AuthorizationResult.approved()) {
1 * userDao.getUser(_) >> { String userId ->
def userEntity = accessPolicyDto.users.find { it.id.equals(userId) }?.component
assert userEntity != null
new User.Builder().identifier(userEntity.id).identity(userEntity.identity).build()
}
}
0 * _
if (isAuthorized) {
assert accessPolicyEntity?.component?.id?.equals(accessPolicyDto.id)
} else {
assert exception instanceof AccessDeniedException
}
where:
accessPolicyDto | isAuthorized | authorizationResult
new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | true | AuthorizationResult.approved()
new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | false | AuthorizationResult.denied()
}
@Unroll
def "UpdateAccessPolicy: isAuthorized: #isAuthorized, policy exists: #hasPolicy"() {
given:
def accessPolicyDao = Mock AccessPolicyDAO
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def entityFactory = new EntityFactory()
def dtoFactory = new DtoFactory()
def authorizableLookup = Mock AuthorizableLookup
def controllerFacade = Mock ControllerFacade
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setAccessPolicyDAO accessPolicyDao
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setControllerFacade controllerFacade
niFiServiceFacade.setUserDAO userDao
def builder = new AccessPolicy.Builder().identifier(accessPolicyDto.id).resource(accessPolicyDto.resource)
.addUsers(accessPolicyDto.users.collect { it.id } as Set)
.addGroups(accessPolicyDto.userGroups.collect { it.id } as Set)
if (accessPolicyDto.canRead) {
builder.addAction(RequestAction.READ)
}
if (accessPolicyDto.canWrite) {
builder.addAction(RequestAction.WRITE)
}
def accessPolicy = builder.build()
def accessPolicyEntityUpdateResult = null
def exception = null
when:
try {
accessPolicyEntityUpdateResult = niFiServiceFacade.updateAccessPolicy(currentRevision, accessPolicyDto)
} catch (AccessDeniedException e) {
exception = e
}
then:
1 * accessPolicyDao.hasAccessPolicy(accessPolicyDto.id) >> hasPolicy
if (!hasPolicy) {
1 * accessPolicyDao.createAccessPolicy(accessPolicyDto) >> accessPolicy
} else {
1 * controllerFacade.save()
1 * accessPolicyDao.updateAccessPolicy(accessPolicyDto) >> accessPolicy
1 * revisionManager.updateRevision(_, _, _) >> { RevisionClaim revisionClaim, NiFiUser niFiUser, UpdateRevisionTask callback ->
callback.update()
}
}
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.getUsersResource(),
isAuthorized, authorizationResult)
if (isAuthorized || hasPolicy) {
1 * authorizableLookup.getAccessPolicyAuthorizable(accessPolicyDto.id) >> new SimpleAuthorizable(null, ResourceFactory.getPolicyResource(accessPolicyDto.id),
isAuthorized, authorizationResult)
}
if (authorizationResult == AuthorizationResult.approved()) {
1 * userDao.getUser(_) >> { String userId ->
def userEntity = accessPolicyDto.users.find { it.id.equals(userId) }?.component
assert userEntity != null
new User.Builder().identifier(userEntity.id).identity(userEntity.identity).build()
}
}
1 * revisionManager.get(_, _) >> { String id, ReadOnlyRevisionCallback callback ->
callback.withRevision(new Revision(1L, 'client1', 'root'))
}
0 * _
def accessPolicyEntity = accessPolicyEntityUpdateResult?.result
if (isAuthorized) {
assert accessPolicyEntity?.component?.id?.equals(accessPolicyDto.id)
assert accessPolicyEntity?.accessPolicy?.canRead
assert accessPolicyEntity?.accessPolicy?.canWrite
} else {
assert accessPolicyEntity?.component == null
assert exception instanceof AccessDeniedException
}
where:
hasPolicy | currentRevision | accessPolicyDto | isAuthorized |
authorizationResult
false | new Revision(0L, 'client1', 'root') | new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | true |
AuthorizationResult.approved()
true | new Revision(1L, 'client1', 'root') | new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | true |
AuthorizationResult.approved()
false | new Revision(0L, 'client1', 'root') | new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | false |
AuthorizationResult.denied()
true | new Revision(1L, 'client1', 'root') | new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | false |
AuthorizationResult.denied()
}
@Unroll
def "DeleteAccessPolicy: isAuthorized: #isAuthorized, hasPolicy: #hasPolicy"() {
given:
def accessPolicyDao = Mock AccessPolicyDAO
def userDao = Mock UserDAO
def revisionManager = Mock RevisionManager
def authorizableLookup = Mock AuthorizableLookup
def dtoFactory = new DtoFactory()
def entityFactory = new EntityFactory()
def controllerFacade = Mock ControllerFacade
def niFiServiceFacade = new StandardNiFiServiceFacade()
niFiServiceFacade.setAuthorizableLookup authorizableLookup
niFiServiceFacade.setRevisionManager revisionManager
niFiServiceFacade.setDtoFactory dtoFactory
niFiServiceFacade.setEntityFactory entityFactory
niFiServiceFacade.setAccessPolicyDAO accessPolicyDao
niFiServiceFacade.setControllerFacade controllerFacade
niFiServiceFacade.setUserDAO userDao
def builder = new AccessPolicy.Builder()
builder.identifier(accessPolicyDto.id).resource(accessPolicyDto.resource)
.addUsers(accessPolicyDto.users.collect { it.id } as Set)
.addGroups(accessPolicyDto.userGroups.collect { it.id } as Set)
if (accessPolicyDto.canRead) {
builder.addAction(RequestAction.READ)
}
if (accessPolicyDto.canWrite) {
builder.addAction(RequestAction.WRITE)
}
def accessPolicy = builder.build()
def accessPolicyEntity = null
def exception = null
when:
try {
accessPolicyEntity = niFiServiceFacade.deleteAccessPolicy(currentRevision, accessPolicyDto.id)
} catch (AccessDeniedException e) {
exception = e
}
then:
if (hasPolicy) {
1 * accessPolicyDao.getAccessPolicy(accessPolicyDto.id) >> accessPolicy
if (isAuthorized) {
1 * accessPolicyDao.deleteAccessPolicy(accessPolicyDto.id) >> accessPolicy
}
1 * authorizableLookup.getUsersAuthorizable() >> new SimpleAuthorizable(null, ResourceFactory.usersResource,
isAuthorized, authorizationResult)
} else {
1 * accessPolicyDao.getAccessPolicy(accessPolicyDto.id) >> null
1 * accessPolicyDao.deleteAccessPolicy(accessPolicyDto.id) >> null
}
if (!(!isAuthorized && hasPolicy)) {
1 * authorizableLookup.getAccessPolicyAuthorizable(accessPolicyDto.id) >> new SimpleAuthorizable(null, ResourceFactory.getPolicyResource(accessPolicyDto.id),
isAuthorized, authorizationResult)
1 * revisionManager.deleteRevision(_, _, _) >> { RevisionClaim revisionClaim, NiFiUser nifiUser, DeleteRevisionTask task ->
task.performTask()
}
1 * controllerFacade.save()
}
_ * revisionManager.get(_, _) >> { String id, ReadOnlyRevisionCallback callback ->
callback.withRevision(new Revision(1L, 'client1', 'root'))
}
if (authorizationResult == AuthorizationResult.approved() && hasPolicy) {
1 * userDao.getUser(_) >> { String userId ->
def userEntity = accessPolicyDto.users.find { it.id.equals(userId) }?.component
assert userEntity != null
new User.Builder().identifier(userEntity.id).identity(userEntity.identity).build()
}
}
0 * _
if (hasPolicy && isAuthorized) {
assert accessPolicyEntity?.id?.equals(accessPolicyDto.id)
} else {
assert accessPolicyEntity?.id == null
}
if (!isAuthorized && hasPolicy) {
assert exception instanceof AccessDeniedException
}
where:
hasPolicy | currentRevision | accessPolicyDto | isAuthorized |
authorizationResult
true | new Revision(1L, 'client1', 'root') | new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | true |
AuthorizationResult.approved()
false | null | new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | true |
AuthorizationResult.approved()
true | new Revision(1L, 'client1', 'root') | new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | false |
AuthorizationResult.denied()
false | null | new AccessPolicyDTO(id: '1', resource: ResourceFactory.flowResource.identifier, users: [createUserEntity()], canRead: true) | false |
AuthorizationResult.denied()
}
private UserGroupDTO createUserGroupDTO() {
new UserGroupDTO(id: 'group-1', name: 'test group', users: [createUserEntity()] as Set)
}
private UserEntity createUserEntity() {
new UserEntity(id: 'user-1', component: createUserDTO(), revision: createRevisionDTO())
}
private UserDTO createUserDTO() {
new UserDTO(id: 'user-1', identity: 'user-1')
}
private RevisionDTO createRevisionDTO() {
new RevisionDTO(version: 0L, clientId: 'client-1', lastModifier: 'user-1')
}
private class SimpleAuthorizable implements Authorizable {
final private Authorizable parentAuthorizable
final private Resource resource
final private boolean isAuthorized
final private AuthorizationResult authorizationResult;
SimpleAuthorizable(Authorizable parentAuthorizable, Resource resource, boolean isAuthorized, AuthorizationResult authorizationResult) {
this.parentAuthorizable = parentAuthorizable
this.resource = resource
this.isAuthorized = isAuthorized
this.authorizationResult = authorizationResult
}
@Override
Authorizable getParentAuthorizable() {
return parentAuthorizable
}
@Override
Resource getResource() {
return resource
}
@Override
boolean isAuthorized(Authorizer authorzr, RequestAction action) {
return isAuthorized
}
@Override
AuthorizationResult checkAuthorization(Authorizer authorzr, RequestAction action) {
return authorizationResult
}
@Override
void authorize(Authorizer authorzr, RequestAction action) throws AccessDeniedException {
if (!isAuthorized) {
throw new AccessDeniedException("test exception, access denied")
}
}
}
}

View File

@ -44,7 +44,6 @@ import org.apache.nifi.web.api.entity.ProcessGroupsEntity;
import org.apache.nifi.web.api.entity.ProcessorEntity;
import org.apache.nifi.web.api.entity.ProcessorTypesEntity;
import org.apache.nifi.web.api.entity.ProcessorsEntity;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.entity.UsersEntity;
import org.junit.AfterClass;
import org.junit.Assert;
@ -993,7 +992,7 @@ public class AdminAccessControlTest {
// ensure the request succeeded
Assert.assertEquals(200, putResponse.getStatus());
Assert.assertEquals("ACTIVE", putResponse.getEntity(UserEntity.class).getUser().getStatus());
Assert.assertEquals("ACTIVE", null); // FIXME test should fail, needs to be updated to test updating user by changing the groups the user is in and the name of the user
}
@AfterClass