http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/AccessPolicyEndpointMerger.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/AccessPolicyEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/AccessPolicyEndpointMerger.java new file mode 100644 index 0000000..4b2406a --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/AccessPolicyEndpointMerger.java @@ -0,0 +1,61 @@ +/* + * 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.coordination.http.EndpointResponseMerger; +import org.apache.nifi.cluster.manager.AccessPolicyEntityMerger; +import org.apache.nifi.cluster.manager.NodeResponse; +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.entity.AccessPolicyEntity; + +import java.net.URI; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +public class AccessPolicyEndpointMerger extends AbstractSingleEntityEndpoint<AccessPolicyEntity> implements EndpointResponseMerger { + public static final Pattern ACCESS_POLICIES_URI_PATTERN = Pattern.compile("/nifi-api/policies"); + public static final Pattern ACCESS_POLICY_URI_PATTERN = Pattern.compile("/nifi-api/policies/[a-f0-9\\-]{36}"); + public static final Pattern ACCESS_POLICY_LOOKUP_URI_PATTERN = Pattern.compile("/nifi-api/policies/(?:read|write)/(?:[\\w-]+?/?)+"); + private final AccessPolicyEntityMerger accessPolicyEntityMerger = new AccessPolicyEntityMerger(); + + @Override + public boolean canHandle(final URI uri, final String method) { + if (("GET".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method)) && (ACCESS_POLICY_URI_PATTERN.matcher(uri.getPath()).matches())) { + return true; + } else if ("GET".equalsIgnoreCase(method) && ACCESS_POLICY_LOOKUP_URI_PATTERN.matcher(uri.getPath()).matches()) { + return true; + } else if ("POST".equalsIgnoreCase(method) && ACCESS_POLICIES_URI_PATTERN.matcher(uri.getPath()).matches()) { + return true; + } + + return false; + } + + @Override + protected Class<AccessPolicyEntity> getEntityClass() { + return AccessPolicyEntity.class; + } + + @Override + protected void mergeResponses(final AccessPolicyEntity clientEntity, final Map<NodeIdentifier, AccessPolicyEntity> entityMap, + final Set<NodeResponse> successfulResponses, final Set<NodeResponse> problematicResponses) { + + accessPolicyEntityMerger.merge(clientEntity, entityMap); + } +}
http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/SearchUsersEndpointMerger.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/SearchUsersEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/SearchUsersEndpointMerger.java new file mode 100644 index 0000000..31996cb --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/SearchUsersEndpointMerger.java @@ -0,0 +1,59 @@ +/* + * 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.coordination.http.EndpointResponseMerger; +import org.apache.nifi.cluster.manager.NodeResponse; +import org.apache.nifi.web.api.entity.TenantEntity; +import org.apache.nifi.web.api.entity.TenantsEntity; + +import java.net.URI; +import java.util.Collection; +import java.util.Set; +import java.util.regex.Pattern; + +public class SearchUsersEndpointMerger implements EndpointResponseMerger { + public static final Pattern SEARCH_TENANTS_URI_PATTERN = Pattern.compile("/nifi-api/tenants/search-results"); + + @Override + public boolean canHandle(final URI uri, final String method) { + return "GET".equalsIgnoreCase(method) && SEARCH_TENANTS_URI_PATTERN.matcher(uri.getPath()).matches(); + } + + @Override + public final NodeResponse merge(final URI uri, final String method, final Set<NodeResponse> successfulResponses, final Set<NodeResponse> problematicResponses, final NodeResponse clientResponse) { + if (!canHandle(uri, method)) { + throw new IllegalArgumentException("Cannot use Endpoint Mapper of type " + getClass().getSimpleName() + " to map responses for URI " + uri + ", HTTP Method " + method); + } + + final TenantsEntity responseEntity = clientResponse.getClientResponse().getEntity(TenantsEntity.class); + final Collection<TenantEntity> userEntities = responseEntity.getUsers(); + final Collection<TenantEntity> userGroupEntities = responseEntity.getUserGroups(); + + for (final NodeResponse nodeResponse : successfulResponses) { + final TenantsEntity nodeResponseEntity = nodeResponse == clientResponse ? responseEntity : nodeResponse.getClientResponse().getEntity(TenantsEntity.class); + + // only retain users/groups that all nodes agree on + userEntities.retainAll(nodeResponseEntity.getUsers()); + userGroupEntities.retainAll(nodeResponseEntity.getUserGroups()); + } + + // create a new client response + return new NodeResponse(clientResponse, responseEntity); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UserEndpointMerger.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/UserEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UserEndpointMerger.java new file mode 100644 index 0000000..afac159 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UserEndpointMerger.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.coordination.http.EndpointResponseMerger; +import org.apache.nifi.cluster.manager.NodeResponse; +import org.apache.nifi.cluster.manager.UserEntityMerger; +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.entity.UserEntity; + +import java.net.URI; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +public class UserEndpointMerger extends AbstractSingleEntityEndpoint<UserEntity> implements EndpointResponseMerger { + public static final Pattern USERS_URI_PATTERN = Pattern.compile("/nifi-api/tenants/users"); + public static final Pattern USER_URI_PATTERN = Pattern.compile("/nifi-api/tenants/users/[a-f0-9\\-]{36}"); + private final UserEntityMerger userEntityMerger = new UserEntityMerger(); + + @Override + public boolean canHandle(final URI uri, final String method) { + if (("GET".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method)) && (USER_URI_PATTERN.matcher(uri.getPath()).matches())) { + return true; + } else if ("POST".equalsIgnoreCase(method) && USERS_URI_PATTERN.matcher(uri.getPath()).matches()) { + return true; + } + + return false; + } + + @Override + protected Class<UserEntity> getEntityClass() { + return UserEntity.class; + } + + @Override + protected void mergeResponses(final UserEntity clientEntity, final Map<NodeIdentifier, UserEntity> entityMap, + final Set<NodeResponse> successfulResponses, final Set<NodeResponse> problematicResponses) { + + userEntityMerger.merge(clientEntity, entityMap); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UserGroupEndpointMerger.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/UserGroupEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UserGroupEndpointMerger.java new file mode 100644 index 0000000..ca2d6e1 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UserGroupEndpointMerger.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.coordination.http.EndpointResponseMerger; +import org.apache.nifi.cluster.manager.NodeResponse; +import org.apache.nifi.cluster.manager.UserGroupEntityMerger; +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.entity.UserGroupEntity; + +import java.net.URI; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +public class UserGroupEndpointMerger extends AbstractSingleEntityEndpoint<UserGroupEntity> implements EndpointResponseMerger { + public static final Pattern USER_GROUPS_URI_PATTERN = Pattern.compile("/nifi-api/tenants/user-groups"); + public static final Pattern USER_GROUP_URI_PATTERN = Pattern.compile("/nifi-api/tenants/user-groups/[a-f0-9\\-]{36}"); + private final UserGroupEntityMerger userGroupEntityMerger = new UserGroupEntityMerger(); + + @Override + public boolean canHandle(final URI uri, final String method) { + if (("GET".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method)) && (USER_GROUP_URI_PATTERN.matcher(uri.getPath()).matches())) { + return true; + } else if ("POST".equalsIgnoreCase(method) && USER_GROUPS_URI_PATTERN.matcher(uri.getPath()).matches()) { + return true; + } + + return false; + } + + @Override + protected Class<UserGroupEntity> getEntityClass() { + return UserGroupEntity.class; + } + + @Override + protected void mergeResponses(final UserGroupEntity clientEntity, final Map<NodeIdentifier, UserGroupEntity> entityMap, + final Set<NodeResponse> successfulResponses, final Set<NodeResponse> problematicResponses) { + + userGroupEntityMerger.merge(clientEntity, entityMap); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UserGroupsEndpointMerger.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/UserGroupsEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UserGroupsEndpointMerger.java new file mode 100644 index 0000000..3b18814 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UserGroupsEndpointMerger.java @@ -0,0 +1,76 @@ +/* + * 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.coordination.http.EndpointResponseMerger; +import org.apache.nifi.cluster.manager.NodeResponse; +import org.apache.nifi.cluster.manager.UserGroupsEntityMerger; +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.entity.UserGroupEntity; +import org.apache.nifi.web.api.entity.UserGroupsEntity; + +import java.net.URI; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +public class UserGroupsEndpointMerger implements EndpointResponseMerger { + public static final Pattern USER_GROUPS_URI_PATTERN = Pattern.compile("/nifi-api/tenants/user-groups"); + + @Override + public boolean canHandle(final URI uri, final String method) { + return "GET".equalsIgnoreCase(method) && USER_GROUPS_URI_PATTERN.matcher(uri.getPath()).matches(); + } + + @Override + public final NodeResponse merge(final URI uri, final String method, final Set<NodeResponse> successfulResponses, final Set<NodeResponse> problematicResponses, final NodeResponse clientResponse) { + if (!canHandle(uri, method)) { + throw new IllegalArgumentException("Cannot use Endpoint Mapper of type " + getClass().getSimpleName() + " to map responses for URI " + uri + ", HTTP Method " + method); + } + + final UserGroupsEntity responseEntity = clientResponse.getClientResponse().getEntity(UserGroupsEntity.class); + final Collection<UserGroupEntity> userGroupEntities = responseEntity.getUserGroups(); + + final Map<String, Map<NodeIdentifier, UserGroupEntity>> entityMap = new HashMap<>(); + for (final NodeResponse nodeResponse : successfulResponses) { + final UserGroupsEntity nodeResponseEntity = nodeResponse == clientResponse ? responseEntity : nodeResponse.getClientResponse().getEntity(UserGroupsEntity.class); + final Collection<UserGroupEntity> nodeUserGroupEntities = nodeResponseEntity.getUserGroups(); + + // only retain user groups that all nodes agree on + userGroupEntities.retainAll(nodeUserGroupEntities); + + for (final UserGroupEntity nodeUserGroupEntity : nodeUserGroupEntities) { + final NodeIdentifier nodeId = nodeResponse.getNodeId(); + Map<NodeIdentifier, UserGroupEntity> innerMap = entityMap.get(nodeId); + if (innerMap == null) { + innerMap = new HashMap<>(); + entityMap.put(nodeUserGroupEntity.getId(), innerMap); + } + + innerMap.put(nodeResponse.getNodeId(), nodeUserGroupEntity); + } + } + + UserGroupsEntityMerger.mergeUserGroups(userGroupEntities, entityMap); + + // create a new client response + return new NodeResponse(clientResponse, responseEntity); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UsersEndpointMerger.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/UsersEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UsersEndpointMerger.java new file mode 100644 index 0000000..581b359 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/UsersEndpointMerger.java @@ -0,0 +1,76 @@ +/* + * 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.coordination.http.EndpointResponseMerger; +import org.apache.nifi.cluster.manager.NodeResponse; +import org.apache.nifi.cluster.manager.UsersEntityMerger; +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.entity.UserEntity; +import org.apache.nifi.web.api.entity.UsersEntity; + +import java.net.URI; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +public class UsersEndpointMerger implements EndpointResponseMerger { + public static final Pattern TENANTS_URI_PATTERN = Pattern.compile("/nifi-api/tenants/users"); + + @Override + public boolean canHandle(final URI uri, final String method) { + return "GET".equalsIgnoreCase(method) && TENANTS_URI_PATTERN.matcher(uri.getPath()).matches(); + } + + @Override + public final NodeResponse merge(final URI uri, final String method, final Set<NodeResponse> successfulResponses, final Set<NodeResponse> problematicResponses, final NodeResponse clientResponse) { + if (!canHandle(uri, method)) { + throw new IllegalArgumentException("Cannot use Endpoint Mapper of type " + getClass().getSimpleName() + " to map responses for URI " + uri + ", HTTP Method " + method); + } + + final UsersEntity responseEntity = clientResponse.getClientResponse().getEntity(UsersEntity.class); + final Collection<UserEntity> userEntities = responseEntity.getUsers(); + + final Map<String, Map<NodeIdentifier, UserEntity>> entityMap = new HashMap<>(); + for (final NodeResponse nodeResponse : successfulResponses) { + final UsersEntity nodeResponseEntity = nodeResponse == clientResponse ? responseEntity : nodeResponse.getClientResponse().getEntity(UsersEntity.class); + final Collection<UserEntity> nodeUserEntities = nodeResponseEntity.getUsers(); + + // only retain users that all nodes agree on + userEntities.retainAll(nodeUserEntities); + + for (final UserEntity nodeUserEntity : nodeUserEntities) { + final NodeIdentifier nodeId = nodeResponse.getNodeId(); + Map<NodeIdentifier, UserEntity> innerMap = entityMap.get(nodeId); + if (innerMap == null) { + innerMap = new HashMap<>(); + entityMap.put(nodeUserEntity.getId(), innerMap); + } + + innerMap.put(nodeResponse.getNodeId(), nodeUserEntity); + } + } + + UsersEntityMerger.mergeUsers(userEntities, entityMap); + + // create a new client response + return new NodeResponse(clientResponse, responseEntity); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/AccessPolicyEntityMerger.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/AccessPolicyEntityMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/AccessPolicyEntityMerger.java new file mode 100644 index 0000000..88a0faf --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/AccessPolicyEntityMerger.java @@ -0,0 +1,74 @@ +/* + * 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.manager; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.dto.AccessPolicyDTO; +import org.apache.nifi.web.api.entity.AccessPolicyEntity; +import org.apache.nifi.web.api.entity.TenantEntity; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class AccessPolicyEntityMerger implements ComponentEntityMerger<AccessPolicyEntity> { + @Override + public void merge(AccessPolicyEntity clientEntity, Map<NodeIdentifier, AccessPolicyEntity> entityMap) { + ComponentEntityMerger.super.merge(clientEntity, entityMap); + } + + /** + * Merges the AccessPolicyEntity responses. + * + * @param clientEntity the entity being returned to the client + * @param entityMap all node responses + */ + public void mergeComponents(final AccessPolicyEntity clientEntity, final Map<NodeIdentifier, AccessPolicyEntity> entityMap) { + final AccessPolicyDTO clientDto = clientEntity.getComponent(); + final Map<NodeIdentifier, AccessPolicyDTO> dtoMap = new HashMap<>(); + for (final Map.Entry<NodeIdentifier, AccessPolicyEntity> entry : entityMap.entrySet()) { + final AccessPolicyEntity nodeAccessPolicyEntity = entry.getValue(); + final AccessPolicyDTO nodeAccessPolicyDto = nodeAccessPolicyEntity.getComponent(); + dtoMap.put(entry.getKey(), nodeAccessPolicyDto); + } + + mergeDtos(clientDto, dtoMap); + } + + private static void mergeDtos(final AccessPolicyDTO clientDto, final Map<NodeIdentifier, AccessPolicyDTO> dtoMap) { + // if unauthorized for the client dto, simple return + if (clientDto == null) { + return; + } + + final Set<TenantEntity> users = new HashSet<>(clientDto.getUsers()); + final Set<TenantEntity> userGroups = new HashSet<>(clientDto.getUserGroups()); + + for (final Map.Entry<NodeIdentifier, AccessPolicyDTO> nodeEntry : dtoMap.entrySet()) { + final AccessPolicyDTO nodeAccessPolicy = nodeEntry.getValue(); + + if (nodeAccessPolicy != null) { + users.retainAll(nodeAccessPolicy.getUsers()); + userGroups.retainAll(nodeAccessPolicy.getUserGroups()); + } + } + + clientDto.setUsers(users); + clientDto.setUserGroups(userGroups); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserEntityMerger.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserEntityMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserEntityMerger.java new file mode 100644 index 0000000..e1e3fcc --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserEntityMerger.java @@ -0,0 +1,76 @@ +/* + * 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.manager; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.dto.UserDTO; +import org.apache.nifi.web.api.entity.AccessPolicySummaryEntity; +import org.apache.nifi.web.api.entity.TenantEntity; +import org.apache.nifi.web.api.entity.UserEntity; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class UserEntityMerger implements ComponentEntityMerger<UserEntity> { + + @Override + public void merge(UserEntity clientEntity, Map<NodeIdentifier, UserEntity> entityMap) { + ComponentEntityMerger.super.merge(clientEntity, entityMap); + } + + /** + * Merges the UserEntity responses. + * + * @param clientEntity the entity being returned to the client + * @param entityMap all node responses + */ + public void mergeComponents(final UserEntity clientEntity, final Map<NodeIdentifier, UserEntity> entityMap) { + final UserDTO clientDto = clientEntity.getComponent(); + final Map<NodeIdentifier, UserDTO> dtoMap = new HashMap<>(); + for (final Map.Entry<NodeIdentifier, UserEntity> entry : entityMap.entrySet()) { + final UserEntity nodeUserEntity = entry.getValue(); + final UserDTO nodeUserDto = nodeUserEntity.getComponent(); + dtoMap.put(entry.getKey(), nodeUserDto); + } + + mergeDtos(clientDto, dtoMap); + } + + private static void mergeDtos(final UserDTO clientDto, final Map<NodeIdentifier, UserDTO> dtoMap) { + // if unauthorized for the client dto, simple return + if (clientDto == null) { + return; + } + + final Set<AccessPolicySummaryEntity> accessPolicyEntities = new HashSet<>(clientDto.getAccessPolicies()); + final Set<TenantEntity> tenantEntities = new HashSet<>(clientDto.getUserGroups()); + + for (final Map.Entry<NodeIdentifier, UserDTO> nodeEntry : dtoMap.entrySet()) { + final UserDTO nodeUser = nodeEntry.getValue(); + + if (nodeUser != null) { + accessPolicyEntities.retainAll(nodeUser.getAccessPolicies()); + tenantEntities.retainAll(nodeUser.getUserGroups()); + } + } + + clientDto.setAccessPolicies(accessPolicyEntities); + clientDto.setUserGroups(tenantEntities); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserGroupEntityMerger.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserGroupEntityMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserGroupEntityMerger.java new file mode 100644 index 0000000..8142b45 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserGroupEntityMerger.java @@ -0,0 +1,75 @@ +/* + * 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.manager; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.dto.UserGroupDTO; +import org.apache.nifi.web.api.entity.AccessPolicyEntity; +import org.apache.nifi.web.api.entity.TenantEntity; +import org.apache.nifi.web.api.entity.UserGroupEntity; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class UserGroupEntityMerger implements ComponentEntityMerger<UserGroupEntity> { + @Override + public void merge(UserGroupEntity clientEntity, Map<NodeIdentifier, UserGroupEntity> entityMap) { + ComponentEntityMerger.super.merge(clientEntity, entityMap); + } + + /** + * Merges the UserGroupEntity responses. + * + * @param clientEntity the entity being returned to the client + * @param entityMap all node responses + */ + public void mergeComponents(final UserGroupEntity clientEntity, final Map<NodeIdentifier, UserGroupEntity> entityMap) { + final UserGroupDTO clientDto = clientEntity.getComponent(); + final Map<NodeIdentifier, UserGroupDTO> dtoMap = new HashMap<>(); + for (final Map.Entry<NodeIdentifier, UserGroupEntity> entry : entityMap.entrySet()) { + final UserGroupEntity nodeUserGroupEntity = entry.getValue(); + final UserGroupDTO nodeUserGroupDto = nodeUserGroupEntity.getComponent(); + dtoMap.put(entry.getKey(), nodeUserGroupDto); + } + + mergeDtos(clientDto, dtoMap); + } + + private static void mergeDtos(final UserGroupDTO clientDto, final Map<NodeIdentifier, UserGroupDTO> dtoMap) { + // if unauthorized for the client dto, simple return + if (clientDto == null) { + return; + } + + final Set<AccessPolicyEntity> accessPolicyEntities = new HashSet<>(clientDto.getAccessPolicies()); + final Set<TenantEntity> userEntities = new HashSet<>(clientDto.getUsers()); + + for (final Map.Entry<NodeIdentifier, UserGroupDTO> nodeEntry : dtoMap.entrySet()) { + final UserGroupDTO nodeUserGroup = nodeEntry.getValue(); + + if (nodeUserGroup != null) { + accessPolicyEntities.retainAll(nodeUserGroup.getAccessPolicies()); + userEntities.retainAll(nodeUserGroup.getUsers()); + } + } + + clientDto.setAccessPolicies(accessPolicyEntities); + clientDto.setUsers(userEntities); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserGroupsEntityMerger.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserGroupsEntityMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserGroupsEntityMerger.java new file mode 100644 index 0000000..6dbb0c6 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UserGroupsEntityMerger.java @@ -0,0 +1,39 @@ +/* + * 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.manager; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.entity.UserGroupEntity; + +import java.util.Collection; +import java.util.Map; + +public class UserGroupsEntityMerger implements ComponentEntityMerger<UserGroupEntity> { + private static final UserGroupEntityMerger userGroupEntityMerger = new UserGroupEntityMerger(); + + /** + * Merges multiple UserGroupEntity responses. + * + * @param userGroupEntities entities being returned to the client + * @param entityMap all node responses + */ + public static void mergeUserGroups(final Collection<UserGroupEntity> userGroupEntities, final Map<String, Map<NodeIdentifier, UserGroupEntity>> entityMap) { + for (final UserGroupEntity entity : userGroupEntities) { + userGroupEntityMerger.merge(entity, entityMap.get(entity.getId())); + } + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UsersEntityMerger.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UsersEntityMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UsersEntityMerger.java new file mode 100644 index 0000000..4874336 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/UsersEntityMerger.java @@ -0,0 +1,39 @@ +/* + * 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.manager; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.entity.UserEntity; + +import java.util.Collection; +import java.util.Map; + +public class UsersEntityMerger implements ComponentEntityMerger<UserEntity> { + private static final UserEntityMerger userEntityMerger = new UserEntityMerger(); + + /** + * Merges multiple UserEntity responses. + * + * @param userEntities entities being returned to the client + * @param entityMap all node responses + */ + public static void mergeUsers(final Collection<UserEntity> userEntities, final Map<String, Map<NodeIdentifier, UserEntity>> entityMap) { + for (final UserEntity entity : userEntities) { + userEntityMerger.merge(entity, entityMap.get(entity.getId())); + } + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/AccessPolicyEndpointMergerTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/AccessPolicyEndpointMergerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/AccessPolicyEndpointMergerTest.java new file mode 100644 index 0000000..c8a06ed --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/AccessPolicyEndpointMergerTest.java @@ -0,0 +1,41 @@ +/* + * 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.junit.Test; + +import java.net.URI; +import java.util.UUID; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class AccessPolicyEndpointMergerTest { + + @Test + public void testCanHandle() throws Exception { + final AccessPolicyEndpointMerger merger = new AccessPolicyEndpointMerger(); + assertTrue(merger.canHandle(URI.create("http://localhost:8080/nifi-api/policies"), "POST")); + assertFalse(merger.canHandle(URI.create("http://localhost:8080/nifi-api/policies"), "GET")); + assertFalse(merger.canHandle(URI.create("http://localhost:8080/nifi-api/policies"), "PUT")); + assertTrue(merger.canHandle(URI.create("http://localhost:8080/nifi-api/policies/" + UUID.randomUUID().toString()), "PUT")); + assertFalse(merger.canHandle(URI.create("http://localhost:8080/nifi-api/policies/Read/flow"), "GET")); + assertTrue(merger.canHandle(URI.create("http://localhost:8080/nifi-api/policies/read/flow"), "GET")); + assertTrue(merger.canHandle(URI.create("http://localhost:8080/nifi-api/policies/read/processors/" + UUID.randomUUID().toString()), "GET")); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/replication/TestThreadPoolRequestReplicator.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/replication/TestThreadPoolRequestReplicator.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/replication/TestThreadPoolRequestReplicator.java index d90c49b..b5eff63 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/replication/TestThreadPoolRequestReplicator.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/replication/TestThreadPoolRequestReplicator.java @@ -27,6 +27,7 @@ import org.apache.commons.collections4.map.MultiValueMap; import org.apache.nifi.authorization.user.NiFiUser; import org.apache.nifi.authorization.user.NiFiUserDetails; import org.apache.nifi.authorization.user.StandardNiFiUser; +import org.apache.nifi.authorization.user.StandardNiFiUser.Builder; import org.apache.nifi.cluster.coordination.ClusterCoordinator; import org.apache.nifi.cluster.coordination.node.NodeConnectionState; import org.apache.nifi.cluster.coordination.node.NodeConnectionStatus; @@ -157,9 +158,9 @@ public class TestThreadPoolRequestReplicator { final Entity entity = new ProcessorEntity(); // set the user - final NiFiUser proxy2 = new StandardNiFiUser(proxyIdentity2); - final NiFiUser proxy1 = new StandardNiFiUser(proxyIdentity1, proxy2); - final NiFiUser user = new StandardNiFiUser(userIdentity, proxy1); + final NiFiUser proxy2 = new Builder().identity(proxyIdentity2).build(); + final NiFiUser proxy1 = new Builder().identity(proxyIdentity1).chain(proxy2).build(); + final NiFiUser user = new Builder().identity(userIdentity).chain(proxy1).build(); final Authentication authentication = new NiFiAuthenticationToken(new NiFiUserDetails(user)); SecurityContextHolder.getContext().setAuthentication(authentication); http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/AccessPolicyEntityMergerTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/AccessPolicyEntityMergerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/AccessPolicyEntityMergerTest.java new file mode 100644 index 0000000..70a941a --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/AccessPolicyEntityMergerTest.java @@ -0,0 +1,96 @@ +/* + * 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.manager; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.dto.AccessPolicyDTO; +import org.apache.nifi.web.api.dto.PermissionsDTO; +import org.apache.nifi.web.api.dto.TenantDTO; +import org.apache.nifi.web.api.entity.AccessPolicyEntity; +import org.apache.nifi.web.api.entity.TenantEntity; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +public class AccessPolicyEntityMergerTest { + + @Test + public void testMergeAccessPolicy() throws Exception { + final NodeIdentifier node1 = new NodeIdentifier("node-1", "host-1", 8080, "host-1", 19998, null, null, null, false); + final NodeIdentifier node2 = new NodeIdentifier("node-2", "host-2", 8081, "host-2", 19999, null, null, null, false); + + final PermissionsDTO permissed = new PermissionsDTO(); + permissed.setCanRead(true); + permissed.setCanWrite(true); + + final TenantDTO user1DTO = new TenantDTO(); + user1DTO.setId("user-1"); + + final TenantEntity user1Entity = new TenantEntity(); + user1Entity.setPermissions(permissed); + user1Entity.setId(user1DTO.getId()); + user1Entity.setComponent(user1DTO); + + final TenantDTO user2DTO = new TenantDTO(); + user1DTO.setId("user-2"); + + final TenantEntity user2Entity = new TenantEntity(); + user2Entity.setPermissions(permissed); + user2Entity.setId(user2DTO.getId()); + user2Entity.setComponent(user2DTO); + + final AccessPolicyDTO accessPolicy1DTO = new AccessPolicyDTO(); + accessPolicy1DTO.setId("policy-1"); + accessPolicy1DTO.setUsers(Stream.of(user1Entity, user2Entity).collect(Collectors.toSet())); + accessPolicy1DTO.setUserGroups(Stream.of(user2Entity).collect(Collectors.toSet())); + + final AccessPolicyEntity accessPolicy1Entity = new AccessPolicyEntity(); + accessPolicy1Entity.setPermissions(permissed); + accessPolicy1Entity.setId(accessPolicy1DTO.getId()); + accessPolicy1Entity.setComponent(accessPolicy1DTO); + + final AccessPolicyDTO accessPolicy2DTO = new AccessPolicyDTO(); + accessPolicy2DTO.setId("policy-2"); + accessPolicy2DTO.setUsers(Stream.of(user1Entity).collect(Collectors.toSet())); + accessPolicy2DTO.setUserGroups(Stream.of(user1Entity, user2Entity).collect(Collectors.toSet())); + + final AccessPolicyEntity accessPolicy2Entity = new AccessPolicyEntity(); + accessPolicy2Entity.setPermissions(permissed); + accessPolicy2Entity.setId(accessPolicy2DTO.getId()); + accessPolicy2Entity.setComponent(accessPolicy2DTO); + + final Map<NodeIdentifier, AccessPolicyEntity> nodeMap = new HashMap<>(); + nodeMap.put(node1, accessPolicy1Entity); + nodeMap.put(node2, accessPolicy2Entity); + + final AccessPolicyEntityMerger merger = new AccessPolicyEntityMerger(); + merger.merge(accessPolicy1Entity, nodeMap); + + assertEquals(1, accessPolicy1DTO.getUserGroups().size()); + assertTrue(accessPolicy1DTO.getUsers().contains(user1Entity)); + + assertEquals(1, accessPolicy1DTO.getUserGroups().size()); + assertTrue(accessPolicy1DTO.getUserGroups().contains(user2Entity)); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/UserEntityMergerTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/UserEntityMergerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/UserEntityMergerTest.java new file mode 100644 index 0000000..03db8b4 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/UserEntityMergerTest.java @@ -0,0 +1,114 @@ +/* + * 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.manager; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.dto.AccessPolicySummaryDTO; +import org.apache.nifi.web.api.dto.PermissionsDTO; +import org.apache.nifi.web.api.dto.TenantDTO; +import org.apache.nifi.web.api.dto.UserDTO; +import org.apache.nifi.web.api.entity.AccessPolicySummaryEntity; +import org.apache.nifi.web.api.entity.TenantEntity; +import org.apache.nifi.web.api.entity.UserEntity; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +public class UserEntityMergerTest { + + @Test + public void testMergeAccessPolicy() throws Exception { + final NodeIdentifier node1 = new NodeIdentifier("node-1", "host-1", 8080, "host-1", 19998, null, null, null, false); + final NodeIdentifier node2 = new NodeIdentifier("node-2", "host-2", 8081, "host-2", 19999, null, null, null, false); + + final PermissionsDTO permissed = new PermissionsDTO(); + permissed.setCanRead(true); + permissed.setCanWrite(true); + + final TenantDTO userGroup1DTO = new TenantDTO(); + userGroup1DTO.setId("user-group-1"); + + final TenantEntity userGroup1Entity = new TenantEntity(); + userGroup1Entity.setPermissions(permissed); + userGroup1Entity.setId(userGroup1DTO.getId()); + userGroup1Entity.setComponent(userGroup1DTO); + + final TenantDTO userGroup2DTO = new TenantDTO(); + userGroup1DTO.setId("user-group-2"); + + final TenantEntity userGroup2Entity = new TenantEntity(); + userGroup2Entity.setPermissions(permissed); + userGroup2Entity.setId(userGroup2DTO.getId()); + userGroup2Entity.setComponent(userGroup2DTO); + + final AccessPolicySummaryDTO policy1DTO = new AccessPolicySummaryDTO(); + policy1DTO.setId("policy-1"); + + final AccessPolicySummaryEntity policy1Entity = new AccessPolicySummaryEntity(); + policy1Entity.setPermissions(permissed); + policy1Entity.setId(policy1DTO.getId()); + policy1Entity.setComponent(policy1DTO); + + final AccessPolicySummaryDTO policy2DTO = new AccessPolicySummaryDTO(); + policy2DTO.setId("policy-2"); + + final AccessPolicySummaryEntity policy2Entity = new AccessPolicySummaryEntity(); + policy2Entity.setPermissions(permissed); + policy2Entity.setId(policy2DTO.getId()); + policy2Entity.setComponent(policy2DTO); + + final UserDTO user1DTO = new UserDTO(); + user1DTO.setId("user-1"); + user1DTO.setAccessPolicies(Stream.of(policy1Entity, policy2Entity).collect(Collectors.toSet())); + user1DTO.setUserGroups(Stream.of(userGroup2Entity).collect(Collectors.toSet())); + + final UserEntity user1Entity = new UserEntity(); + user1Entity.setPermissions(permissed); + user1Entity.setId(user1DTO.getId()); + user1Entity.setComponent(user1DTO); + + final UserDTO user2DTO = new UserDTO(); + user2DTO.setId("user-2"); + user2DTO.setAccessPolicies(Stream.of(policy1Entity).collect(Collectors.toSet())); + user2DTO.setUserGroups(Stream.of(userGroup1Entity, userGroup2Entity).collect(Collectors.toSet())); + + final UserEntity user2Entity = new UserEntity(); + user2Entity.setPermissions(permissed); + user2Entity.setId(user2DTO.getId()); + user2Entity.setComponent(user2DTO); + + final Map<NodeIdentifier, UserEntity> nodeMap = new HashMap<>(); + nodeMap.put(node1, user1Entity); + nodeMap.put(node2, user2Entity); + + final UserEntityMerger merger = new UserEntityMerger(); + merger.merge(user1Entity, nodeMap); + + assertEquals(1, user1DTO.getUserGroups().size()); + assertTrue(user1DTO.getAccessPolicies().contains(policy1Entity)); + + assertEquals(1, user1DTO.getUserGroups().size()); + assertTrue(user1DTO.getUserGroups().contains(userGroup2Entity)); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/UserGroupEntityMergerTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/UserGroupEntityMergerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/UserGroupEntityMergerTest.java new file mode 100644 index 0000000..cc975cb --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/manager/UserGroupEntityMergerTest.java @@ -0,0 +1,114 @@ +/* + * 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.manager; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.dto.AccessPolicyDTO; +import org.apache.nifi.web.api.dto.PermissionsDTO; +import org.apache.nifi.web.api.dto.TenantDTO; +import org.apache.nifi.web.api.dto.UserGroupDTO; +import org.apache.nifi.web.api.entity.AccessPolicyEntity; +import org.apache.nifi.web.api.entity.TenantEntity; +import org.apache.nifi.web.api.entity.UserGroupEntity; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +public class UserGroupEntityMergerTest { + + @Test + public void testMergeAccessPolicy() throws Exception { + final NodeIdentifier node1 = new NodeIdentifier("node-1", "host-1", 8080, "host-1", 19998, null, null, null, false); + final NodeIdentifier node2 = new NodeIdentifier("node-2", "host-2", 8081, "host-2", 19999, null, null, null, false); + + final PermissionsDTO permissed = new PermissionsDTO(); + permissed.setCanRead(true); + permissed.setCanWrite(true); + + final TenantDTO user1DTO = new TenantDTO(); + user1DTO.setId("user-1"); + + final TenantEntity user1Entity = new TenantEntity(); + user1Entity.setPermissions(permissed); + user1Entity.setId(user1DTO.getId()); + user1Entity.setComponent(user1DTO); + + final TenantDTO user2DTO = new TenantDTO(); + user1DTO.setId("user-2"); + + final TenantEntity user2Entity = new TenantEntity(); + user2Entity.setPermissions(permissed); + user2Entity.setId(user2DTO.getId()); + user2Entity.setComponent(user2DTO); + + final AccessPolicyDTO policy1DTO = new AccessPolicyDTO(); + policy1DTO.setId("policy-1"); + + final AccessPolicyEntity policy1Entity = new AccessPolicyEntity(); + policy1Entity.setPermissions(permissed); + policy1Entity.setId(policy1DTO.getId()); + policy1Entity.setComponent(policy1DTO); + + final AccessPolicyDTO policy2DTO = new AccessPolicyDTO(); + policy2DTO.setId("policy-2"); + + final AccessPolicyEntity policy2Entity = new AccessPolicyEntity(); + policy2Entity.setPermissions(permissed); + policy2Entity.setId(policy2DTO.getId()); + policy2Entity.setComponent(policy2DTO); + + final UserGroupDTO userGroup1DTO = new UserGroupDTO(); + userGroup1DTO.setId("user-1"); + userGroup1DTO.setAccessPolicies(Stream.of(policy1Entity, policy2Entity).collect(Collectors.toSet())); + userGroup1DTO.setUsers(Stream.of(user2Entity).collect(Collectors.toSet())); + + final UserGroupEntity userGroup1Entity = new UserGroupEntity(); + userGroup1Entity.setPermissions(permissed); + userGroup1Entity.setId(userGroup1DTO.getId()); + userGroup1Entity.setComponent(userGroup1DTO); + + final UserGroupDTO userGroup2DTO = new UserGroupDTO(); + userGroup2DTO.setId("user-2"); + userGroup2DTO.setAccessPolicies(Stream.of(policy1Entity).collect(Collectors.toSet())); + userGroup2DTO.setUsers(Stream.of(user1Entity, user2Entity).collect(Collectors.toSet())); + + final UserGroupEntity userGroup2Entity = new UserGroupEntity(); + userGroup2Entity.setPermissions(permissed); + userGroup2Entity.setId(userGroup2DTO.getId()); + userGroup2Entity.setComponent(userGroup2DTO); + + final Map<NodeIdentifier, UserGroupEntity> nodeMap = new HashMap<>(); + nodeMap.put(node1, userGroup1Entity); + nodeMap.put(node2, userGroup2Entity); + + final UserGroupEntityMerger merger = new UserGroupEntityMerger(); + merger.merge(userGroup1Entity, nodeMap); + + assertEquals(1, userGroup1DTO.getUsers().size()); + assertTrue(userGroup1DTO.getAccessPolicies().contains(policy1Entity)); + + assertEquals(1, userGroup1DTO.getUsers().size()); + assertTrue(userGroup1DTO.getUsers().contains(user2Entity)); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/cluster/protocol/DataFlow.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/cluster/protocol/DataFlow.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/cluster/protocol/DataFlow.java index 6e2b9fe..0317584 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/cluster/protocol/DataFlow.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/cluster/protocol/DataFlow.java @@ -32,7 +32,7 @@ public interface DataFlow { /** * @return the raw byte array of the Authorizer's fingerprint, - * null when not using a sub-class of AbstractPolicyBasedAuthorizer + * null when not using a ManagedAuthorizer */ public byte[] getAuthorizerFingerprint(); http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml index 57522f5..9d00f49 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml @@ -188,6 +188,10 @@ <version>4.3.1.201605051710-r</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-authorizer</artifactId> + </dependency> </dependencies> <build> <plugins> http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java index b2c1628..f2387c2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java @@ -17,8 +17,9 @@ package org.apache.nifi.controller; import org.apache.commons.lang3.StringUtils; -import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer; import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.AuthorizerCapabilityDetection; +import org.apache.nifi.authorization.ManagedAuthorizer; import org.apache.nifi.bundle.Bundle; import org.apache.nifi.cluster.ConnectionException; import org.apache.nifi.cluster.coordination.ClusterCoordinator; @@ -572,8 +573,8 @@ public class StandardFlowService implements FlowService, ProtocolHandler { } private byte[] getAuthorizerFingerprint() { - final boolean isInternalAuthorizer = (authorizer instanceof AbstractPolicyBasedAuthorizer); - return isInternalAuthorizer ? ((AbstractPolicyBasedAuthorizer) authorizer).getFingerprint().getBytes(StandardCharsets.UTF_8) : null; + final boolean isInternalAuthorizer = AuthorizerCapabilityDetection.isManagedAuthorizer(authorizer); + return isInternalAuthorizer ? ((ManagedAuthorizer) authorizer).getFingerprint().getBytes(StandardCharsets.UTF_8) : null; } @Override http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowSynchronizer.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowSynchronizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowSynchronizer.java index 6f1e8e1..01dd35e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowSynchronizer.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowSynchronizer.java @@ -18,8 +18,10 @@ package org.apache.nifi.controller; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer; import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.AuthorizerCapabilityDetection; +import org.apache.nifi.authorization.ManagedAuthorizer; +import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException; import org.apache.nifi.bundle.BundleCoordinate; import org.apache.nifi.cluster.protocol.DataFlow; import org.apache.nifi.cluster.protocol.StandardDataFlow; @@ -224,15 +226,15 @@ public class StandardFlowSynchronizer implements FlowSynchronizer { logger.trace("Getting Authorizer fingerprint from controller"); final byte[] existingAuthFingerprint; - final AbstractPolicyBasedAuthorizer policyBasedAuthorizer; + final ManagedAuthorizer managedAuthorizer; final Authorizer authorizer = controller.getAuthorizer(); - if (authorizer instanceof AbstractPolicyBasedAuthorizer) { - policyBasedAuthorizer = (AbstractPolicyBasedAuthorizer) authorizer; - existingAuthFingerprint = policyBasedAuthorizer.getFingerprint().getBytes(StandardCharsets.UTF_8); + if (AuthorizerCapabilityDetection.isManagedAuthorizer(authorizer)) { + managedAuthorizer = (ManagedAuthorizer) authorizer; + existingAuthFingerprint = managedAuthorizer.getFingerprint().getBytes(StandardCharsets.UTF_8); } else { existingAuthFingerprint = null; - policyBasedAuthorizer = null; + managedAuthorizer = null; } final Set<String> missingComponents = new HashSet<>(); @@ -249,7 +251,7 @@ public class StandardFlowSynchronizer implements FlowSynchronizer { if (existingFlowEmpty) { configuration = parseFlowBytes(proposedFlow.getFlow()); if (configuration != null) { - logger.trace("Checking bunde compatibility"); + logger.trace("Checking bundle compatibility"); checkBundleCompatibility(configuration); } } else { @@ -272,7 +274,7 @@ public class StandardFlowSynchronizer implements FlowSynchronizer { logger.trace("Checking authorizer inheritability"); - final AuthorizerInheritability authInheritability = checkAuthorizerInheritability(existingDataFlow, proposedFlow); + final AuthorizerInheritability authInheritability = checkAuthorizerInheritability(authorizer, existingDataFlow, proposedFlow); if (!authInheritability.isInheritable() && authInheritability.getReason() != null) { throw new UninheritableFlowException("Proposed Authorizer is not inheritable by the flow controller because of Authorizer differences: " + authInheritability.getReason()); } @@ -415,10 +417,10 @@ public class StandardFlowSynchronizer implements FlowSynchronizer { } // if auths are inheritable and we have a policy based authorizer, then inherit - if (authInheritability.isInheritable() && policyBasedAuthorizer != null) { + if (authInheritability.isInheritable() && managedAuthorizer != null) { logger.trace("Inheriting authorizations"); final String proposedAuthFingerprint = new String(proposedFlow.getAuthorizerFingerprint(), StandardCharsets.UTF_8); - policyBasedAuthorizer.inheritFingerprint(proposedAuthFingerprint); + managedAuthorizer.inheritFingerprint(proposedAuthFingerprint); } logger.debug("Finished syncing flows"); @@ -1391,7 +1393,7 @@ public class StandardFlowSynchronizer implements FlowSynchronizer { * @param proposedFlow the proposed DataFlow * @return the AuthorizerInheritability result */ - public AuthorizerInheritability checkAuthorizerInheritability(final DataFlow existingFlow, final DataFlow proposedFlow) { + private AuthorizerInheritability checkAuthorizerInheritability(final Authorizer authorizer, final DataFlow existingFlow, final DataFlow proposedFlow) { final byte[] existing = existingFlow.getAuthorizerFingerprint(); final byte[] proposed = proposedFlow.getAuthorizerFingerprint(); @@ -1414,15 +1416,20 @@ public class StandardFlowSynchronizer implements FlowSynchronizer { // both are internal, but not the same if (!Arrays.equals(existing, proposed)) { - final byte[] emptyAuthBytes = AbstractPolicyBasedAuthorizer.EMPTY_FINGERPRINT.getBytes(StandardCharsets.UTF_8); + if (AuthorizerCapabilityDetection.isManagedAuthorizer(authorizer)) { + final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer; - // if current is empty then we can take all the proposed authorizations - // otherwise they are both internal authorizers and don't match so we can't proceed - if (Arrays.equals(emptyAuthBytes, existing)) { - return AuthorizerInheritability.inheritable(); + try { + // if the configurations are not equal, see if the manager indicates the proposed configuration is inheritable + managedAuthorizer.checkInheritability(new String(proposed, StandardCharsets.UTF_8)); + return AuthorizerInheritability.inheritable(); + } catch (final UninheritableAuthorizationsException e) { + return AuthorizerInheritability.uninheritable("Proposed Authorizations do not match current Authorizations: " + e.getMessage()); + } } else { + // should never hit since the existing is only null when authorizer is not managed return AuthorizerInheritability.uninheritable( - "Proposed Authorizations do not match current Authorizations"); + "Proposed Authorizations do not match current Authorizations and are not configured with an internal Authorizer"); } } http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java index 14d3dcc..8326889 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java @@ -18,7 +18,9 @@ package org.apache.nifi.nar; import org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading; import org.apache.nifi.authentication.LoginIdentityProvider; +import org.apache.nifi.authorization.AccessPolicyProvider; import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.UserGroupProvider; import org.apache.nifi.bundle.Bundle; import org.apache.nifi.bundle.BundleCoordinate; import org.apache.nifi.components.ConfigurableComponent; @@ -82,6 +84,8 @@ public class ExtensionManager { definitionMap.put(ReportingTask.class, new HashSet<>()); definitionMap.put(ControllerService.class, new HashSet<>()); definitionMap.put(Authorizer.class, new HashSet<>()); + definitionMap.put(UserGroupProvider.class, new HashSet<>()); + definitionMap.put(AccessPolicyProvider.class, new HashSet<>()); definitionMap.put(LoginIdentityProvider.class, new HashSet<>()); definitionMap.put(ProvenanceRepository.class, new HashSet<>()); definitionMap.put(ComponentStatusRepository.class, new HashSet<>()); http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java index e7faa02..0be99dc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java @@ -17,7 +17,9 @@ package org.apache.nifi.nar; import org.apache.nifi.authentication.LoginIdentityProvider; +import org.apache.nifi.authorization.AccessPolicyProvider; import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.UserGroupProvider; import org.apache.nifi.bundle.Bundle; import org.apache.nifi.components.Validator; import org.apache.nifi.components.state.StateProvider; @@ -64,6 +66,8 @@ public class NarThreadContextClassLoader extends URLClassLoader { narSpecificClasses.add(StreamCallback.class); narSpecificClasses.add(ControllerService.class); narSpecificClasses.add(Authorizer.class); + narSpecificClasses.add(UserGroupProvider.class); + narSpecificClasses.add(AccessPolicyProvider.class); narSpecificClasses.add(LoginIdentityProvider.class); narSpecificClasses.add(ProvenanceRepository.class); narSpecificClasses.add(ComponentStatusRepository.class); http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml index 1816297..8e740a9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml @@ -141,7 +141,7 @@ <nifi.security.truststoreType /> <nifi.security.truststorePasswd /> <nifi.security.needClientAuth /> - <nifi.security.user.authorizer>file-provider</nifi.security.user.authorizer> + <nifi.security.user.authorizer>managed-authorizer</nifi.security.user.authorizer> <nifi.security.user.login.identity.provider /> <nifi.security.x509.principal.extractor /> <nifi.security.ocsp.responder.url /> http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml index 46bf637..247c0e8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml @@ -14,13 +14,105 @@ limitations under the License. --> <!-- - This file lists the authority providers to use when running securely. In order - to use a specific provider it must be configured here and it's identifier - must be specified in the nifi.properties file. + This file lists the userGroupProviders, accessPolicyProviders, and authorizers to use when running securely. In order + to use a specific authorizer it must be configured here and it's identifier must be specified in the nifi.properties file. + If the authorizer is a managedAuthorizer, it may need to be configured with an accessPolicyProvider and an userGroupProvider. + This file allows for configuration of them, but they must be configured in order: + + ... + all userGroupProviders + all accessPolicyProviders + all Authorizers + ... --> <authorizers> <!-- + The FileUserGroupProvider will provide support for managing users and groups which is backed by a file + on the local file system. + + - Users File - The file where the FileUserGroupProvider will store users and groups. + + - Legacy Authorized Users File - The full path to an existing authorized-users.xml that will be automatically + be used to load the users and groups into the Users File. + + - Initial User Identity [unique key] - The identity of a users and systems to seed the Users File. The name of + each property must be unique, for example: "Initial User Identity A", "Initial User Identity B", + "Initial User Identity C" or "Initial User Identity 1", "Initial User Identity 2", "Initial User Identity 3" + + NOTE: Any identity mapping rules specified in nifi.properties will also be applied to the user identities, + so the values should be the unmapped identities (i.e. full DN from a certificate). + --> + <userGroupProvider> + <identifier>file-user-group-provider</identifier> + <class>org.apache.nifi.authorization.FileUserGroupProvider</class> + <property name="Users File">./conf/users.xml</property> + <property name="Legacy Authorized Users File"></property> + + <property name="Initial User Identity 1"></property> + </userGroupProvider> + + <!-- + The FileAccessPolicyProvider will provide support for managing access policies which is backed by a file + on the local file system. + + - User Group Provider - The identifier for an User Group Provider defined above that will be used to access + users and groups for use in the managed access policies. + + - Authorizations File - The file where the FileAccessPolicyProvider will store policies. + + - Initial Admin Identity - The identity of an initial admin user that will be granted access to the UI and + given the ability to create additional users, groups, and policies. The value of this property could be + a DN when using certificates or LDAP, or a Kerberos principal. This property will only be used when there + are no other policies defined. If this property is specified then a Legacy Authorized Users File can not be specified. + + NOTE: Any identity mapping rules specified in nifi.properties will also be applied to the initial admin identity, + so the value should be the unmapped identity. This identity must be found in the configured User Group Provider. + + - Legacy Authorized Users File - The full path to an existing authorized-users.xml that will be automatically + converted to the new authorizations model. If this property is specified then an Initial Admin Identity can + not be specified, and this property will only be used when there are no other users, groups, and policies defined. + + NOTE: Any users in the legacy users file must be found in the configured User Group Provider. + + - Node Identity [unique key] - The identity of a NiFi cluster node. When clustered, a property for each node + should be defined, so that every node knows about every other node. If not clustered these properties can be ignored. + The name of each property must be unique, for example for a three node cluster: + "Node Identity A", "Node Identity B", "Node Identity C" or "Node Identity 1", "Node Identity 2", "Node Identity 3" + + NOTE: Any identity mapping rules specified in nifi.properties will also be applied to the node identities, + so the values should be the unmapped identities (i.e. full DN from a certificate). This identity must be found + in the configured User Group Provider. + --> + <accessPolicyProvider> + <identifier>file-access-policy-provider</identifier> + <class>org.apache.nifi.authorization.FileAccessPolicyProvider</class> + <property name="User Group Provider">file-user-group-provider</property> + <property name="Authorizations File">./conf/authorizations.xml</property> + <property name="Initial Admin Identity"></property> + <property name="Legacy Authorized Users File"></property> + + <property name="Node Identity 1"></property> + </accessPolicyProvider> + + <!-- + The StandardManagedAuthorizer. This authorizer implementation must be configured with the + Access Policy Provider which it will use to access and manage users, groups, and policies. + These users, groups, and policies will be used to make all access decisions during authorization + requests. + + - Access Policy Provider - The identifier for an Access Policy Provider defined above. + --> + <authorizer> + <identifier>managed-authorizer</identifier> + <class>org.apache.nifi.authorization.StandardManagedAuthorizer</class> + <property name="Access Policy Provider">file-access-policy-provider</property> + </authorizer> + + <!-- + NOTE: This Authorizer has been replaced with the more granular approach configured above with the Standard + Managed Authorizer. However, it is still available for backwards compatibility reasons. + The FileAuthorizer is NiFi's provided authorizer and has the following properties: - Authorizations File - The file where the FileAuthorizer will store policies. @@ -48,7 +140,7 @@ NOTE: Any identity mapping rules specified in nifi.properties will also be applied to the node identities, so the values should be the unmapped identities (i.e. full DN from a certificate). --> - <authorizer> + <!-- <authorizer> <identifier>file-provider</identifier> <class>org.apache.nifi.authorization.FileAuthorizer</class> <property name="Authorizations File">./conf/authorizations.xml</property> @@ -56,9 +148,7 @@ <property name="Initial Admin Identity"></property> <property name="Legacy Authorized Users File"></property> - <!-- Provide the identity (typically a DN) of each node when clustered, see above description of Node Identity. <property name="Node Identity 1"></property> - <property name="Node Identity 2"></property> - --> </authorizer> + --> </authorizers> \ No newline at end of file
