Repository: nifi Updated Branches: refs/heads/master 5e4ba0458 -> da238b16e
NIFI-2122: - Merging responses for the current user and the flow configuration. - Returning whether NiFi is configured with a policy based authorizer in the flow configuration. - Only showing the users and policy icons when configured with a policy based authorizer. - Failing faster when invoking the users or policies endpoint when not configured with a configurable authorizer. This closes #736 Signed-off-by: jpercivall <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/da238b16 Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/da238b16 Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/da238b16 Branch: refs/heads/master Commit: da238b16efacb46cb78847027de07b197f3f88d0 Parents: 5e4ba04 Author: Matt Gilman <[email protected]> Authored: Thu Jul 28 16:22:58 2016 -0400 Committer: jpercivall <[email protected]> Committed: Thu Jul 28 16:51:40 2016 -0400 ---------------------------------------------------------------------- .../nifi/web/api/dto/FlowConfigurationDTO.java | 16 +++++ .../http/StandardHttpResponseMerger.java | 4 ++ .../endpoints/CurrentUserEndpointMerger.java | 65 ++++++++++++++++++++ .../FlowConfigurationEndpointMerger.java | 58 +++++++++++++++++ .../nifi/web/api/AccessPolicyResource.java | 27 ++++++++ .../org/apache/nifi/web/api/FlowResource.java | 8 +++ .../apache/nifi/web/api/TenantsResource.java | 61 +++++++++++++++++- .../org/apache/nifi/web/api/dto/DtoFactory.java | 2 + .../apache/nifi/web/dao/AccessPolicyDAO.java | 2 + .../impl/StandardPolicyBasedAuthorizerDAO.java | 1 - .../WEB-INF/partials/canvas/canvas-header.jsp | 8 +-- .../WEB-INF/partials/canvas/navigation.jsp | 4 +- .../src/main/webapp/css/policy-management.css | 2 +- .../src/main/webapp/js/nf/canvas/nf-canvas.js | 11 ++++ .../js/nf/canvas/nf-controller-services.js | 6 +- .../src/main/webapp/js/nf/canvas/nf-settings.js | 6 +- .../js/nf/templates/nf-templates-table.js | 9 +-- 17 files changed, 272 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java index d5028d2..969168c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java @@ -29,6 +29,7 @@ import java.util.Date; @XmlType(name = "flowConfiguration") public class FlowConfigurationDTO { + private Boolean supportsConfigurableAuthorizer; private Long autoRefreshIntervalSeconds; private Date currentTime; @@ -50,6 +51,21 @@ public class FlowConfigurationDTO { } /** + * @return whether this NiFi supports a configurable authorizer. This value is read only + */ + @ApiModelProperty( + value = "Whether this NiFi supports a configurable authorizer.", + readOnly = true + ) + public Boolean getSupportsConfigurableAuthorizer() { + return supportsConfigurableAuthorizer; + } + + public void setSupportsConfigurableAuthorizer(Boolean supportsConfigurableAuthorizer) { + this.supportsConfigurableAuthorizer = supportsConfigurableAuthorizer; + } + + /** * @return current time on the server */ @XmlJavaTypeAdapter(TimeAdapter.class) http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java index 8ff321d..ad9f33f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/StandardHttpResponseMerger.java @@ -28,7 +28,9 @@ import org.apache.nifi.cluster.coordination.http.endpoints.ControllerServiceRefe import org.apache.nifi.cluster.coordination.http.endpoints.ControllerServicesEndpointMerger; import org.apache.nifi.cluster.coordination.http.endpoints.ControllerStatusEndpointMerger; import org.apache.nifi.cluster.coordination.http.endpoints.CountersEndpointMerger; +import org.apache.nifi.cluster.coordination.http.endpoints.CurrentUserEndpointMerger; import org.apache.nifi.cluster.coordination.http.endpoints.DropRequestEndpiontMerger; +import org.apache.nifi.cluster.coordination.http.endpoints.FlowConfigurationEndpointMerger; import org.apache.nifi.cluster.coordination.http.endpoints.FlowMerger; import org.apache.nifi.cluster.coordination.http.endpoints.FlowSnippetEndpointMerger; import org.apache.nifi.cluster.coordination.http.endpoints.GroupStatusEndpointMerger; @@ -105,6 +107,8 @@ public class StandardHttpResponseMerger implements HttpResponseMerger { endpointMergers.add(new SystemDiagnosticsEndpointMerger()); endpointMergers.add(new CountersEndpointMerger()); endpointMergers.add(new FlowMerger()); + endpointMergers.add(new CurrentUserEndpointMerger()); + endpointMergers.add(new FlowConfigurationEndpointMerger()); endpointMergers.add(new TemplatesEndpointMerger()); } http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/CurrentUserEndpointMerger.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/CurrentUserEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/CurrentUserEndpointMerger.java new file mode 100644 index 0000000..4a97d7a --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/CurrentUserEndpointMerger.java @@ -0,0 +1,65 @@ +/* + * 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.cluster.coordination.http.endpoints; + +import org.apache.nifi.cluster.manager.NodeResponse; +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.dto.PermissionsDTO; +import org.apache.nifi.web.api.entity.CurrentUserEntity; + +import java.net.URI; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +public class CurrentUserEndpointMerger extends AbstractSingleEntityEndpoint<CurrentUserEntity> { + public static final Pattern CURRENT_USER_URI_PATTERN = Pattern.compile("/nifi-api/flow/current-user"); + + @Override + public boolean canHandle(URI uri, String method) { + return "GET".equalsIgnoreCase(method) && CURRENT_USER_URI_PATTERN.matcher(uri.getPath()).matches(); + } + + @Override + protected Class<CurrentUserEntity> getEntityClass() { + return CurrentUserEntity.class; + } + + + @Override + protected void mergeResponses(final CurrentUserEntity clientEntity, final Map<NodeIdentifier, CurrentUserEntity> entityMap, + final Set<NodeResponse> successfulResponses, final Set<NodeResponse> problematicResponses) { + + for (final Map.Entry<NodeIdentifier, CurrentUserEntity> entry : entityMap.entrySet()) { + final CurrentUserEntity entity = entry.getValue(); + if (entity != clientEntity) { + mergePermissions(clientEntity.getControllerPermissions(), entity.getControllerPermissions()); + mergePermissions(clientEntity.getCountersPermissions(), entity.getCountersPermissions()); + mergePermissions(clientEntity.getPoliciesPermissions(), entity.getPoliciesPermissions()); + mergePermissions(clientEntity.getProvenancePermissions(), entity.getProvenancePermissions()); + mergePermissions(clientEntity.getTenantsPermissions(), entity.getTenantsPermissions()); + } + } + } + + private void mergePermissions(PermissionsDTO clientPermissions, PermissionsDTO permissions) { + clientPermissions.setCanRead(clientPermissions.getCanRead() && permissions.getCanRead()); + clientPermissions.setCanWrite(clientPermissions.getCanWrite() && permissions.getCanWrite()); + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/FlowConfigurationEndpointMerger.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/FlowConfigurationEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/FlowConfigurationEndpointMerger.java new file mode 100644 index 0000000..22fa684 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/FlowConfigurationEndpointMerger.java @@ -0,0 +1,58 @@ +/* + * 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.cluster.coordination.http.endpoints; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.dto.FlowConfigurationDTO; +import org.apache.nifi.web.api.entity.FlowConfigurationEntity; + +import java.net.URI; +import java.util.Map; +import java.util.regex.Pattern; + +public class FlowConfigurationEndpointMerger extends AbstractNodeStatusEndpoint<FlowConfigurationEntity, FlowConfigurationDTO> { + public static final Pattern FLOW_CONFIGURATION_URI_PATTERN = Pattern.compile("/nifi-api/flow/config"); + + @Override + public boolean canHandle(URI uri, String method) { + return "GET".equalsIgnoreCase(method) && FLOW_CONFIGURATION_URI_PATTERN.matcher(uri.getPath()).matches(); + } + + @Override + protected Class<FlowConfigurationEntity> getEntityClass() { + return FlowConfigurationEntity.class; + } + + @Override + protected FlowConfigurationDTO getDto(FlowConfigurationEntity entity) { + return entity.getFlowConfiguration(); + } + + @Override + protected void mergeResponses(FlowConfigurationDTO clientDto, Map<NodeIdentifier, FlowConfigurationDTO> dtoMap, NodeIdentifier selectedNodeId) { + + for (final Map.Entry<NodeIdentifier, FlowConfigurationDTO> entry : dtoMap.entrySet()) { + final NodeIdentifier nodeId = entry.getKey(); + final FlowConfigurationDTO toMerge = entry.getValue(); + if (toMerge != clientDto) { + clientDto.setSupportsConfigurableAuthorizer(clientDto.getSupportsConfigurableAuthorizer() && toMerge.getSupportsConfigurableAuthorizer()); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java index 8a03dbf..54f98f1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java @@ -23,6 +23,7 @@ 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.AbstractPolicyBasedAuthorizer; import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.authorization.RequestAction; import org.apache.nifi.authorization.resource.Authorizable; @@ -37,6 +38,7 @@ 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 org.apache.nifi.web.dao.AccessPolicyDAO; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; @@ -130,6 +132,11 @@ public class AccessPolicyResource extends ApplicationResource { required = true ) @PathParam("resource") String rawResource) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + // parse the action and resource type final RequestAction requestAction = RequestAction.valueOfValue(action); final String resource = "/" + rawResource; @@ -189,6 +196,11 @@ public class AccessPolicyResource extends ApplicationResource { required = true ) final AccessPolicyEntity accessPolicyEntity) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) { throw new IllegalArgumentException("Access policy details must be specified."); } @@ -277,6 +289,11 @@ public class AccessPolicyResource extends ApplicationResource { ) @PathParam("id") final String id) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (isReplicateRequest()) { return replicate(HttpMethod.GET); } @@ -335,6 +352,11 @@ public class AccessPolicyResource extends ApplicationResource { required = true ) final AccessPolicyEntity accessPolicyEntity) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) { throw new IllegalArgumentException("Access policy details must be specified."); } @@ -425,6 +447,11 @@ public class AccessPolicyResource extends ApplicationResource { ) @PathParam("id") final String id) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (isReplicateRequest()) { return replicate(HttpMethod.DELETE); } http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java index f9c6708..96e7dbc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java @@ -300,6 +300,10 @@ public class FlowResource extends ApplicationResource { authorizeFlow(); + if (isReplicateRequest()) { + return replicate(HttpMethod.GET); + } + final FlowConfigurationEntity entity = serviceFacade.getFlowConfiguration(); return clusterContext(generateOkResponse(entity)).build(); } @@ -321,6 +325,10 @@ public class FlowResource extends ApplicationResource { authorizeFlow(); + if (isReplicateRequest()) { + return replicate(HttpMethod.GET); + } + // note that the cluster manager will handle this request directly final NiFiUser user = NiFiUserUtils.getNiFiUser(); if (user == null) { http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java index 860bf7f..b944bf7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java @@ -23,6 +23,7 @@ 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.AbstractPolicyBasedAuthorizer; import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.authorization.RequestAction; import org.apache.nifi.authorization.resource.Authorizable; @@ -45,6 +46,7 @@ import org.apache.nifi.web.api.entity.UserGroupsEntity; import org.apache.nifi.web.api.entity.UsersEntity; import org.apache.nifi.web.api.request.ClientIdParameter; import org.apache.nifi.web.api.request.LongParameter; +import org.apache.nifi.web.dao.AccessPolicyDAO; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; @@ -105,7 +107,7 @@ public class TenantsResource extends ApplicationResource { * @return userEntity */ public UserEntity populateRemainingUserEntityContent(UserEntity userEntity) { - userEntity.setUri(generateResourceUri("tenants/users", userEntity.getId())); + userEntity.setUri(generateResourceUri("tenants", "users", userEntity.getId())); return userEntity; } @@ -144,6 +146,11 @@ public class TenantsResource extends ApplicationResource { required = true ) final UserEntity userEntity) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (userEntity == null || userEntity.getComponent() == null) { throw new IllegalArgumentException("User details must be specified."); } @@ -224,6 +231,11 @@ public class TenantsResource extends ApplicationResource { ) @PathParam("id") final String id) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (isReplicateRequest()) { return replicate(HttpMethod.GET); } @@ -271,6 +283,11 @@ public class TenantsResource extends ApplicationResource { ) public Response getUsers() { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (isReplicateRequest()) { return replicate(HttpMethod.GET); } @@ -334,6 +351,11 @@ public class TenantsResource extends ApplicationResource { required = true ) final UserEntity userEntity) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (userEntity == null || userEntity.getComponent() == null) { throw new IllegalArgumentException("User details must be specified."); } @@ -424,6 +446,11 @@ public class TenantsResource extends ApplicationResource { ) @PathParam("id") final String id) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (isReplicateRequest()) { return replicate(HttpMethod.DELETE); } @@ -466,7 +493,7 @@ public class TenantsResource extends ApplicationResource { * @return userGroupEntity */ public UserGroupEntity populateRemainingUserGroupEntityContent(UserGroupEntity userGroupEntity) { - userGroupEntity.setUri(generateResourceUri("tenants/user-groups", userGroupEntity.getId())); + userGroupEntity.setUri(generateResourceUri("tenants", "user-groups", userGroupEntity.getId())); return userGroupEntity; } @@ -505,6 +532,11 @@ public class TenantsResource extends ApplicationResource { required = true ) final UserGroupEntity userGroupEntity) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (userGroupEntity == null || userGroupEntity.getComponent() == null) { throw new IllegalArgumentException("User group details must be specified."); } @@ -585,6 +617,11 @@ public class TenantsResource extends ApplicationResource { ) @PathParam("id") final String id) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (isReplicateRequest()) { return replicate(HttpMethod.GET); } @@ -632,6 +669,11 @@ public class TenantsResource extends ApplicationResource { ) public Response getUserGroups() { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (isReplicateRequest()) { return replicate(HttpMethod.GET); } @@ -694,6 +736,11 @@ public class TenantsResource extends ApplicationResource { required = true ) final UserGroupEntity userGroupEntity) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (userGroupEntity == null || userGroupEntity.getComponent() == null) { throw new IllegalArgumentException("User group details must be specified."); } @@ -784,6 +831,11 @@ public class TenantsResource extends ApplicationResource { ) @PathParam("id") final String id) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (isReplicateRequest()) { return replicate(HttpMethod.DELETE); } @@ -846,6 +898,11 @@ public class TenantsResource extends ApplicationResource { ) @QueryParam("q") @DefaultValue(StringUtils.EMPTY) String value) { + // ensure we're running with a configurable authorizer + if (!(authorizer instanceof AbstractPolicyBasedAuthorizer)) { + throw new IllegalStateException(AccessPolicyDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER); + } + if (isReplicateRequest()) { return replicate(HttpMethod.GET); } http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java index 07d2143..93afccf 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java @@ -34,6 +34,7 @@ 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.AbstractPolicyBasedAuthorizer; import org.apache.nifi.authorization.AccessPolicy; import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.authorization.Group; @@ -199,6 +200,7 @@ public final class DtoFactory { // get the refresh interval final long refreshInterval = FormatUtils.getTimeDuration(autoRefreshInterval, TimeUnit.SECONDS); dto.setAutoRefreshIntervalSeconds(refreshInterval); + dto.setSupportsConfigurableAuthorizer(authorizer instanceof AbstractPolicyBasedAuthorizer); final Date now = new Date(); dto.setTimeOffset(TimeZone.getDefault().getOffset(now.getTime())); http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java index 009ec9c..1d48ee0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/AccessPolicyDAO.java @@ -23,6 +23,8 @@ import org.apache.nifi.web.api.dto.AccessPolicyDTO; public interface AccessPolicyDAO { + String MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER = "This NiFi is not configured to internally manage users, groups, and policies. Please contact your system administrator."; + /** * Whether or not NiFi supports a configurable authorizer. * http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java index 4c41584..24bcbef 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java @@ -44,7 +44,6 @@ import java.util.stream.Collectors; public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGroupDAO, UserDAO { - static final String MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER = "This NiFi is not configured to internally manage users, groups, and policies. Please contact your system administrator."; private final AbstractPolicyBasedAuthorizer authorizer; private final boolean supportsConfigurableAuthorizer; http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp index 7fc08a0..42bff59 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp @@ -147,15 +147,15 @@ <i class="fa fa-history"></i>Flow Configuration History </a> </md-menu-item> - <md-menu-divider></md-menu-divider> - <md-menu-item layout-align="space-around center"> + <md-menu-divider ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()"></md-menu-divider> + <md-menu-item layout-align="space-around center" ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()"> <a id="users-link" layout="row" ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.users.shell.launch();" - ng-class="{disabled: !appCtrl.nf.Common.canAccessTenants()}"> + ng-class="{disabled: !(appCtrl.nf.Common.canAccessTenants())}"> <i class="fa fa-users"></i>Users </a> </md-menu-item> - <md-menu-item layout-align="space-around center"> + <md-menu-item layout-align="space-around center" ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()"> <a id="policies-link" layout="row" ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.policies.shell.launch();" ng-class="{disabled: !(appCtrl.nf.Common.canAccessTenants() && appCtrl.nf.Common.canModifyPolicies())}"> http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp index 3e719e9..7babfa0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp @@ -99,8 +99,8 @@ ng-disabled="!(appCtrl.serviceProvider.graphControlsCtrl.canConfigureOrOpenDetails())"> <div class="graph-control-action-icon fa fa-gear"></div></button> </div> - <div class="button-spacer-small"> </div> - <div id="operate-policy" class="action-button" title="Access Policies"> + <div class="button-spacer-small" ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()"> </div> + <div id="operate-policy" class="action-button" title="Access Policies" ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()"> <button ng-click="appCtrl.nf.Actions['managePolicies'](appCtrl.nf.CanvasUtils.getSelection());" ng-disabled="!(appCtrl.serviceProvider.graphControlsCtrl.canManagePolicies())"> <div class="graph-control-action-icon fa fa-key"></div></button> http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css index 919f4c0..6259c4f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css @@ -133,7 +133,7 @@ div.policy-selected-component-name { color: #262626; width: 300px; text-overflow: ellipsis; - overflow-x: hidden; + overflow: hidden; white-space: nowrap; } http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js index 6f54962..54d5845 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js @@ -118,6 +118,7 @@ nf.Canvas = (function () { var parentGroupId = null; var clustered = false; var connectedToCluster = false; + var configurableAuthorizer = false; var svg = null; var canvas = null; @@ -884,6 +885,9 @@ nf.Canvas = (function () { // get the auto refresh interval var autoRefreshIntervalSeconds = parseInt(configDetails.autoRefreshIntervalSeconds, 10); + // record whether we can configure the authorizer + configurableAuthorizer = configDetails.supportsConfigurableAuthorizer; + // init storage nf.Storage.init(); @@ -1009,6 +1013,13 @@ nf.Canvas = (function () { }, /** + * Returns whether the authorizer is configurable. + */ + isConfigurableAuthorizer: function () { + return configurableAuthorizer; + }, + + /** * Whether the current user can write in this group. * * @returns {boolean} can write http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js index e77ab19..fc00517 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js @@ -605,8 +605,10 @@ nf.ControllerServices = (function () { } } - // TODO - only if we can adminster policies - markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>'; + // allow policy configuration conditionally + if (nf.Canvas.isConfigurableAuthorizer() && nf.Common.canAccessTenants()) { + markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>'; + } return markup; }; http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js index 74f1ea6..5456a02 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js @@ -682,8 +682,10 @@ nf.Settings = (function () { } } - // TODO - only if we can adminster policies - markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>'; + // allow policy configuration conditionally + if (nf.Canvas.isConfigurableAuthorizer() && nf.Common.canAccessTenants()) { + markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>'; + } return markup; }; http://git-wip-us.apache.org/repos/asf/nifi/blob/da238b16/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js index 272a1fe..6afba5e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates-table.js @@ -283,10 +283,11 @@ nf.TemplatesTable = (function () { markup += '<div title="Remove Template" class="pointer prompt-to-delete-template fa fa-trash" style="margin-top: 2px; margin-right: 3px;"></div>'; } - // if we in the shell - // TODO - only if we can adminster policies - if (top !== window) { - markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>'; + // allow policy configuration conditionally + if (top !== window && nf.Common.canAccessTenants()) { + if (nf.Common.isDefinedAndNotNull(parent.nf) && nf.Common.isDefinedAndNotNull(parent.nf.Canvas) && parent.nf.Canvas.isConfigurableAuthorizer()) { + markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>'; + } } return markup;
