http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProvider.java ---------------------------------------------------------------------- diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProvider.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProvider.java new file mode 100644 index 0000000..a7b7a0b --- /dev/null +++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProvider.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization; + +import org.apache.nifi.authorization.exception.AuthorizationAccessException; +import org.apache.nifi.authorization.exception.AuthorizerCreationException; +import org.apache.nifi.authorization.exception.AuthorizerDestructionException; + +import java.util.Set; + +/** + * Provides access to Users and Groups. + * + * NOTE: Extensions will be called often and frequently. Because of this, if the underlying implementation needs to + * make remote calls or expensive calculations those should probably be done asynchronously and/or cache the results. + * + * Additionally, extensions need to be thread safe. + */ +public interface UserGroupProvider { + + /** + * Retrieves all users. Must be non null + * + * @return a list of users + * @throws AuthorizationAccessException if there was an unexpected error performing the operation + */ + Set<User> getUsers() throws AuthorizationAccessException; + + /** + * Retrieves the user with the given identifier. + * + * @param identifier the id of the user to retrieve + * @return the user with the given id, or null if no matching user was found + * @throws AuthorizationAccessException if there was an unexpected error performing the operation + */ + User getUser(String identifier) throws AuthorizationAccessException; + + /** + * Retrieves the user with the given identity. + * + * @param identity the identity of the user to retrieve + * @return the user with the given identity, or null if no matching user was found + * @throws AuthorizationAccessException if there was an unexpected error performing the operation + */ + User getUserByIdentity(String identity) throws AuthorizationAccessException; + + /** + * Retrieves all groups. Must be non null + * + * @return a list of groups + * @throws AuthorizationAccessException if there was an unexpected error performing the operation + */ + Set<Group> getGroups() throws AuthorizationAccessException; + + /** + * Retrieves a Group by id. + * + * @param identifier the identifier of the Group to retrieve + * @return the Group with the given identifier, or null if no matching group was found + * @throws AuthorizationAccessException if there was an unexpected error performing the operation + */ + Group getGroup(String identifier) throws AuthorizationAccessException; + + /** + * Gets a user and their groups. Must be non null. If the user is not known the UserAndGroups.getUser() and + * UserAndGroups.getGroups() should return null + * + * @return the UserAndGroups for the specified identity + * @throws AuthorizationAccessException if there was an unexpected error performing the operation + */ + UserAndGroups getUserAndGroups(String identity) throws AuthorizationAccessException; + + /** + * Called immediately after instance creation for implementers to perform additional setup + * + * @param initializationContext in which to initialize + */ + void initialize(UserGroupProviderInitializationContext initializationContext) throws AuthorizerCreationException; + + /** + * Called to configure the Authorizer. + * + * @param configurationContext at the time of configuration + * @throws AuthorizerCreationException for any issues configuring the provider + */ + void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException; + + /** + * Called immediately before instance destruction for implementers to release resources. + * + * @throws AuthorizerDestructionException If pre-destruction fails. + */ + void preDestruction() throws AuthorizerDestructionException; +}
http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProviderInitializationContext.java ---------------------------------------------------------------------- diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProviderInitializationContext.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProviderInitializationContext.java new file mode 100644 index 0000000..d83b4b3 --- /dev/null +++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProviderInitializationContext.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization; + +/** + * Initialization content for UserGroupProviders. + */ +public interface UserGroupProviderInitializationContext { + + /** + * The identifier of the UserGroupProvider. + * + * @return The identifier + */ + String getIdentifier(); + + /** + * The lookup for accessing other configured UserGroupProviders. + * + * @return The UserGroupProvider lookup + */ + UserGroupProviderLookup getUserGroupProviderLookup(); +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProviderLookup.java ---------------------------------------------------------------------- diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProviderLookup.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProviderLookup.java new file mode 100644 index 0000000..b879374 --- /dev/null +++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/UserGroupProviderLookup.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization; + +/** + * + */ +public interface UserGroupProviderLookup { + + /** + * Looks up the UserGroupProvider with the specified identifier + * + * @param identifier The identifier of the UserGroupProvider + * @return The UserGroupProvider + */ + UserGroupProvider getUserGroupProvider(String identifier); +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/UninheritableAuthorizationsException.java ---------------------------------------------------------------------- diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/UninheritableAuthorizationsException.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/UninheritableAuthorizationsException.java new file mode 100644 index 0000000..f75ead8 --- /dev/null +++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/exception/UninheritableAuthorizationsException.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization.exception; + +/** + * Represents the case when the proposed authorizations are not inheritable. + */ +public class UninheritableAuthorizationsException extends RuntimeException { + + public UninheritableAuthorizationsException(String message) { + super(message); + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java ---------------------------------------------------------------------- diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java index 3219ac2..cd27e10 100644 --- a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java +++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java @@ -84,6 +84,7 @@ public interface Authorizable { final Resource resource = getResource(); final AuthorizationRequest request = new AuthorizationRequest.Builder() .identity(user.getIdentity()) + .groups(user.getGroups()) .anonymous(user.isAnonymous()) .accessAttempt(false) .action(action) @@ -188,6 +189,7 @@ public interface Authorizable { final Resource resource = getResource(); final AuthorizationRequest request = new AuthorizationRequest.Builder() .identity(user.getIdentity()) + .groups(user.getGroups()) .anonymous(user.isAnonymous()) .accessAttempt(true) .action(action) http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java ---------------------------------------------------------------------- diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java index c450bc4..6b8012b 100644 --- a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java +++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java @@ -17,6 +17,8 @@ package org.apache.nifi.authorization.user; +import java.util.Set; + /** * A representation of a NiFi user that has logged into the application */ @@ -28,6 +30,11 @@ public interface NiFiUser { String getIdentity(); /** + * @return the groups that this user belongs to if this nifi is configured to load user groups, null otherwise. + */ + Set<String> getGroups(); + + /** * @return the next user in the proxied entities chain, or <code>null</code> if no more users exist in the chain. */ NiFiUser getChain(); http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-framework-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java ---------------------------------------------------------------------- diff --git a/nifi-framework-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java b/nifi-framework-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java index cda2ac5..08c8bb3 100644 --- a/nifi-framework-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java +++ b/nifi-framework-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java @@ -16,7 +16,6 @@ */ package org.apache.nifi.authorization; -import org.apache.nifi.authorization.exception.AuthorizerCreationException; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -251,10 +250,7 @@ public class TestAbstractPolicyBasedAuthorizer { when(authorizer2.getAccessPolicies()).thenReturn(policies2); // compare the fingerprints - assertEquals(authorizer1.getFingerprint(), authorizer2.getFingerprint()); - - //System.out.println(authorizer1.getFingerprint()); } @Test @@ -332,211 +328,4 @@ public class TestAbstractPolicyBasedAuthorizer { Assert.assertTrue(fingerprint.length() > 0); } - @Test(expected = AuthorizerCreationException.class) - public void testOnConfiguredWhenPoliciesWithSameResourceAndAction() { - User user1 = new User.Builder().identifier("user-id-1").identity("user-1").build(); - - AccessPolicy policy1 = new AccessPolicy.Builder() - .identifier("policy-id-1") - .resource("resource1") - .action(RequestAction.READ) - .addUser(user1.getIdentifier()) - .build(); - - AccessPolicy policy2 = new AccessPolicy.Builder() - .identifier("policy-id-2") - .resource("resource1") - .action(RequestAction.READ) - .addUser(user1.getIdentifier()) - .build(); - - Set<AccessPolicy> policies = new LinkedHashSet<>(); - policies.add(policy1); - policies.add(policy2); - - Set<User> users = new LinkedHashSet<>(); - users.add(user1); - - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(new HashSet<>(), users, policies); - authorizer.onConfigured(context); - } - - @Test(expected = AuthorizerCreationException.class) - public void testOnConfiguredWhenUsersWithSameIdentity() { - User user1 = new User.Builder().identifier("user-id-1").identity("user-1").build(); - User user2 = new User.Builder().identifier("user-id-2").identity("user-1").build(); - - Set<User> users = new LinkedHashSet<>(); - users.add(user1); - users.add(user2); - - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(new HashSet<>(), users, new HashSet<>()); - authorizer.onConfigured(context); - } - - @Test(expected = AuthorizerCreationException.class) - public void testOnConfiguredWhenGroupsWithSameName() { - Group group1 = new Group.Builder().identifier("group-id-1").name("group-1").build(); - Group group2 = new Group.Builder().identifier("group-id-2").name("group-1").build(); - - Set<Group> groups = new LinkedHashSet<>(); - groups.add(group1); - groups.add(group2); - - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(groups, new HashSet<>(), new HashSet<>()); - authorizer.onConfigured(context); - } - - @Test - public void testAddPoliciesWithSameResourceAndAction() { - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(); - authorizer.onConfigured(context); - - User user1 = new User.Builder().identifier("user-id-1").identity("user-1").build(); - authorizer.addUser(user1); - - AccessPolicy policy1 = new AccessPolicy.Builder() - .identifier("policy-id-1") - .resource("resource1") - .action(RequestAction.READ) - .addUser(user1.getIdentifier()) - .build(); - authorizer.addAccessPolicy(policy1); - - AccessPolicy policy2 = new AccessPolicy.Builder() - .identifier("policy-id-2") - .resource("resource1") - .action(RequestAction.READ) - .addUser(user1.getIdentifier()) - .build(); - - try { - authorizer.addAccessPolicy(policy2); - Assert.fail("Should have thrown exception"); - } catch (IllegalStateException e) { - - } - } - - @Test - public void testAddUsersWithSameIdentity() { - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(); - authorizer.onConfigured(context); - - User user1 = new User.Builder().identifier("user-id-1").identity("user-1").build(); - authorizer.addUser(user1); - - User user2 = new User.Builder().identifier("user-id-2").identity("user-1").build(); - - try { - authorizer.addUser(user2); - Assert.fail("Should have thrown exception"); - } catch (IllegalStateException e) { - - } - } - - @Test - public void testAddGroupsWithSameName() { - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(); - authorizer.onConfigured(context); - - Group group1 = new Group.Builder().identifier("group-id-1").name("group-1").build(); - authorizer.addGroup(group1); - - Group group2 = new Group.Builder().identifier("group-id-2").name("group-1").build(); - - try { - authorizer.addGroup(group2); - Assert.fail("Should have thrown exception"); - } catch (IllegalStateException e) { - - } - } - - @Test - public void testAddUsersWithSameIdentityAsGroupName() { - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(); - authorizer.onConfigured(context); - - Group group1 = new Group.Builder().identifier("group-id-1").name("abc").build(); - authorizer.addGroup(group1); - - User user = new User.Builder().identifier("user-id-2").identity("abc").build(); - - try { - authorizer.addUser(user); - Assert.fail("Should have thrown exception"); - } catch (IllegalStateException e) { - - } - } - - @Test - public void testAddGroupWithSameNameAsUserIdentity() { - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(); - authorizer.onConfigured(context); - - User user = new User.Builder().identifier("user-id-2").identity("abc").build(); - authorizer.addUser(user); - - Group group1 = new Group.Builder().identifier("group-id-1").name("abc").build(); - try { - authorizer.addGroup(group1); - Assert.fail("Should have thrown exception"); - } catch (IllegalStateException e) { - - } - } - - @Test - public void testUpdateUserWithSameIdentity() { - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(); - authorizer.onConfigured(context); - - User user1 = new User.Builder().identifier("user-id-1").identity("abc").build(); - authorizer.addUser(user1); - - User user2 = new User.Builder().identifier("user-id-2").identity("xyz").build(); - authorizer.addUser(user2); - - try { - User user1Updated = new User.Builder().identifier("user-id-1").identity("xyz").build(); - authorizer.updateUser(user1Updated); - Assert.fail("Should have thrown exception"); - } catch (IllegalStateException e) { - - } - } - - @Test - public void testUpdateGroupWithSameName() { - AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class); - AbstractPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer(); - authorizer.onConfigured(context); - - Group group1 = new Group.Builder().identifier("group-id-1").name("abc").build(); - authorizer.addGroup(group1); - - Group group2 = new Group.Builder().identifier("group-id-2").name("xyz").build(); - authorizer.addGroup(group2); - - try { - Group group1Updated = new Group.Builder().identifier("group-id-1").name("xyz").build(); - authorizer.updateGroup(group1Updated); - Assert.fail("Should have thrown exception"); - } catch (IllegalStateException e) { - - } - } - } http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml index 1fe42d9..b0a64d9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml @@ -65,15 +65,27 @@ </dependency> <dependency> <groupId>org.apache.nifi</groupId> - <artifactId>nifi-framework-core</artifactId> + <artifactId>nifi-nar-utils</artifactId> </dependency> <dependency> <groupId>org.apache.nifi</groupId> - <artifactId>nifi-nar-utils</artifactId> + <artifactId>nifi-properties</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-beans</artifactId> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> </dependency> <dependency> <groupId>org.apache.nifi</groupId> - <artifactId>nifi-properties</artifactId> + <artifactId>nifi-framework-nar-utils</artifactId> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-framework-authorization</artifactId> </dependency> </dependencies> http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AccessPolicyProviderFactory.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AccessPolicyProviderFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AccessPolicyProviderFactory.java new file mode 100644 index 0000000..c71c982 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AccessPolicyProviderFactory.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization; + +import org.apache.nifi.authorization.exception.AuthorizationAccessException; +import org.apache.nifi.authorization.exception.AuthorizerCreationException; +import org.apache.nifi.authorization.exception.AuthorizerDestructionException; +import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException; +import org.apache.nifi.nar.NarCloseable; + +import java.util.Set; + +public final class AccessPolicyProviderFactory { + + public static AccessPolicyProvider withNarLoader(final AccessPolicyProvider baseAccessPolicyProvider) { + if (baseAccessPolicyProvider instanceof ConfigurableAccessPolicyProvider) { + final ConfigurableAccessPolicyProvider baseConfigurableAccessPolicyProvider = (ConfigurableAccessPolicyProvider) baseAccessPolicyProvider; + return new ConfigurableAccessPolicyProvider() { + @Override + public AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseConfigurableAccessPolicyProvider.addAccessPolicy(accessPolicy); + } + } + + @Override + public AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseConfigurableAccessPolicyProvider.updateAccessPolicy(accessPolicy); + } + } + + @Override + public AccessPolicy deleteAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseConfigurableAccessPolicyProvider.deleteAccessPolicy(accessPolicy); + } + } + + @Override + public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseConfigurableAccessPolicyProvider.getAccessPolicies(); + } + } + + @Override + public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseConfigurableAccessPolicyProvider.getAccessPolicy(identifier); + } + } + + @Override + public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseConfigurableAccessPolicyProvider.getAccessPolicy(resourceIdentifier, action); + } + } + + @Override + public UserGroupProvider getUserGroupProvider() { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseConfigurableAccessPolicyProvider.getUserGroupProvider(); + } + } + + @Override + public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseConfigurableAccessPolicyProvider.inheritFingerprint(fingerprint); + } + } + + @Override + public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseConfigurableAccessPolicyProvider.checkInheritability(proposedFingerprint); + } + } + + @Override + public String getFingerprint() throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseConfigurableAccessPolicyProvider.getFingerprint(); + } + } + + @Override + public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseConfigurableAccessPolicyProvider.initialize(initializationContext); + } + } + + @Override + public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseConfigurableAccessPolicyProvider.onConfigured(configurationContext); + } + } + + @Override + public void preDestruction() throws AuthorizerDestructionException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseConfigurableAccessPolicyProvider.preDestruction(); + } + } + }; + } else { + return new AccessPolicyProvider() { + @Override + public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseAccessPolicyProvider.getAccessPolicies(); + } + } + + @Override + public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseAccessPolicyProvider.getAccessPolicy(identifier); + } + } + + @Override + public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseAccessPolicyProvider.getAccessPolicy(resourceIdentifier, action); + } + } + + @Override + public UserGroupProvider getUserGroupProvider() { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseAccessPolicyProvider.getUserGroupProvider(); + } + } + + @Override + public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseAccessPolicyProvider.initialize(initializationContext); + } + } + + @Override + public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseAccessPolicyProvider.onConfigured(configurationContext); + } + } + + @Override + public void preDestruction() throws AuthorizerDestructionException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseAccessPolicyProvider.preDestruction(); + } + } + }; + } + } + + private AccessPolicyProviderFactory() {} +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerCapabilityDetection.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerCapabilityDetection.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerCapabilityDetection.java new file mode 100644 index 0000000..59de908 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerCapabilityDetection.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization; + +public final class AuthorizerCapabilityDetection { + + public static boolean isManagedAuthorizer(final Authorizer authorizer) { + return authorizer instanceof ManagedAuthorizer; + } + + public static boolean isConfigurableAccessPolicyProvider(final Authorizer authorizer) { + if (!isManagedAuthorizer(authorizer)) { + return false; + } + + final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer; + return managedAuthorizer.getAccessPolicyProvider() instanceof ConfigurableAccessPolicyProvider; + } + + public static boolean isConfigurableUserGroupProvider(final Authorizer authorizer) { + if (!isManagedAuthorizer(authorizer)) { + return false; + } + + final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer; + final AccessPolicyProvider accessPolicyProvider = managedAuthorizer.getAccessPolicyProvider(); + return accessPolicyProvider.getUserGroupProvider() instanceof ConfigurableUserGroupProvider; + } + + private AuthorizerCapabilityDetection() {} +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactory.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactory.java new file mode 100644 index 0000000..660b47b --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactory.java @@ -0,0 +1,426 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization; + +import org.apache.nifi.authorization.exception.AuthorizationAccessException; +import org.apache.nifi.authorization.exception.AuthorizerCreationException; +import org.apache.nifi.authorization.exception.AuthorizerDestructionException; +import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException; +import org.apache.nifi.nar.NarCloseable; + +import java.util.Set; + +public final class AuthorizerFactory { + + /** + * Checks if another policy exists with the same resource and action as the given policy. + * + * @param checkAccessPolicy an access policy being checked + * @return true if another access policy exists with the same resource and action, false otherwise + */ + private static boolean policyExists(final AccessPolicyProvider accessPolicyProvider, final AccessPolicy checkAccessPolicy) { + for (AccessPolicy accessPolicy : accessPolicyProvider.getAccessPolicies()) { + if (!accessPolicy.getIdentifier().equals(checkAccessPolicy.getIdentifier()) + && accessPolicy.getResource().equals(checkAccessPolicy.getResource()) + && accessPolicy.getAction().equals(checkAccessPolicy.getAction())) { + return true; + } + } + return false; + } + + /** + * Checks if another user exists with the same identity. + * + * @param identifier identity of the user + * @param identity identity of the user + * @return true if another user exists with the same identity, false otherwise + */ + private static boolean tenantExists(final UserGroupProvider userGroupProvider, final String identifier, final String identity) { + for (User user : userGroupProvider.getUsers()) { + if (!user.getIdentifier().equals(identifier) + && user.getIdentity().equals(identity)) { + return true; + } + } + + for (Group group : userGroupProvider.getGroups()) { + if (!group.getIdentifier().equals(identifier) + && group.getName().equals(identity)) { + return true; + } + } + + return false; + } + + public static Authorizer installIntegrityChecks(final Authorizer baseAuthorizer) { + if (baseAuthorizer instanceof ManagedAuthorizer) { + final ManagedAuthorizer baseManagedAuthorizer = (ManagedAuthorizer) baseAuthorizer; + return new ManagedAuthorizer() { + @Override + public String getFingerprint() throws AuthorizationAccessException { + return baseManagedAuthorizer.getFingerprint(); + } + + @Override + public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException { + baseManagedAuthorizer.inheritFingerprint(fingerprint); + } + + @Override + public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException { + baseManagedAuthorizer.checkInheritability(proposedFingerprint); + } + + @Override + public AccessPolicyProvider getAccessPolicyProvider() { + final AccessPolicyProvider baseAccessPolicyProvider = baseManagedAuthorizer.getAccessPolicyProvider(); + if (baseAccessPolicyProvider instanceof ConfigurableAccessPolicyProvider) { + final ConfigurableAccessPolicyProvider baseConfigurableAccessPolicyProvider = (ConfigurableAccessPolicyProvider) baseAccessPolicyProvider; + return new ConfigurableAccessPolicyProvider() { + @Override + public String getFingerprint() throws AuthorizationAccessException { + return baseConfigurableAccessPolicyProvider.getFingerprint(); + } + + @Override + public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException { + baseConfigurableAccessPolicyProvider.inheritFingerprint(fingerprint); + } + + @Override + public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException { + baseConfigurableAccessPolicyProvider.checkInheritability(proposedFingerprint); + } + + @Override + public AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { + if (policyExists(baseConfigurableAccessPolicyProvider, accessPolicy)) { + throw new IllegalStateException(String.format("Found multiple policies for '%s' with '%s'.", accessPolicy.getResource(), accessPolicy.getAction())); + } + return baseConfigurableAccessPolicyProvider.addAccessPolicy(accessPolicy); + } + + @Override + public AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { + return baseConfigurableAccessPolicyProvider.updateAccessPolicy(accessPolicy); + } + + @Override + public AccessPolicy deleteAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { + return baseConfigurableAccessPolicyProvider.deleteAccessPolicy(accessPolicy); + } + + @Override + public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException { + return baseConfigurableAccessPolicyProvider.getAccessPolicies(); + } + + @Override + public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException { + return baseConfigurableAccessPolicyProvider.getAccessPolicy(identifier); + } + + @Override + public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException { + return baseConfigurableAccessPolicyProvider.getAccessPolicy(resourceIdentifier, action); + } + + @Override + public UserGroupProvider getUserGroupProvider() { + final UserGroupProvider baseUserGroupProvider = baseConfigurableAccessPolicyProvider.getUserGroupProvider(); + if (baseUserGroupProvider instanceof ConfigurableUserGroupProvider) { + final ConfigurableUserGroupProvider baseConfigurableUserGroupProvider = (ConfigurableUserGroupProvider) baseUserGroupProvider; + return new ConfigurableUserGroupProvider() { + @Override + public String getFingerprint() throws AuthorizationAccessException { + return baseConfigurableUserGroupProvider.getFingerprint(); + } + + @Override + public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException { + baseConfigurableUserGroupProvider.inheritFingerprint(fingerprint); + } + + @Override + public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException { + baseConfigurableUserGroupProvider.checkInheritability(proposedFingerprint); + } + + @Override + public User addUser(User user) throws AuthorizationAccessException { + if (tenantExists(baseConfigurableUserGroupProvider, user.getIdentifier(), user.getIdentity())) { + throw new IllegalStateException(String.format("User/user group already exists with the identity '%s'.", user.getIdentity())); + } + return baseConfigurableUserGroupProvider.addUser(user); + } + + @Override + public User updateUser(User user) throws AuthorizationAccessException { + if (tenantExists(baseConfigurableUserGroupProvider, user.getIdentifier(), user.getIdentity())) { + throw new IllegalStateException(String.format("User/user group already exists with the identity '%s'.", user.getIdentity())); + } + return baseConfigurableUserGroupProvider.updateUser(user); + } + + @Override + public User deleteUser(User user) throws AuthorizationAccessException { + return baseConfigurableUserGroupProvider.deleteUser(user); + } + + @Override + public Group addGroup(Group group) throws AuthorizationAccessException { + if (tenantExists(baseConfigurableUserGroupProvider, group.getIdentifier(), group.getName())) { + throw new IllegalStateException(String.format("User/user group already exists with the identity '%s'.", group.getName())); + } + return baseConfigurableUserGroupProvider.addGroup(group); + } + + @Override + public Group updateGroup(Group group) throws AuthorizationAccessException { + if (tenantExists(baseConfigurableUserGroupProvider, group.getIdentifier(), group.getName())) { + throw new IllegalStateException(String.format("User/user group already exists with the identity '%s'.", group.getName())); + } + return baseConfigurableUserGroupProvider.updateGroup(group); + } + + @Override + public Group deleteGroup(Group group) throws AuthorizationAccessException { + return baseConfigurableUserGroupProvider.deleteGroup(group); + } + + @Override + public Set<User> getUsers() throws AuthorizationAccessException { + return baseConfigurableUserGroupProvider.getUsers(); + } + + @Override + public User getUser(String identifier) throws AuthorizationAccessException { + return baseConfigurableUserGroupProvider.getUser(identifier); + } + + @Override + public User getUserByIdentity(String identity) throws AuthorizationAccessException { + return baseConfigurableUserGroupProvider.getUserByIdentity(identity); + } + + @Override + public Set<Group> getGroups() throws AuthorizationAccessException { + return baseConfigurableUserGroupProvider.getGroups(); + } + + @Override + public Group getGroup(String identifier) throws AuthorizationAccessException { + return baseConfigurableUserGroupProvider.getGroup(identifier); + } + + @Override + public UserAndGroups getUserAndGroups(String identity) throws AuthorizationAccessException { + return baseConfigurableUserGroupProvider.getUserAndGroups(identity); + } + + @Override + public void initialize(UserGroupProviderInitializationContext initializationContext) throws AuthorizerCreationException { + baseConfigurableUserGroupProvider.initialize(initializationContext); + } + + @Override + public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { + baseConfigurableUserGroupProvider.onConfigured(configurationContext); + } + + @Override + public void preDestruction() throws AuthorizerDestructionException { + baseConfigurableUserGroupProvider.preDestruction(); + } + }; + } else { + return baseUserGroupProvider; + } + } + + @Override + public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException { + baseConfigurableAccessPolicyProvider.initialize(initializationContext); + } + + @Override + public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { + baseConfigurableAccessPolicyProvider.onConfigured(configurationContext); + } + + @Override + public void preDestruction() throws AuthorizerDestructionException { + baseConfigurableAccessPolicyProvider.preDestruction(); + } + }; + } else { + return baseAccessPolicyProvider; + } + } + + @Override + public AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException { + return baseManagedAuthorizer.authorize(request); + } + + @Override + public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException { + baseManagedAuthorizer.initialize(initializationContext); + } + + @Override + public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { + baseManagedAuthorizer.onConfigured(configurationContext); + + final AccessPolicyProvider accessPolicyProvider = baseManagedAuthorizer.getAccessPolicyProvider(); + final UserGroupProvider userGroupProvider = accessPolicyProvider.getUserGroupProvider(); + + // ensure that only one policy per resource-action exists + for (AccessPolicy accessPolicy : accessPolicyProvider.getAccessPolicies()) { + if (policyExists(accessPolicyProvider, accessPolicy)) { + throw new AuthorizerCreationException(String.format("Found multiple policies for '%s' with '%s'.", accessPolicy.getResource(), accessPolicy.getAction())); + } + } + + // ensure that only one group exists per identity + for (User user : userGroupProvider.getUsers()) { + if (tenantExists(userGroupProvider, user.getIdentifier(), user.getIdentity())) { + throw new AuthorizerCreationException(String.format("Found multiple users/user groups with identity '%s'.", user.getIdentity())); + } + } + + // ensure that only one group exists per identity + for (Group group : userGroupProvider.getGroups()) { + if (tenantExists(userGroupProvider, group.getIdentifier(), group.getName())) { + throw new AuthorizerCreationException(String.format("Found multiple users/user groups with name '%s'.", group.getName())); + } + } + } + + @Override + public void preDestruction() throws AuthorizerDestructionException { + baseManagedAuthorizer.preDestruction(); + } + }; + } else { + return baseAuthorizer; + } + } + + /** + * Decorates the base authorizer to ensure the nar context classloader is used when invoking the underlying methods. + * + * @param baseAuthorizer base authorizer + * @return authorizer + */ + public static Authorizer withNarLoader(final Authorizer baseAuthorizer) { + if (baseAuthorizer instanceof ManagedAuthorizer) { + final ManagedAuthorizer baseManagedAuthorizer = (ManagedAuthorizer) baseAuthorizer; + return new ManagedAuthorizer() { + @Override + public String getFingerprint() throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseManagedAuthorizer.getFingerprint(); + } + } + + @Override + public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseManagedAuthorizer.inheritFingerprint(fingerprint); + } + } + + @Override + public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseManagedAuthorizer.checkInheritability(proposedFingerprint); + } + } + + @Override + public AccessPolicyProvider getAccessPolicyProvider() { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseManagedAuthorizer.getAccessPolicyProvider(); + } + } + + @Override + public AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseManagedAuthorizer.authorize(request); + } + } + + @Override + public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseManagedAuthorizer.initialize(initializationContext); + } + } + + @Override + public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseManagedAuthorizer.onConfigured(configurationContext); + } + } + + @Override + public void preDestruction() throws AuthorizerDestructionException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseManagedAuthorizer.preDestruction(); + } + } + }; + } else { + return new Authorizer() { + @Override + public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseAuthorizer.authorize(request); + } + } + + @Override + public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseAuthorizer.initialize(initializationContext); + } + } + + @Override + public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseAuthorizer.onConfigured(configurationContext); + } + } + + @Override + public void preDestruction() throws AuthorizerDestructionException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseAuthorizer.preDestruction(); + } + } + }; + } + } + + private AuthorizerFactory() {} +} http://git-wip-us.apache.org/repos/asf/nifi/blob/4ed7511b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java index b934cb8..9de8756 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java @@ -25,7 +25,6 @@ import org.apache.nifi.authorization.generated.Authorizers; import org.apache.nifi.authorization.generated.Property; import org.apache.nifi.bundle.Bundle; import org.apache.nifi.nar.ExtensionManager; -import org.apache.nifi.nar.NarCloseable; import org.apache.nifi.util.NiFiProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,12 +48,11 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; /** * Factory bean for loading the configured authorizer. */ -public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, AuthorizerLookup { +public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, UserGroupProviderLookup, AccessPolicyProviderLookup, AuthorizerLookup { private static final Logger logger = LoggerFactory.getLogger(AuthorizerFactoryBean.class); private static final String AUTHORIZERS_XSD = "/authorizers.xsd"; @@ -74,8 +72,19 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho private Authorizer authorizer; private NiFiProperties properties; + private final Map<String, UserGroupProvider> userGroupProviders = new HashMap<>(); + private final Map<String, AccessPolicyProvider> accessPolicyProviders = new HashMap<>(); private final Map<String, Authorizer> authorizers = new HashMap<>(); + @Override + public UserGroupProvider getUserGroupProvider(String identifier) { + return userGroupProviders.get(identifier); + } + + @Override + public AccessPolicyProvider getAccessPolicyProvider(String identifier) { + return accessPolicyProviders.get(identifier); + } @Override public Authorizer getAuthorizer(String identifier) { @@ -98,6 +107,28 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho } else { final Authorizers authorizerConfiguration = loadAuthorizersConfiguration(); + // create each user group provider + for (final org.apache.nifi.authorization.generated.UserGroupProvider userGroupProvider : authorizerConfiguration.getUserGroupProvider()) { + userGroupProviders.put(userGroupProvider.getIdentifier(), createUserGroupProvider(userGroupProvider.getIdentifier(), userGroupProvider.getClazz())); + } + + // configure each user group provider + for (final org.apache.nifi.authorization.generated.UserGroupProvider provider : authorizerConfiguration.getUserGroupProvider()) { + final UserGroupProvider instance = userGroupProviders.get(provider.getIdentifier()); + instance.onConfigured(loadAuthorizerConfiguration(provider.getIdentifier(), provider.getProperty())); + } + + // create each access policy provider + for (final org.apache.nifi.authorization.generated.AccessPolicyProvider accessPolicyProvider : authorizerConfiguration.getAccessPolicyProvider()) { + accessPolicyProviders.put(accessPolicyProvider.getIdentifier(), createAccessPolicyProvider(accessPolicyProvider.getIdentifier(), accessPolicyProvider.getClazz())); + } + + // configure each access policy provider + for (final org.apache.nifi.authorization.generated.AccessPolicyProvider provider : authorizerConfiguration.getAccessPolicyProvider()) { + final AccessPolicyProvider instance = accessPolicyProviders.get(provider.getIdentifier()); + instance.onConfigured(loadAuthorizerConfiguration(provider.getIdentifier(), provider.getProperty())); + } + // create each authorizer for (final org.apache.nifi.authorization.generated.Authorizer authorizer : authorizerConfiguration.getAuthorizer()) { authorizers.put(authorizer.getIdentifier(), createAuthorizer(authorizer.getIdentifier(), authorizer.getClazz())); @@ -106,7 +137,7 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho // configure each authorizer for (final org.apache.nifi.authorization.generated.Authorizer provider : authorizerConfiguration.getAuthorizer()) { final Authorizer instance = authorizers.get(provider.getIdentifier()); - instance.onConfigured(loadAuthorizerConfiguration(provider)); + instance.onConfigured(loadAuthorizerConfiguration(provider.getIdentifier(), provider.getProperty())); } // get the authorizer instance @@ -146,6 +177,102 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho } } + private UserGroupProvider createUserGroupProvider(final String identifier, final String userGroupProviderClassName) throws Exception { + // get the classloader for the specified user group provider + final List<Bundle> userGroupProviderBundles = ExtensionManager.getBundles(userGroupProviderClassName); + + if (userGroupProviderBundles.size() == 0) { + throw new Exception(String.format("The specified user group provider class '%s' is not known to this nifi.", userGroupProviderClassName)); + } + + if (userGroupProviderBundles.size() > 1) { + throw new Exception(String.format("Multiple bundles found for the specified user group provider class '%s', only one is allowed.", userGroupProviderClassName)); + } + + final Bundle userGroupProviderBundle = userGroupProviderBundles.get(0); + final ClassLoader userGroupProviderClassLoader = userGroupProviderBundle.getClassLoader(); + + // get the current context classloader + final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); + + final UserGroupProvider instance; + try { + // set the appropriate class loader + Thread.currentThread().setContextClassLoader(userGroupProviderClassLoader); + + // attempt to load the class + Class<?> rawUserGroupProviderClass = Class.forName(userGroupProviderClassName, true, userGroupProviderClassLoader); + Class<? extends UserGroupProvider> userGroupProviderClass = rawUserGroupProviderClass.asSubclass(UserGroupProvider.class); + + // otherwise create a new instance + Constructor constructor = userGroupProviderClass.getConstructor(); + instance = (UserGroupProvider) constructor.newInstance(); + + // method injection + performMethodInjection(instance, userGroupProviderClass); + + // field injection + performFieldInjection(instance, userGroupProviderClass); + + // call post construction lifecycle event + instance.initialize(new StandardAuthorizerInitializationContext(identifier, this, this, this)); + } finally { + if (currentClassLoader != null) { + Thread.currentThread().setContextClassLoader(currentClassLoader); + } + } + + return UserGroupProviderFactory.withNarLoader(instance); + } + + private AccessPolicyProvider createAccessPolicyProvider(final String identifier, final String accessPolicyProviderClassName) throws Exception { + // get the classloader for the specified access policy provider + final List<Bundle> accessPolicyProviderBundles = ExtensionManager.getBundles(accessPolicyProviderClassName); + + if (accessPolicyProviderBundles.size() == 0) { + throw new Exception(String.format("The specified access policy provider class '%s' is not known to this nifi.", accessPolicyProviderClassName)); + } + + if (accessPolicyProviderBundles.size() > 1) { + throw new Exception(String.format("Multiple bundles found for the specified access policy provider class '%s', only one is allowed.", accessPolicyProviderClassName)); + } + + final Bundle accessPolicyProviderBundle = accessPolicyProviderBundles.get(0); + final ClassLoader accessPolicyProviderClassLoader = accessPolicyProviderBundle.getClassLoader(); + + // get the current context classloader + final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); + + final AccessPolicyProvider instance; + try { + // set the appropriate class loader + Thread.currentThread().setContextClassLoader(accessPolicyProviderClassLoader); + + // attempt to load the class + Class<?> rawAccessPolicyProviderClass = Class.forName(accessPolicyProviderClassName, true, accessPolicyProviderClassLoader); + Class<? extends AccessPolicyProvider> accessPolicyClass = rawAccessPolicyProviderClass.asSubclass(AccessPolicyProvider.class); + + // otherwise create a new instance + Constructor constructor = accessPolicyClass.getConstructor(); + instance = (AccessPolicyProvider) constructor.newInstance(); + + // method injection + performMethodInjection(instance, accessPolicyClass); + + // field injection + performFieldInjection(instance, accessPolicyClass); + + // call post construction lifecycle event + instance.initialize(new StandardAuthorizerInitializationContext(identifier, this, this, this)); + } finally { + if (currentClassLoader != null) { + Thread.currentThread().setContextClassLoader(currentClassLoader); + } + } + + return AccessPolicyProviderFactory.withNarLoader(instance); + } + private Authorizer createAuthorizer(final String identifier, final String authorizerClassName) throws Exception { // get the classloader for the specified authorizer final List<Bundle> authorizerBundles = ExtensionManager.getBundles(authorizerClassName); @@ -184,26 +311,26 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho performFieldInjection(instance, authorizerClass); // call post construction lifecycle event - instance.initialize(new StandardAuthorizerInitializationContext(identifier, this)); + instance.initialize(new StandardAuthorizerInitializationContext(identifier, this, this, this)); } finally { if (currentClassLoader != null) { Thread.currentThread().setContextClassLoader(currentClassLoader); } } - return withNarLoader(instance); + return AuthorizerFactory.installIntegrityChecks(AuthorizerFactory.withNarLoader(instance)); } - private AuthorizerConfigurationContext loadAuthorizerConfiguration(final org.apache.nifi.authorization.generated.Authorizer authorizer) { + private AuthorizerConfigurationContext loadAuthorizerConfiguration(final String identifier, final List<Property> properties) { final Map<String, String> authorizerProperties = new HashMap<>(); - for (final Property property : authorizer.getProperty()) { + for (final Property property : properties) { authorizerProperties.put(property.getName(), property.getValue()); } - return new StandardAuthorizerConfigurationContext(authorizer.getIdentifier(), authorizerProperties); + return new StandardAuthorizerConfigurationContext(identifier, authorizerProperties); } - private void performMethodInjection(final Authorizer instance, final Class authorizerClass) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + private void performMethodInjection(final Object instance, final Class authorizerClass) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { for (final Method method : authorizerClass.getMethods()) { if (method.isAnnotationPresent(AuthorizerContext.class)) { // make the method accessible @@ -235,7 +362,7 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho } } - private void performFieldInjection(final Authorizer instance, final Class authorizerClass) throws IllegalArgumentException, IllegalAccessException { + private void performFieldInjection(final Object instance, final Class authorizerClass) throws IllegalArgumentException, IllegalAccessException { for (final Field field : authorizerClass.getDeclaredFields()) { if (field.isAnnotationPresent(AuthorizerContext.class)) { // make the method accessible @@ -291,189 +418,6 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho }; } - /** - * Decorates the base authorizer to ensure the nar context classloader is used when invoking the underlying methods. - * - * @param baseAuthorizer base authorizer - * @return authorizer - */ - public Authorizer withNarLoader(final Authorizer baseAuthorizer) { - if (baseAuthorizer instanceof AbstractPolicyBasedAuthorizer) { - AbstractPolicyBasedAuthorizer policyBasedAuthorizer = (AbstractPolicyBasedAuthorizer) baseAuthorizer; - return new AbstractPolicyBasedAuthorizer() { - @Override - public Group doAddGroup(Group group) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.addGroup(group); - } - } - - @Override - public Group getGroup(String identifier) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.getGroup(identifier); - } - } - - @Override - public Group doUpdateGroup(Group group) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.updateGroup(group); - } - } - - @Override - public Group deleteGroup(Group group) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.deleteGroup(group); - } - } - - @Override - public Set<Group> getGroups() throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.getGroups(); - } - } - - @Override - public User doAddUser(User user) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.addUser(user); - } - } - - @Override - public User getUser(String identifier) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.getUser(identifier); - } - } - - @Override - public User getUserByIdentity(String identity) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.getUserByIdentity(identity); - } - } - - @Override - public User doUpdateUser(User user) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.updateUser(user); - } - } - - @Override - public User deleteUser(User user) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.deleteUser(user); - } - } - - @Override - public Set<User> getUsers() throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.getUsers(); - } - } - - @Override - public AccessPolicy doAddAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.addAccessPolicy(accessPolicy); - } - } - - @Override - public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.getAccessPolicy(identifier); - } - } - - @Override - public AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.updateAccessPolicy(accessPolicy); - } - } - - @Override - public AccessPolicy deleteAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.deleteAccessPolicy(accessPolicy); - } - } - - @Override - public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.getAccessPolicies(); - } - } - - @Override - public UsersAndAccessPolicies getUsersAndAccessPolicies() throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return policyBasedAuthorizer.getUsersAndAccessPolicies(); - } - } - - @Override - public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - policyBasedAuthorizer.initialize(initializationContext); - } - } - - @Override - public void doOnConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - policyBasedAuthorizer.onConfigured(configurationContext); - } - } - - @Override - public void preDestruction() throws AuthorizerDestructionException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - baseAuthorizer.preDestruction(); - } - } - }; - } else { - return new Authorizer() { - @Override - public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - return baseAuthorizer.authorize(request); - } - } - - @Override - public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - baseAuthorizer.initialize(initializationContext); - } - } - - @Override - public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - baseAuthorizer.onConfigured(configurationContext); - } - } - - @Override - public void preDestruction() throws AuthorizerDestructionException { - try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { - baseAuthorizer.preDestruction(); - } - } - }; - } - } - @Override public Class getObjectType() { return Authorizer.class;
