mirror of https://github.com/apache/nifi.git
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 <joepercivall@yahoo.com>
This commit is contained in:
parent
5e4ba04589
commit
da238b16ef
|
@ -29,6 +29,7 @@ import java.util.Date;
|
||||||
@XmlType(name = "flowConfiguration")
|
@XmlType(name = "flowConfiguration")
|
||||||
public class FlowConfigurationDTO {
|
public class FlowConfigurationDTO {
|
||||||
|
|
||||||
|
private Boolean supportsConfigurableAuthorizer;
|
||||||
private Long autoRefreshIntervalSeconds;
|
private Long autoRefreshIntervalSeconds;
|
||||||
|
|
||||||
private Date currentTime;
|
private Date currentTime;
|
||||||
|
@ -49,6 +50,21 @@ public class FlowConfigurationDTO {
|
||||||
this.autoRefreshIntervalSeconds = autoRefreshIntervalSeconds;
|
this.autoRefreshIntervalSeconds = autoRefreshIntervalSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
* @return current time on the server
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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.ControllerServicesEndpointMerger;
|
||||||
import org.apache.nifi.cluster.coordination.http.endpoints.ControllerStatusEndpointMerger;
|
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.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.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.FlowMerger;
|
||||||
import org.apache.nifi.cluster.coordination.http.endpoints.FlowSnippetEndpointMerger;
|
import org.apache.nifi.cluster.coordination.http.endpoints.FlowSnippetEndpointMerger;
|
||||||
import org.apache.nifi.cluster.coordination.http.endpoints.GroupStatusEndpointMerger;
|
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 SystemDiagnosticsEndpointMerger());
|
||||||
endpointMergers.add(new CountersEndpointMerger());
|
endpointMergers.add(new CountersEndpointMerger());
|
||||||
endpointMergers.add(new FlowMerger());
|
endpointMergers.add(new FlowMerger());
|
||||||
|
endpointMergers.add(new CurrentUserEndpointMerger());
|
||||||
|
endpointMergers.add(new FlowConfigurationEndpointMerger());
|
||||||
endpointMergers.add(new TemplatesEndpointMerger());
|
endpointMergers.add(new TemplatesEndpointMerger());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import com.wordnik.swagger.annotations.ApiResponse;
|
||||||
import com.wordnik.swagger.annotations.ApiResponses;
|
import com.wordnik.swagger.annotations.ApiResponses;
|
||||||
import com.wordnik.swagger.annotations.Authorization;
|
import com.wordnik.swagger.annotations.Authorization;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer;
|
||||||
import org.apache.nifi.authorization.Authorizer;
|
import org.apache.nifi.authorization.Authorizer;
|
||||||
import org.apache.nifi.authorization.RequestAction;
|
import org.apache.nifi.authorization.RequestAction;
|
||||||
import org.apache.nifi.authorization.resource.Authorizable;
|
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.entity.AccessPolicyEntity;
|
||||||
import org.apache.nifi.web.api.request.ClientIdParameter;
|
import org.apache.nifi.web.api.request.ClientIdParameter;
|
||||||
import org.apache.nifi.web.api.request.LongParameter;
|
import org.apache.nifi.web.api.request.LongParameter;
|
||||||
|
import org.apache.nifi.web.dao.AccessPolicyDAO;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
@ -130,6 +132,11 @@ public class AccessPolicyResource extends ApplicationResource {
|
||||||
required = true
|
required = true
|
||||||
) @PathParam("resource") String rawResource) {
|
) @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
|
// parse the action and resource type
|
||||||
final RequestAction requestAction = RequestAction.valueOfValue(action);
|
final RequestAction requestAction = RequestAction.valueOfValue(action);
|
||||||
final String resource = "/" + rawResource;
|
final String resource = "/" + rawResource;
|
||||||
|
@ -189,6 +196,11 @@ public class AccessPolicyResource extends ApplicationResource {
|
||||||
required = true
|
required = true
|
||||||
) final AccessPolicyEntity accessPolicyEntity) {
|
) 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) {
|
if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) {
|
||||||
throw new IllegalArgumentException("Access policy details must be specified.");
|
throw new IllegalArgumentException("Access policy details must be specified.");
|
||||||
}
|
}
|
||||||
|
@ -277,6 +289,11 @@ public class AccessPolicyResource extends ApplicationResource {
|
||||||
)
|
)
|
||||||
@PathParam("id") final String id) {
|
@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()) {
|
if (isReplicateRequest()) {
|
||||||
return replicate(HttpMethod.GET);
|
return replicate(HttpMethod.GET);
|
||||||
}
|
}
|
||||||
|
@ -335,6 +352,11 @@ public class AccessPolicyResource extends ApplicationResource {
|
||||||
required = true
|
required = true
|
||||||
) final AccessPolicyEntity accessPolicyEntity) {
|
) 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) {
|
if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) {
|
||||||
throw new IllegalArgumentException("Access policy details must be specified.");
|
throw new IllegalArgumentException("Access policy details must be specified.");
|
||||||
}
|
}
|
||||||
|
@ -425,6 +447,11 @@ public class AccessPolicyResource extends ApplicationResource {
|
||||||
)
|
)
|
||||||
@PathParam("id") final String id) {
|
@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()) {
|
if (isReplicateRequest()) {
|
||||||
return replicate(HttpMethod.DELETE);
|
return replicate(HttpMethod.DELETE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -300,6 +300,10 @@ public class FlowResource extends ApplicationResource {
|
||||||
|
|
||||||
authorizeFlow();
|
authorizeFlow();
|
||||||
|
|
||||||
|
if (isReplicateRequest()) {
|
||||||
|
return replicate(HttpMethod.GET);
|
||||||
|
}
|
||||||
|
|
||||||
final FlowConfigurationEntity entity = serviceFacade.getFlowConfiguration();
|
final FlowConfigurationEntity entity = serviceFacade.getFlowConfiguration();
|
||||||
return clusterContext(generateOkResponse(entity)).build();
|
return clusterContext(generateOkResponse(entity)).build();
|
||||||
}
|
}
|
||||||
|
@ -321,6 +325,10 @@ public class FlowResource extends ApplicationResource {
|
||||||
|
|
||||||
authorizeFlow();
|
authorizeFlow();
|
||||||
|
|
||||||
|
if (isReplicateRequest()) {
|
||||||
|
return replicate(HttpMethod.GET);
|
||||||
|
}
|
||||||
|
|
||||||
// note that the cluster manager will handle this request directly
|
// note that the cluster manager will handle this request directly
|
||||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.wordnik.swagger.annotations.ApiResponse;
|
||||||
import com.wordnik.swagger.annotations.ApiResponses;
|
import com.wordnik.swagger.annotations.ApiResponses;
|
||||||
import com.wordnik.swagger.annotations.Authorization;
|
import com.wordnik.swagger.annotations.Authorization;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer;
|
||||||
import org.apache.nifi.authorization.Authorizer;
|
import org.apache.nifi.authorization.Authorizer;
|
||||||
import org.apache.nifi.authorization.RequestAction;
|
import org.apache.nifi.authorization.RequestAction;
|
||||||
import org.apache.nifi.authorization.resource.Authorizable;
|
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.entity.UsersEntity;
|
||||||
import org.apache.nifi.web.api.request.ClientIdParameter;
|
import org.apache.nifi.web.api.request.ClientIdParameter;
|
||||||
import org.apache.nifi.web.api.request.LongParameter;
|
import org.apache.nifi.web.api.request.LongParameter;
|
||||||
|
import org.apache.nifi.web.dao.AccessPolicyDAO;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
@ -105,7 +107,7 @@ public class TenantsResource extends ApplicationResource {
|
||||||
* @return userEntity
|
* @return userEntity
|
||||||
*/
|
*/
|
||||||
public UserEntity populateRemainingUserEntityContent(UserEntity userEntity) {
|
public UserEntity populateRemainingUserEntityContent(UserEntity userEntity) {
|
||||||
userEntity.setUri(generateResourceUri("tenants/users", userEntity.getId()));
|
userEntity.setUri(generateResourceUri("tenants", "users", userEntity.getId()));
|
||||||
return userEntity;
|
return userEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +146,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
required = true
|
required = true
|
||||||
) final UserEntity userEntity) {
|
) 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) {
|
if (userEntity == null || userEntity.getComponent() == null) {
|
||||||
throw new IllegalArgumentException("User details must be specified.");
|
throw new IllegalArgumentException("User details must be specified.");
|
||||||
}
|
}
|
||||||
|
@ -224,6 +231,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
)
|
)
|
||||||
@PathParam("id") final String id) {
|
@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()) {
|
if (isReplicateRequest()) {
|
||||||
return replicate(HttpMethod.GET);
|
return replicate(HttpMethod.GET);
|
||||||
}
|
}
|
||||||
|
@ -271,6 +283,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
)
|
)
|
||||||
public Response getUsers() {
|
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()) {
|
if (isReplicateRequest()) {
|
||||||
return replicate(HttpMethod.GET);
|
return replicate(HttpMethod.GET);
|
||||||
}
|
}
|
||||||
|
@ -334,6 +351,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
required = true
|
required = true
|
||||||
) final UserEntity userEntity) {
|
) 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) {
|
if (userEntity == null || userEntity.getComponent() == null) {
|
||||||
throw new IllegalArgumentException("User details must be specified.");
|
throw new IllegalArgumentException("User details must be specified.");
|
||||||
}
|
}
|
||||||
|
@ -424,6 +446,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
)
|
)
|
||||||
@PathParam("id") final String id) {
|
@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()) {
|
if (isReplicateRequest()) {
|
||||||
return replicate(HttpMethod.DELETE);
|
return replicate(HttpMethod.DELETE);
|
||||||
}
|
}
|
||||||
|
@ -466,7 +493,7 @@ public class TenantsResource extends ApplicationResource {
|
||||||
* @return userGroupEntity
|
* @return userGroupEntity
|
||||||
*/
|
*/
|
||||||
public UserGroupEntity populateRemainingUserGroupEntityContent(UserGroupEntity userGroupEntity) {
|
public UserGroupEntity populateRemainingUserGroupEntityContent(UserGroupEntity userGroupEntity) {
|
||||||
userGroupEntity.setUri(generateResourceUri("tenants/user-groups", userGroupEntity.getId()));
|
userGroupEntity.setUri(generateResourceUri("tenants", "user-groups", userGroupEntity.getId()));
|
||||||
return userGroupEntity;
|
return userGroupEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,6 +532,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
required = true
|
required = true
|
||||||
) final UserGroupEntity userGroupEntity) {
|
) 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) {
|
if (userGroupEntity == null || userGroupEntity.getComponent() == null) {
|
||||||
throw new IllegalArgumentException("User group details must be specified.");
|
throw new IllegalArgumentException("User group details must be specified.");
|
||||||
}
|
}
|
||||||
|
@ -585,6 +617,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
)
|
)
|
||||||
@PathParam("id") final String id) {
|
@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()) {
|
if (isReplicateRequest()) {
|
||||||
return replicate(HttpMethod.GET);
|
return replicate(HttpMethod.GET);
|
||||||
}
|
}
|
||||||
|
@ -632,6 +669,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
)
|
)
|
||||||
public Response getUserGroups() {
|
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()) {
|
if (isReplicateRequest()) {
|
||||||
return replicate(HttpMethod.GET);
|
return replicate(HttpMethod.GET);
|
||||||
}
|
}
|
||||||
|
@ -694,6 +736,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
required = true
|
required = true
|
||||||
) final UserGroupEntity userGroupEntity) {
|
) 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) {
|
if (userGroupEntity == null || userGroupEntity.getComponent() == null) {
|
||||||
throw new IllegalArgumentException("User group details must be specified.");
|
throw new IllegalArgumentException("User group details must be specified.");
|
||||||
}
|
}
|
||||||
|
@ -784,6 +831,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
)
|
)
|
||||||
@PathParam("id") final String id) {
|
@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()) {
|
if (isReplicateRequest()) {
|
||||||
return replicate(HttpMethod.DELETE);
|
return replicate(HttpMethod.DELETE);
|
||||||
}
|
}
|
||||||
|
@ -846,6 +898,11 @@ public class TenantsResource extends ApplicationResource {
|
||||||
)
|
)
|
||||||
@QueryParam("q") @DefaultValue(StringUtils.EMPTY) String value) {
|
@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()) {
|
if (isReplicateRequest()) {
|
||||||
return replicate(HttpMethod.GET);
|
return replicate(HttpMethod.GET);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.apache.nifi.action.details.PurgeDetails;
|
||||||
import org.apache.nifi.annotation.behavior.Stateful;
|
import org.apache.nifi.annotation.behavior.Stateful;
|
||||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||||
import org.apache.nifi.annotation.documentation.Tags;
|
import org.apache.nifi.annotation.documentation.Tags;
|
||||||
|
import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer;
|
||||||
import org.apache.nifi.authorization.AccessPolicy;
|
import org.apache.nifi.authorization.AccessPolicy;
|
||||||
import org.apache.nifi.authorization.Authorizer;
|
import org.apache.nifi.authorization.Authorizer;
|
||||||
import org.apache.nifi.authorization.Group;
|
import org.apache.nifi.authorization.Group;
|
||||||
|
@ -199,6 +200,7 @@ public final class DtoFactory {
|
||||||
// get the refresh interval
|
// get the refresh interval
|
||||||
final long refreshInterval = FormatUtils.getTimeDuration(autoRefreshInterval, TimeUnit.SECONDS);
|
final long refreshInterval = FormatUtils.getTimeDuration(autoRefreshInterval, TimeUnit.SECONDS);
|
||||||
dto.setAutoRefreshIntervalSeconds(refreshInterval);
|
dto.setAutoRefreshIntervalSeconds(refreshInterval);
|
||||||
|
dto.setSupportsConfigurableAuthorizer(authorizer instanceof AbstractPolicyBasedAuthorizer);
|
||||||
|
|
||||||
final Date now = new Date();
|
final Date now = new Date();
|
||||||
dto.setTimeOffset(TimeZone.getDefault().getOffset(now.getTime()));
|
dto.setTimeOffset(TimeZone.getDefault().getOffset(now.getTime()));
|
||||||
|
|
|
@ -23,6 +23,8 @@ import org.apache.nifi.web.api.dto.AccessPolicyDTO;
|
||||||
|
|
||||||
public interface AccessPolicyDAO {
|
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.
|
* Whether or not NiFi supports a configurable authorizer.
|
||||||
*
|
*
|
||||||
|
|
|
@ -44,7 +44,6 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGroupDAO, UserDAO {
|
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 AbstractPolicyBasedAuthorizer authorizer;
|
||||||
private final boolean supportsConfigurableAuthorizer;
|
private final boolean supportsConfigurableAuthorizer;
|
||||||
|
|
||||||
|
|
|
@ -147,15 +147,15 @@
|
||||||
<i class="fa fa-history"></i>Flow Configuration History
|
<i class="fa fa-history"></i>Flow Configuration History
|
||||||
</a>
|
</a>
|
||||||
</md-menu-item>
|
</md-menu-item>
|
||||||
<md-menu-divider></md-menu-divider>
|
<md-menu-divider ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()"></md-menu-divider>
|
||||||
<md-menu-item layout-align="space-around center">
|
<md-menu-item layout-align="space-around center" ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()">
|
||||||
<a id="users-link" layout="row"
|
<a id="users-link" layout="row"
|
||||||
ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.users.shell.launch();"
|
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
|
<i class="fa fa-users"></i>Users
|
||||||
</a>
|
</a>
|
||||||
</md-menu-item>
|
</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"
|
<a id="policies-link" layout="row"
|
||||||
ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.policies.shell.launch();"
|
ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.policies.shell.launch();"
|
||||||
ng-class="{disabled: !(appCtrl.nf.Common.canAccessTenants() && appCtrl.nf.Common.canModifyPolicies())}">
|
ng-class="{disabled: !(appCtrl.nf.Common.canAccessTenants() && appCtrl.nf.Common.canModifyPolicies())}">
|
||||||
|
|
|
@ -99,8 +99,8 @@
|
||||||
ng-disabled="!(appCtrl.serviceProvider.graphControlsCtrl.canConfigureOrOpenDetails())">
|
ng-disabled="!(appCtrl.serviceProvider.graphControlsCtrl.canConfigureOrOpenDetails())">
|
||||||
<div class="graph-control-action-icon fa fa-gear"></div></button>
|
<div class="graph-control-action-icon fa fa-gear"></div></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-spacer-small"> </div>
|
<div class="button-spacer-small" ng-if="appCtrl.nf.Canvas.isConfigurableAuthorizer()"> </div>
|
||||||
<div id="operate-policy" class="action-button" title="Access Policies">
|
<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());"
|
<button ng-click="appCtrl.nf.Actions['managePolicies'](appCtrl.nf.CanvasUtils.getSelection());"
|
||||||
ng-disabled="!(appCtrl.serviceProvider.graphControlsCtrl.canManagePolicies())">
|
ng-disabled="!(appCtrl.serviceProvider.graphControlsCtrl.canManagePolicies())">
|
||||||
<div class="graph-control-action-icon fa fa-key"></div></button>
|
<div class="graph-control-action-icon fa fa-key"></div></button>
|
||||||
|
|
|
@ -133,7 +133,7 @@ div.policy-selected-component-name {
|
||||||
color: #262626;
|
color: #262626;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,7 @@ nf.Canvas = (function () {
|
||||||
var parentGroupId = null;
|
var parentGroupId = null;
|
||||||
var clustered = false;
|
var clustered = false;
|
||||||
var connectedToCluster = false;
|
var connectedToCluster = false;
|
||||||
|
var configurableAuthorizer = false;
|
||||||
var svg = null;
|
var svg = null;
|
||||||
var canvas = null;
|
var canvas = null;
|
||||||
|
|
||||||
|
@ -884,6 +885,9 @@ nf.Canvas = (function () {
|
||||||
// get the auto refresh interval
|
// get the auto refresh interval
|
||||||
var autoRefreshIntervalSeconds = parseInt(configDetails.autoRefreshIntervalSeconds, 10);
|
var autoRefreshIntervalSeconds = parseInt(configDetails.autoRefreshIntervalSeconds, 10);
|
||||||
|
|
||||||
|
// record whether we can configure the authorizer
|
||||||
|
configurableAuthorizer = configDetails.supportsConfigurableAuthorizer;
|
||||||
|
|
||||||
// init storage
|
// init storage
|
||||||
nf.Storage.init();
|
nf.Storage.init();
|
||||||
|
|
||||||
|
@ -1008,6 +1012,13 @@ nf.Canvas = (function () {
|
||||||
return parentGroupId;
|
return parentGroupId;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the authorizer is configurable.
|
||||||
|
*/
|
||||||
|
isConfigurableAuthorizer: function () {
|
||||||
|
return configurableAuthorizer;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the current user can write in this group.
|
* Whether the current user can write in this group.
|
||||||
*
|
*
|
||||||
|
|
|
@ -605,8 +605,10 @@ nf.ControllerServices = (function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - only if we can adminster policies
|
// 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>';
|
markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>';
|
||||||
|
}
|
||||||
|
|
||||||
return markup;
|
return markup;
|
||||||
};
|
};
|
||||||
|
|
|
@ -682,8 +682,10 @@ nf.Settings = (function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - only if we can adminster policies
|
// 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>';
|
markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>';
|
||||||
|
}
|
||||||
|
|
||||||
return markup;
|
return markup;
|
||||||
};
|
};
|
||||||
|
|
|
@ -283,11 +283,12 @@ 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>';
|
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
|
// allow policy configuration conditionally
|
||||||
// TODO - only if we can adminster policies
|
if (top !== window && nf.Common.canAccessTenants()) {
|
||||||
if (top !== window) {
|
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>';
|
markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return markup;
|
return markup;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue