From 1c9393032d4917bf4b9584a5066d84a85dc68a6b Mon Sep 17 00:00:00 2001 From: Matt Gilman Date: Tue, 23 Dec 2014 09:30:29 -0500 Subject: [PATCH] NIFI-65: - Adding an authorizeDownload method to the UserService. - Removing an unused/deprecated unit test. --- .../nifi/admin/service/UserService.java | 13 + .../action/AuthorizeDownloadAction.java | 54 ++++ .../service/impl/StandardUserService.java | 36 ++- .../AuthorityProviderFactoryBean.java | 13 + .../java/org/apache/nifi/user/NiFiUser.java | 10 + .../impl/NiFiAuthorizationServiceTest.java | 284 ------------------ 6 files changed, 125 insertions(+), 285 deletions(-) create mode 100644 nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AuthorizeDownloadAction.java delete mode 100644 nar-bundles/framework-bundle/framework/administration/src/test/java/org/apache/nifi/admin/service/impl/NiFiAuthorizationServiceTest.java diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/UserService.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/UserService.java index 76e54d6ee1..86256fd408 100644 --- a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/UserService.java +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/UserService.java @@ -17,8 +17,11 @@ package org.apache.nifi.admin.service; import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.nifi.authorization.Authority; +import org.apache.nifi.authorization.DownloadAuthorization; import org.apache.nifi.user.NiFiUser; import org.apache.nifi.user.NiFiUserGroup; @@ -43,6 +46,16 @@ public interface UserService { */ Boolean hasPendingUserAccount(); + /** + * Determines if the users in the dnChain are authorized to download content + * with the specified attributes. + * + * @param dnChain + * @param attributes + * @return + */ + DownloadAuthorization authorizeDownload(List dnChain, Map attributes); + /** * Updates a user group using the specified group comprised of the specified * users. Returns all the users that are currently in the specified group. diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AuthorizeDownloadAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AuthorizeDownloadAction.java new file mode 100644 index 0000000000..d1b994c366 --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AuthorizeDownloadAction.java @@ -0,0 +1,54 @@ +/* + * 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.admin.service.action; + +import java.util.List; +import java.util.Map; +import org.apache.nifi.admin.dao.DAOFactory; +import org.apache.nifi.admin.service.AccountNotFoundException; +import org.apache.nifi.admin.service.AdministrationException; +import org.apache.nifi.authorization.AuthorityProvider; +import org.apache.nifi.authorization.DownloadAuthorization; +import org.apache.nifi.authorization.exception.AuthorityAccessException; +import org.apache.nifi.authorization.exception.UnknownIdentityException; + +/** + * Attempts to obtain authorization to download the content with the specified + * attributes for the specified user. + */ +public class AuthorizeDownloadAction implements AdministrationAction { + + private final List dnChain; + private final Map attributes; + + public AuthorizeDownloadAction(List dnChain, Map attributes) { + this.dnChain = dnChain; + this.attributes = attributes; + } + + @Override + public DownloadAuthorization execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) { + try { + return authorityProvider.authorizeDownload(dnChain, attributes); + } catch (UnknownIdentityException uie) { + throw new AccountNotFoundException(uie.getMessage(), uie); + } catch (AuthorityAccessException aae) { + throw new AdministrationException(aae.getMessage(), aae); + } + } + +} diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/impl/StandardUserService.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/impl/StandardUserService.java index 63aa93bafb..5c9af4b721 100644 --- a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/impl/StandardUserService.java +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/impl/StandardUserService.java @@ -18,6 +18,8 @@ package org.apache.nifi.admin.service.impl; import java.io.IOException; import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -27,6 +29,7 @@ import org.apache.nifi.admin.service.AccountDisabledException; import org.apache.nifi.admin.service.AccountPendingException; import org.apache.nifi.admin.service.AdministrationException; import org.apache.nifi.admin.service.UserService; +import org.apache.nifi.admin.service.action.AuthorizeDownloadAction; import org.apache.nifi.admin.service.action.AuthorizeUserAction; import org.apache.nifi.admin.service.action.DeleteUserAction; import org.apache.nifi.admin.service.action.DisableUserAction; @@ -48,6 +51,7 @@ import org.apache.nifi.admin.service.transaction.Transaction; import org.apache.nifi.admin.service.transaction.TransactionBuilder; import org.apache.nifi.admin.service.transaction.TransactionException; import org.apache.nifi.authorization.Authority; +import org.apache.nifi.authorization.DownloadAuthorization; import org.apache.nifi.user.NiFiUser; import org.apache.nifi.user.NiFiUserGroup; import org.apache.nifi.util.FormatUtils; @@ -440,7 +444,7 @@ public class StandardUserService implements UserService { * modifying a user account. This method should only be invoked from within * a write lock. * - * @param id + * @param group */ @Override public void invalidateUserGroupAccount(String group) { @@ -500,6 +504,36 @@ public class StandardUserService implements UserService { } } + @Override + public DownloadAuthorization authorizeDownload(final List dnChain, final Map attributes) { + Transaction transaction = null; + + readLock.lock(); + try { + // start the transaction + transaction = transactionBuilder.start(); + + // authorize the download + AuthorizeDownloadAction authorizeDownload = new AuthorizeDownloadAction(dnChain, attributes); + DownloadAuthorization downloadAuthorization = transaction.execute(authorizeDownload); + + // commit the transaction + transaction.commit(); + + // return the authorization + return downloadAuthorization; + } catch (TransactionException | DataAccessException te) { + rollback(transaction); + throw new AdministrationException(te); + } catch (Throwable t) { + rollback(transaction); + throw t; + } finally { + closeQuietly(transaction); + readLock.unlock(); + } + } + @Override public Collection getUsers() { Transaction transaction = null; diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java index b05d32fa9c..31a01be82f 100644 --- a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java @@ -24,6 +24,7 @@ import java.lang.reflect.Method; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.XMLConstants; @@ -365,6 +366,11 @@ public class AuthorityProviderFactoryBean implements FactoryBean, ApplicationCon public void ungroup(String group) throws AuthorityAccessException { } + @Override + public DownloadAuthorization authorizeDownload(List dnChain, Map attributes) throws UnknownIdentityException, AuthorityAccessException { + return DownloadAuthorization.approved(); + } + @Override public void initialize(AuthorityProviderInitializationContext initializationContext) throws ProviderCreationException { } @@ -465,6 +471,13 @@ public class AuthorityProviderFactoryBean implements FactoryBean, ApplicationCon } } + @Override + public DownloadAuthorization authorizeDownload(List dnChain, Map attributes) throws UnknownIdentityException, AuthorityAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseProvider.authorizeDownload(dnChain, attributes); + } + } + @Override public void initialize(AuthorityProviderInitializationContext initializationContext) throws ProviderCreationException { try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/user/NiFiUser.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/user/NiFiUser.java index 984a572459..415160af4b 100644 --- a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/user/NiFiUser.java +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/user/NiFiUser.java @@ -43,6 +43,8 @@ public class NiFiUser implements Serializable { private AccountStatus status; private EnumSet authorities; + + private NiFiUser chain; /* getters / setters */ public Date getCreation() { @@ -117,6 +119,14 @@ public class NiFiUser implements Serializable { this.lastAccessed = lastAccessed; } + public NiFiUser getChain() { + return chain; + } + + public void setChain(NiFiUser chain) { + this.chain = chain; + } + public Set getAuthorities() { if (authorities == null) { authorities = EnumSet.noneOf(Authority.class); diff --git a/nar-bundles/framework-bundle/framework/administration/src/test/java/org/apache/nifi/admin/service/impl/NiFiAuthorizationServiceTest.java b/nar-bundles/framework-bundle/framework/administration/src/test/java/org/apache/nifi/admin/service/impl/NiFiAuthorizationServiceTest.java deleted file mode 100644 index 5c8b75ac73..0000000000 --- a/nar-bundles/framework-bundle/framework/administration/src/test/java/org/apache/nifi/admin/service/impl/NiFiAuthorizationServiceTest.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * 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.admin.service.impl; - -import org.junit.Ignore; - -/** - * - */ -@Ignore -public class NiFiAuthorizationServiceTest { - -// private static final String UNKNOWN_USER_IN_CACHE_DN = "unknown-user-in-cache-dn"; -// private static final String PENDING_USER_DN = "pending-user-dn"; -// private static final String DISABLED_USER_DN = "disabled-user-dn"; -// private static final String UNKNOWN_USER_IN_IDENTITY_PROVIDER_DN = "unknown-user-in-identity-provider-dn"; -// private static final String ACCESS_EXCEPTION_IN_IDENTITY_PROVIDER_DN = "access-exception-in-identity-provider-dn"; -// private static final String UNABLE_TO_UPDATE_CACHE_DN = "unable-to-update-cache-dn"; -// private static final String VERIFICATION_REQUIRED_DN = "verification-required-dn"; -// private static final String VERIFICATION_NOT_REQUIRED_DN = "verification-not-required-dn"; -// private static final String NEW_USER_DN = "new-user-dn"; -// -// private UserService userService; -// private AuthorityProvider authorityProvider; -// private UserDAO userDAO; -// -// @Before -// public void setup() throws Exception { -// // mock the web security properties -// NiFiProperties properties = Mockito.mock(NiFiProperties.class); -// Mockito.when(properties.getSupportNewAccountRequests()).thenReturn(Boolean.TRUE); -// Mockito.when(properties.getUserCredentialCacheDurationSeconds()).thenReturn(60); -// -// // mock the authority provider -// -// // mock the admin service -// userDAO = Mockito.mock(UserDAO.class); -// Mockito.doAnswer(new Answer() { -// -// @Override -// public Object answer(InvocationOnMock invocation) throws Throwable { -// Object[] args = invocation.getArguments(); -// String dn = (String) args[0]; -// -// NiFiUser user = null; -// switch (dn) { -// case PENDING_USER_DN: -// user = new NiFiUser(); -// user.setDn(dn); -// user.setStatus(AccountStatus.PENDING); -// break; -// case DISABLED_USER_DN: -// user = new NiFiUser(); -// user.setDn(dn); -// user.setStatus(AccountStatus.DISABLED); -// break; -// case UNKNOWN_USER_IN_IDENTITY_PROVIDER_DN: -// case UNABLE_TO_UPDATE_CACHE_DN: -// case ACCESS_EXCEPTION_IN_IDENTITY_PROVIDER_DN: -// user = new NiFiUser(); -// user.setDn(dn); -// user.setStatus(AccountStatus.ACTIVE); -// break; -// case VERIFICATION_REQUIRED_DN: { -// Calendar calendar = Calendar.getInstance(); -// calendar.add(Calendar.SECOND, -65); -// user = new NiFiUser(); -// user.setDn(dn); -// user.setStatus(AccountStatus.ACTIVE); -// user.setLastVerified(calendar.getTime()); -// user.getAuthorities().addAll(EnumSet.of(Authority.ROLE_ADMIN, Authority.ROLE_DFM)); -// break; -// } -// case VERIFICATION_NOT_REQUIRED_DN: { -// Calendar calendar = Calendar.getInstance(); -// calendar.add(Calendar.SECOND, -5); -// user = new NiFiUser(); -// user.setDn(dn); -// user.setStatus(AccountStatus.ACTIVE); -// user.setLastVerified(calendar.getTime()); -// user.getAuthorities().addAll(EnumSet.of(Authority.ROLE_ADMIN, Authority.ROLE_DFM)); -// break; -// } -// } -// return user; -// } -// }).when(userDAO).getUser(Mockito.anyString()); -// Mockito.doAnswer(new Answer() { -// -// @Override -// public Object answer(InvocationOnMock invocation) throws Throwable { -// Object[] args = invocation.getArguments(); -// NiFiUser user = (NiFiUser) args[0]; -// -// if (UNABLE_TO_UPDATE_CACHE_DN.equals(user.getDn())) { -// throw new AdministrationException(); -// } -// return user; -// } -// }).when(userDAO).updateUser(Mockito.any(NiFiUser.class)); -// Mockito.doNothing().when(userDAO).createUser(Mockito.any(NiFiUser.class)); -// -// // mock the authority provider -// authorityProvider = Mockito.mock(AuthorityProvider.class); -// Mockito.doAnswer(new Answer() { -// -// @Override -// public Object answer(InvocationOnMock invocation) throws Throwable { -// Object[] args = invocation.getArguments(); -// String dn = (String) args[0]; -// -// boolean hasDn = false; -// if (VERIFICATION_REQUIRED_DN.equals(dn) || NEW_USER_DN.equals(dn)) { -// hasDn = true; -// } -// return hasDn; -// } -// }).when(authorityProvider).doesDnExist(Mockito.anyString()); -// Mockito.doAnswer(new Answer() { -// -// @Override -// public Object answer(InvocationOnMock invocation) throws Throwable { -// Object[] args = invocation.getArguments(); -// String dn = (String) args[0]; -// -// Set authorities = null; -// switch (dn) { -// case VERIFICATION_REQUIRED_DN: -// case NEW_USER_DN: -// authorities = new HashSet<>(); -// authorities.add("ROLE_MONITOR"); -// break; -// case DISABLED_USER_DN: -// throw new UnknownIdentityException("Unable to find user"); -// } -// return authorities; -// } -// }).when(authorityProvider).getAuthorities(Mockito.anyString()); -// -// // create an instance of the authorization service -// userService = new UserServiceImpl(); -// ((UserServiceImpl) userService).setAuthorityProvider(authorityProvider); -// ((UserServiceImpl) userService).set(authorityProvider); -// -//// authorizationService.setIdentityProvider(identityProvider); -//// authorizationService.setAuthorityProvider(authorityProvider); -//// authorizationService.setProperties(properties); -// } -// -// /** -// * Ensures the authorization service correctly handles users who are -// * unknown. -// * -// * @throws Exception -// */ -// @Test(expected = org.springframework.security.core.userdetails.UsernameNotFoundException.class) -// public void testUnknownUserInCache() throws Exception { -// authorizationService.loadUserByUsername(WebUtils.formatProxyDn(UNKNOWN_USER_IN_CACHE_DN)); -// } -// -// /** -// * Ensures the authorization service correctly handles users whose accounts -// * are PENDING. -// * -// * @throws Exception -// */ -// @Test(expected = nifi.admin.service.AccountPendingException.class) -// public void testPendingUser() throws Exception { -// authorizationService.loadUserByUsername(WebUtils.formatProxyDn(PENDING_USER_DN)); -// } -// -// /** -// * Ensures the authorization service correctly handles users whose accounts -// * are DISABLED. -// * -// * @throws Exception -// */ -// @Test(expected = org.springframework.security.authentication.DisabledException.class) -// public void testDisabledUser() throws Exception { -// authorizationService.loadUserByUsername(WebUtils.formatProxyDn(DISABLED_USER_DN)); -// } -// -// /** -// * Ensures the authorization service correctly handles users whose are in -// * the cache but have been removed from the identity provider. -// * -// * @throws Exception -// */ -// @Test(expected = org.springframework.security.authentication.DisabledException.class) -// public void testUnknownUserInIdentityProvider() throws Exception { -// authorizationService.loadUserByUsername(WebUtils.formatProxyDn(UNKNOWN_USER_IN_IDENTITY_PROVIDER_DN)); -// } -// -// /** -// * Ensures the authorization service correctly handles cases when the cache -// * is unable to be updated. -// * -// * @throws Exception -// */ -// @Test(expected = org.springframework.security.authentication.AuthenticationServiceException.class) -// public void testUnableToUpdateCache() throws Exception { -// authorizationService.loadUserByUsername(WebUtils.formatProxyDn(UNABLE_TO_UPDATE_CACHE_DN)); -// } -// -// /** -// * Ensures the authorization service correctly handles cases when the -// * identity provider has an access exception. -// * -// * @throws Exception -// */ -// @Test(expected = org.springframework.security.authentication.AuthenticationServiceException.class) -// public void testUnableToAccessIdentity() throws Exception { -// authorizationService.loadUserByUsername(WebUtils.formatProxyDn(ACCESS_EXCEPTION_IN_IDENTITY_PROVIDER_DN)); -// } -// -// /** -// * Ensures that user authorities are properly loaded from the authority -// * provider. -// * -// * @throws Exception -// */ -// @Test -// public void testVerificationRequiredUser() throws Exception { -// NiFiUserDetails userDetails = (NiFiUserDetails) authorizationService.loadUserByUsername(WebUtils.formatProxyDn(VERIFICATION_REQUIRED_DN)); -// NiFiUser user = userDetails.getNiFiUser(); -// Mockito.verify(authorityProvider).getAuthorities(VERIFICATION_REQUIRED_DN); -// -// // ensure the user details -// Assert.assertEquals(VERIFICATION_REQUIRED_DN, user.getDn()); -// Assert.assertEquals(1, user.getAuthorities().size()); -// Assert.assertTrue(user.getAuthorities().contains(Authority.ROLE_MONITOR)); -// } -// -// /** -// * Ensures that user authorities are not loaded when the cache is still -// * valid. -// * -// * @throws Exception -// */ -// @Test -// public void testVerificationNotRequiredUser() throws Exception { -// NiFiUserDetails userDetails = (NiFiUserDetails) authorizationService.loadUserByUsername(WebUtils.formatProxyDn(VERIFICATION_NOT_REQUIRED_DN)); -// NiFiUser user = userDetails.getNiFiUser(); -// Mockito.verify(authorityProvider, Mockito.never()).getAuthorities(VERIFICATION_NOT_REQUIRED_DN); -// -// // ensure the user details -// Assert.assertEquals(VERIFICATION_NOT_REQUIRED_DN, user.getDn()); -// Assert.assertEquals(2, user.getAuthorities().size()); -// Assert.assertTrue(user.getAuthorities().contains(Authority.ROLE_ADMIN)); -// Assert.assertTrue(user.getAuthorities().contains(Authority.ROLE_DFM)); -// } -// -// /** -// * Ensures that new users are automatically created when the authority -// * provider has their authorities. -// * -// * @throws Exception -// */ -// @Test -// public void testNewUser() throws Exception { -// NiFiUserDetails userDetails = (NiFiUserDetails) authorizationService.loadUserByUsername(WebUtils.formatProxyDn(NEW_USER_DN)); -// NiFiUser user = userDetails.getNiFiUser(); -// Mockito.verify(authorityProvider).getAuthorities(NEW_USER_DN); -// -// // ensure the user details -// Assert.assertEquals(NEW_USER_DN, user.getDn()); -// Assert.assertEquals(1, user.getAuthorities().size()); -// Assert.assertTrue(user.getAuthorities().contains(Authority.ROLE_MONITOR)); -// } -}