You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by jo...@apache.org on 2014/12/08 21:29:51 UTC

[28/51] [partial] incubator-nifi git commit: Initial code contribution

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/UserService.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
new file mode 100644
index 0000000..76e54d6
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/UserService.java
@@ -0,0 +1,148 @@
+/*
+ * 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;
+
+import java.util.Collection;
+import java.util.Set;
+import org.apache.nifi.authorization.Authority;
+import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.user.NiFiUserGroup;
+
+/**
+ * Manages NiFi user accounts.
+ */
+public interface UserService {
+
+    /**
+     * Creates a new user account using the specified dn and justification.
+     *
+     * @param dn
+     * @param justification
+     * @return
+     */
+    NiFiUser createPendingUserAccount(String dn, String justification);
+
+    /**
+     * Determines if there are any PENDING user accounts present.
+     *
+     * @return
+     */
+    Boolean hasPendingUserAccount();
+
+    /**
+     * Updates a user group using the specified group comprised of the specified
+     * users. Returns all the users that are currently in the specified group.
+     *
+     * @param group
+     * @param userIds
+     * @param authorities
+     * @return
+     */
+    NiFiUserGroup updateGroup(String group, Set<String> userIds, Set<Authority> authorities);
+
+    /**
+     * Authorizes the user specified.
+     *
+     * @param dn
+     * @return
+     */
+    NiFiUser checkAuthorization(String dn);
+
+    /**
+     * Deletes the user with the specified id.
+     *
+     * @param id
+     */
+    void deleteUser(String id);
+
+    /**
+     * Disables the specified users account.
+     *
+     * @param id
+     * @return
+     */
+    NiFiUser disable(String id);
+
+    /**
+     * Disables the specified user group.
+     *
+     * @param group
+     * @return
+     */
+    NiFiUserGroup disableGroup(String group);
+
+    /**
+     * Updates the specified user with the specified authorities.
+     *
+     * @param id
+     * @param authorities
+     * @return
+     */
+    NiFiUser update(String id, Set<Authority> authorities);
+
+    /**
+     * Invalidates the specified user account.
+     *
+     * @param id
+     */
+    void invalidateUserAccount(String id);
+
+    /**
+     * Invalidates the user accounts associated with the specified user group.
+     *
+     * @param group
+     */
+    void invalidateUserGroupAccount(String group);
+
+    /**
+     * Ungroups the specified group.
+     *
+     * @param group
+     */
+    void ungroup(String group);
+
+    /**
+     * Ungroups the specified user.
+     *
+     * @param id
+     */
+    void ungroupUser(String id);
+
+    /**
+     * Returns a collection of all NiFiUsers.
+     *
+     * @return
+     */
+    Collection<NiFiUser> getUsers();
+
+    /**
+     * Finds the specified user by id.
+     *
+     * @param id
+     * @return
+     */
+    NiFiUser getUserById(String id);
+
+    /**
+     * Finds the specified user by dn.
+     *
+     * @param dn
+     * @return
+     * @throws AdministrationException
+     */
+    NiFiUser getUserByDn(String dn);
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AbstractUserAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AbstractUserAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AbstractUserAction.java
new file mode 100644
index 0000000..41c97fe
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AbstractUserAction.java
@@ -0,0 +1,97 @@
+/*
+ * 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.Date;
+import java.util.EnumSet;
+import java.util.Set;
+import org.apache.nifi.authorization.Authority;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.user.AccountStatus;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ *
+ * @param <T>
+ */
+public abstract class AbstractUserAction<T> implements AdministrationAction<T> {
+
+    /**
+     * Determines the authorities that need to be added to the specified user.
+     *
+     * @param user
+     * @param authorities
+     * @return
+     */
+    protected Set<Authority> determineAuthoritiesToAdd(NiFiUser user, Set<Authority> authorities) {
+        // not using copyOf since authorities may be empty and copyOf can throw an IllegalArgumentException when empty
+        Set<Authority> authoritiesToAdd = EnumSet.noneOf(Authority.class);
+        authoritiesToAdd.addAll(authorities);
+
+        // identify the authorities that need to be inserted
+        authoritiesToAdd.removeAll(user.getAuthorities());
+
+        // return the desired authorities
+        return authoritiesToAdd;
+    }
+
+    /**
+     * Determines the authorities that need to be removed from the specified
+     * user.
+     *
+     * @param user
+     * @param authorities
+     * @return
+     */
+    protected Set<Authority> determineAuthoritiesToRemove(NiFiUser user, Set<Authority> authorities) {
+        Set<Authority> authoritiesToRemove = EnumSet.copyOf(user.getAuthorities());
+
+        // identify the authorities that need to be removed
+        authoritiesToRemove.removeAll(authorities);
+
+        // return the desired authorities
+        return authoritiesToRemove;
+    }
+
+    /**
+     * Verifies the specified users account. Includes obtaining the authorities
+     * and group according to the specified authority provider.
+     *
+     * @param authorityProvider
+     * @param user
+     */
+    protected void verifyAccount(AuthorityProvider authorityProvider, NiFiUser user) {
+        // load the roles for the user
+        Set<Authority> authorities = authorityProvider.getAuthorities(user.getDn());
+
+        // update the user's authorities
+        user.getAuthorities().clear();
+        user.getAuthorities().addAll(authorities);
+
+        // get the user group
+        user.setUserGroup(authorityProvider.getGroupForUser(user.getDn()));
+
+        // update the users status in case they were previously pending or disabled
+        user.setStatus(AccountStatus.ACTIVE);
+
+        // update the users last verified time - this timestampt shouldn't be record
+        // until the both the user's authorities and group have been synced
+        Date now = new Date();
+        user.setLastVerified(now);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AddActionsAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AddActionsAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AddActionsAction.java
new file mode 100644
index 0000000..5a2159f
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AddActionsAction.java
@@ -0,0 +1,48 @@
+/*
+ * 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.Collection;
+import org.apache.nifi.action.Action;
+import org.apache.nifi.admin.dao.ActionDAO;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.authorization.AuthorityProvider;
+
+/**
+ * Adds the specified actions.
+ */
+public class AddActionsAction implements AdministrationAction<Void> {
+
+    private final Collection<Action> actions;
+
+    public AddActionsAction(Collection<Action> actions) {
+        this.actions = actions;
+    }
+
+    @Override
+    public Void execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) {
+        ActionDAO actionDao = daoFactory.getActionDAO();
+
+        // add each action
+        for (Action action : actions) {
+            actionDao.createAction(action);
+        }
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AdministrationAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AdministrationAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AdministrationAction.java
new file mode 100644
index 0000000..5818ebe
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AdministrationAction.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.authorization.AuthorityProvider;
+
+/**
+ * Defines the administration action. Actions are provided a DAO factory and
+ * authority provider to perform a require action.
+ *
+ * @param <T>
+ */
+public interface AdministrationAction<T> {
+
+    /**
+     * Performs an action using the specified DAOFactory and AuthorityProvider.
+     *
+     * @param daoFactory
+     * @param authorityProvider
+     * @return
+     */
+    T execute(DAOFactory daoFactory, AuthorityProvider authorityProvider);
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AuthorizeUserAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AuthorizeUserAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AuthorizeUserAction.java
new file mode 100644
index 0000000..ea6973d
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/AuthorizeUserAction.java
@@ -0,0 +1,175 @@
+/*
+ * 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.Calendar;
+import java.util.Date;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.admin.service.AccountDisabledException;
+import org.apache.nifi.admin.service.AccountNotFoundException;
+import org.apache.nifi.admin.service.AccountPendingException;
+import org.apache.nifi.admin.service.AdministrationException;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.authorization.exception.AuthorityAccessException;
+import org.apache.nifi.authorization.exception.UnknownIdentityException;
+import org.apache.nifi.security.util.CertificateUtils;
+import org.apache.nifi.user.AccountStatus;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ *
+ */
+public class AuthorizeUserAction extends AbstractUserAction<NiFiUser> {
+
+    private final String dn;
+    private final int cacheDurationSeconds;
+
+    public AuthorizeUserAction(String dn, int cacheDurationSeconds) {
+        this.dn = dn;
+        this.cacheDurationSeconds = cacheDurationSeconds;
+    }
+
+    @Override
+    public NiFiUser execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        UserDAO userDao = daoFactory.getUserDAO();
+
+        // get the user
+        NiFiUser user = userDao.findUserByDn(dn);
+
+        // verify the user was found
+        if (user == null) {
+            // determine whether this users exists
+            boolean doesDnExist = false;
+            try {
+                doesDnExist = authorityProvider.doesDnExist(dn);
+            } catch (AuthorityAccessException aae) {
+                throw new AdministrationException(String.format("Unable to access authority details: %s", aae.getMessage()), aae);
+            }
+
+            // if the authority provider has the details for this user, create the account
+            if (doesDnExist) {
+                // create the user
+                user = new NiFiUser();
+                user.setDn(dn);
+                user.setUserName(CertificateUtils.extractUsername(dn));
+                user.setJustification("User details specified by authority provider.");
+
+                try {
+                    // verify the users account
+                    verifyAccount(authorityProvider, user);
+
+                    // get the date used for verification
+                    Date now = user.getLastVerified();
+
+                    // update the last accessed field
+                    user.setLastAccessed(now);
+                    user.setCreation(now);
+
+                    // create the new user account
+                    CreateUserAction createUser = new CreateUserAction(user);
+                    createUser.execute(daoFactory, authorityProvider);
+                } catch (UnknownIdentityException uie) {
+                    // strange since the provider just reported this dn existed but handleing anyways...
+                    throw new AccountNotFoundException(String.format("Unable to verify access for %s.", dn));
+                } catch (AuthorityAccessException aae) {
+                    throw new AdministrationException(String.format("Unable to access authority details: %s", aae.getMessage()), aae);
+                }
+            } else {
+                throw new AccountNotFoundException(String.format("Unable to verify access for %s.", dn));
+            }
+        } else {
+            Throwable providerError = null;
+
+            // verify the users account if necessary
+            if (isAccountVerificationRequired(user)) {
+                try {
+                    // verify the users account
+                    verifyAccount(authorityProvider, user);
+
+                    // update the last accessed field
+                    user.setLastAccessed(user.getLastVerified());
+                } catch (UnknownIdentityException uie) {
+                    // check the account status before attempting to update the account - depending on the account
+                    // status we might not need to update the account
+                    checkAccountStatus(user);
+
+                    // the user is currently active and they were not found in the providers - disable the account...
+                    user.setStatus(AccountStatus.DISABLED);
+
+                    // record the exception
+                    providerError = uie;
+                } catch (AuthorityAccessException aae) {
+                    throw new AdministrationException(String.format("Unable to access authority details: %s", aae.getMessage()), aae);
+                }
+            } else {
+                // verfiy the users account status before allowing access.
+                checkAccountStatus(user);
+
+                // update the users last accessed time
+                user.setLastAccessed(new Date());
+            }
+
+            // persist the user's updates
+            UpdateUserCacheAction updateUser = new UpdateUserCacheAction(user);
+            updateUser.execute(daoFactory, authorityProvider);
+
+            // persist the user's authorities
+            UpdateUserAuthoritiesCacheAction updateUserAuthorities = new UpdateUserAuthoritiesCacheAction(user);
+            updateUserAuthorities.execute(daoFactory, authorityProvider);
+
+            if (providerError != null) {
+                throw new AccountDisabledException(String.format("User credentials for %s were not found. This account has been disabled.", user.getDn()), providerError);
+            }
+        }
+
+        return user;
+    }
+
+    /**
+     * Determines if account verification is required.
+     *
+     * @return
+     */
+    private boolean isAccountVerificationRequired(NiFiUser user) {
+        // accounts that have never been verified obviously needs to be re-verified
+        if (user.getLastVerified() == null) {
+            return true;
+        }
+
+        // create a calendar and substract the threshold - anything
+        // before this time will need to be re-verified
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.SECOND, -cacheDurationSeconds);
+
+        return user.getLastVerified().before(calendar.getTime());
+    }
+
+    /**
+     * Checks the account status of the specified user.
+     *
+     * @param user
+     */
+    private void checkAccountStatus(NiFiUser user) {
+        if (AccountStatus.DISABLED.equals(user.getStatus())) {
+            throw new AccountDisabledException(String.format("Account for %s is disabled.", user.getDn()));
+        } else if (AccountStatus.PENDING.equals(user.getStatus())) {
+            throw new AccountPendingException(String.format("Account for %s is pending.", user.getDn()));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/CreateUserAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/CreateUserAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/CreateUserAction.java
new file mode 100644
index 0000000..3833abb
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/CreateUserAction.java
@@ -0,0 +1,53 @@
+/*
+ * 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.Set;
+import org.apache.nifi.admin.dao.AuthorityDAO;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.authorization.Authority;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ * Action for creating a NiFiUser account.
+ */
+public class CreateUserAction extends AbstractUserAction<Void> {
+
+    private final NiFiUser user;
+
+    public CreateUserAction(NiFiUser user) {
+        this.user = user;
+    }
+
+    @Override
+    public Void execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        UserDAO userDao = daoFactory.getUserDAO();
+        AuthorityDAO authorityDao = daoFactory.getAuthorityDAO();
+
+        // create the user entry
+        userDao.createUser(user);
+
+        // create the authorities
+        Set<Authority> authorities = user.getAuthorities();
+        authorityDao.createAuthorities(authorities, user.getId());
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DeleteUserAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DeleteUserAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DeleteUserAction.java
new file mode 100644
index 0000000..f93e97e
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DeleteUserAction.java
@@ -0,0 +1,68 @@
+/*
+ * 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 org.apache.nifi.admin.dao.AuthorityDAO;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.admin.service.AccountNotFoundException;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.user.AccountStatus;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ *
+ */
+public class DeleteUserAction implements AdministrationAction<Void> {
+
+    private final String userId;
+
+    /**
+     * Creates a new transactions for deleting the specified user.
+     *
+     * @param userId
+     */
+    public DeleteUserAction(String userId) {
+        this.userId = userId;
+    }
+
+    @Override
+    public Void execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        final AuthorityDAO authorityDAO = daoFactory.getAuthorityDAO();
+        final UserDAO userDAO = daoFactory.getUserDAO();
+
+        // find the user and ensure they are currently revoked
+        final NiFiUser user = userDAO.findUserById(userId);
+
+        // ensure the user was found
+        if (user == null) {
+            throw new AccountNotFoundException(String.format("Unable to find account with ID %s.", userId));
+        }
+
+        // ensure the user is in the appropriate state
+        if (AccountStatus.ACTIVE.equals(user.getStatus())) {
+            throw new IllegalStateException(String.format("An active user cannot be removed. Revoke user access before attempting to remove."));
+        }
+
+        // remove the user and their authorities
+        authorityDAO.deleteAuthorities(userId);
+        userDAO.deleteUser(userId);
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DisableUserAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DisableUserAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DisableUserAction.java
new file mode 100644
index 0000000..c31f107
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DisableUserAction.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.admin.service.action;
+
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+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.exception.AuthorityAccessException;
+import org.apache.nifi.authorization.exception.UnknownIdentityException;
+import org.apache.nifi.user.AccountStatus;
+import org.apache.nifi.user.NiFiUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class DisableUserAction implements AdministrationAction<NiFiUser> {
+
+    private static final Logger logger = LoggerFactory.getLogger(DisableUserAction.class);
+
+    private final String id;
+
+    public DisableUserAction(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public NiFiUser execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        UserDAO userDao = daoFactory.getUserDAO();
+
+        // get the user
+        NiFiUser user = userDao.findUserById(id);
+
+        // ensure the user exists
+        if (user == null) {
+            throw new AccountNotFoundException(String.format("Unable to find account with ID %s.", id));
+        }
+
+        // update the account
+        user.setStatus(AccountStatus.DISABLED);
+        user.setUserGroup(null);
+
+        // update the user locally
+        userDao.updateUser(user);
+
+        try {
+            // revoke the user in the authority provider
+            authorityProvider.revokeUser(user.getDn());
+        } catch (UnknownIdentityException uie) {
+            // user identity is not known
+            logger.info(String.format("User %s has already been removed from the authority provider.", user.getDn()));
+        } catch (AuthorityAccessException aae) {
+            throw new AdministrationException(String.format("Unable to revoke user '%s': %s", user.getDn(), aae.getMessage()), aae);
+        }
+
+        return user;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DisableUserGroupAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DisableUserGroupAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DisableUserGroupAction.java
new file mode 100644
index 0000000..385fce6
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/DisableUserGroupAction.java
@@ -0,0 +1,69 @@
+/*
+ * 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 org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.admin.service.AdministrationException;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.authorization.exception.AuthorityAccessException;
+import org.apache.nifi.authorization.exception.UnknownIdentityException;
+import org.apache.nifi.user.AccountStatus;
+import org.apache.nifi.user.NiFiUserGroup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class DisableUserGroupAction implements AdministrationAction<NiFiUserGroup> {
+
+    private static final Logger logger = LoggerFactory.getLogger(DisableUserGroupAction.class);
+
+    private final String group;
+
+    public DisableUserGroupAction(final String group) {
+        this.group = group;
+    }
+
+    @Override
+    public NiFiUserGroup execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        final NiFiUserGroup userGroup = new NiFiUserGroup();
+
+        final UserDAO userDao = daoFactory.getUserDAO();
+
+        // update the user group locally
+        userDao.updateGroupStatus(group, AccountStatus.DISABLED);
+
+        // populate the group details
+        userGroup.setGroup(group);
+        userGroup.setUsers(userDao.findUsersForGroup(group));
+
+        try {
+            // revoke the user in the authority provider
+            authorityProvider.revokeGroup(group);
+        } catch (UnknownIdentityException uie) {
+            // user identity is not known
+            logger.info(String.format("User group %s has already been removed from the authority provider.", group));
+        } catch (AuthorityAccessException aae) {
+            throw new AdministrationException(String.format("Unable to revoke user group '%s': %s", group, aae.getMessage()), aae);
+        }
+
+        return userGroup;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/FindUserByDnAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/FindUserByDnAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/FindUserByDnAction.java
new file mode 100644
index 0000000..8e5b574
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/FindUserByDnAction.java
@@ -0,0 +1,49 @@
+/*
+ * 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 org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ *
+ */
+public class FindUserByDnAction implements AdministrationAction<NiFiUser> {
+
+    private final String dn;
+
+    /**
+     * Creates a new transactions for getting a user with the specified DN.
+     *
+     * @param dn The DN of the user to obtain
+     */
+    public FindUserByDnAction(String dn) {
+        this.dn = dn;
+    }
+
+    @Override
+    public NiFiUser execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        // get a UserDAO
+        UserDAO userDAO = daoFactory.getUserDAO();
+
+        // return the desired user
+        return userDAO.findUserByDn(dn);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/FindUserByIdAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/FindUserByIdAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/FindUserByIdAction.java
new file mode 100644
index 0000000..3062a2e
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/FindUserByIdAction.java
@@ -0,0 +1,49 @@
+/*
+ * 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 org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ *
+ */
+public class FindUserByIdAction implements AdministrationAction<NiFiUser> {
+
+    private final String id;
+
+    /**
+     * Creates a new transactions for getting a user with the specified id.
+     *
+     * @param id
+     */
+    public FindUserByIdAction(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public NiFiUser execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        // get a UserDAO
+        UserDAO userDAO = daoFactory.getUserDAO();
+
+        // return the desired user
+        return userDAO.findUserById(id);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetActionAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetActionAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetActionAction.java
new file mode 100644
index 0000000..1dc5588
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetActionAction.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.admin.service.action;
+
+import org.apache.nifi.action.Action;
+import org.apache.nifi.admin.dao.ActionDAO;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.authorization.AuthorityProvider;
+
+/**
+ * Gets the action with the specified id.
+ */
+public class GetActionAction implements AdministrationAction<Action> {
+
+    private final Integer id;
+
+    public GetActionAction(Integer id) {
+        this.id = id;
+    }
+
+    @Override
+    public Action execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) {
+        ActionDAO actionDao = daoFactory.getActionDAO();
+        return actionDao.getAction(id);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetActionsAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetActionsAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetActionsAction.java
new file mode 100644
index 0000000..3b82d79
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetActionsAction.java
@@ -0,0 +1,48 @@
+/*
+ * 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.Date;
+import org.apache.nifi.admin.dao.ActionDAO;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.history.History;
+import org.apache.nifi.history.HistoryQuery;
+
+/**
+ * Get all actions that match the specified query.
+ */
+public class GetActionsAction implements AdministrationAction<History> {
+
+    private final HistoryQuery query;
+
+    public GetActionsAction(HistoryQuery query) {
+        this.query = query;
+    }
+
+    @Override
+    public History execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) {
+        ActionDAO actionDao = daoFactory.getActionDAO();
+
+        // find all matching history
+        History history = actionDao.findActions(query);
+        history.setLastRefreshed(new Date());
+
+        return history;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetPreviousValues.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetPreviousValues.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetPreviousValues.java
new file mode 100644
index 0000000..5ce663e
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetPreviousValues.java
@@ -0,0 +1,43 @@
+/*
+ * 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.ActionDAO;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.history.PreviousValue;
+
+/**
+ * Gets the action with the specified id.
+ */
+public class GetPreviousValues implements AdministrationAction<Map<String, List<PreviousValue>>> {
+
+    private final String processorId;
+
+    public GetPreviousValues(String processorId) {
+        this.processorId = processorId;
+    }
+
+    @Override
+    public Map<String, List<PreviousValue>> execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) {
+        ActionDAO actionDao = daoFactory.getActionDAO();
+        return actionDao.getPreviousValues(processorId);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetUserGroupAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetUserGroupAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetUserGroupAction.java
new file mode 100644
index 0000000..5377c46
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetUserGroupAction.java
@@ -0,0 +1,50 @@
+/*
+ * 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 org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.user.NiFiUserGroup;
+
+/**
+ *
+ */
+public class GetUserGroupAction implements AdministrationAction<NiFiUserGroup> {
+
+    private final String group;
+
+    public GetUserGroupAction(String group) {
+        this.group = group;
+    }
+
+    @Override
+    public NiFiUserGroup execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        final UserDAO userDAO = daoFactory.getUserDAO();
+        final NiFiUserGroup userGroup = new NiFiUserGroup();
+
+        // set the group
+        userGroup.setGroup(group);
+
+        // get the users in this group
+        userGroup.setUsers(userDAO.findUsersForGroup(group));
+
+        // return the group
+        return userGroup;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetUsersAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetUsersAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetUsersAction.java
new file mode 100644
index 0000000..42d180e
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/GetUsersAction.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.admin.service.action;
+
+import java.util.Collection;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ *
+ */
+public class GetUsersAction implements AdministrationAction<Collection<NiFiUser>> {
+
+    @Override
+    public Collection<NiFiUser> execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        // get a UserDAO
+        UserDAO userDAO = daoFactory.getUserDAO();
+
+        // return the desired user
+        return userDAO.findUsers();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/HasPendingUserAccounts.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/HasPendingUserAccounts.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/HasPendingUserAccounts.java
new file mode 100644
index 0000000..3325642
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/HasPendingUserAccounts.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.authorization.AuthorityProvider;
+
+/**
+ * Action for creating a NiFiUser account.
+ */
+public class HasPendingUserAccounts extends AbstractUserAction<Boolean> {
+
+    @Override
+    public Boolean execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        UserDAO userDao = daoFactory.getUserDAO();
+        return userDao.hasPendingUserAccounts();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/InvalidateUserAccountAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/InvalidateUserAccountAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/InvalidateUserAccountAction.java
new file mode 100644
index 0000000..14596b2
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/InvalidateUserAccountAction.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.admin.service.action;
+
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.admin.service.AccountNotFoundException;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ * Invalidates a user account.
+ */
+public class InvalidateUserAccountAction implements AdministrationAction<Void> {
+
+    private final String id;
+
+    public InvalidateUserAccountAction(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public Void execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        UserDAO userDao = daoFactory.getUserDAO();
+
+        // get the current user details
+        NiFiUser user = userDao.findUserById(id);
+
+        // ensure the user exists
+        if (user == null) {
+            throw new AccountNotFoundException(String.format("Unable to find account with ID %s.", id));
+        }
+
+        // invalidate the user account
+        user.setLastVerified(null);
+
+        // create the user entry
+        userDao.updateUser(user);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/InvalidateUserGroupAccountsAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/InvalidateUserGroupAccountsAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/InvalidateUserGroupAccountsAction.java
new file mode 100644
index 0000000..0cb7e14
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/InvalidateUserGroupAccountsAction.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.admin.service.action;
+
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.authorization.AuthorityProvider;
+
+/**
+ * Invalidates a user account.
+ */
+public class InvalidateUserGroupAccountsAction implements AdministrationAction<Void> {
+
+    private final String group;
+
+    public InvalidateUserGroupAccountsAction(String group) {
+        this.group = group;
+    }
+
+    @Override
+    public Void execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        UserDAO userDao = daoFactory.getUserDAO();
+
+        // create the user entry
+        userDao.updateGroupVerification(group, null);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/PurgeActionsAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/PurgeActionsAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/PurgeActionsAction.java
new file mode 100644
index 0000000..b5a2883
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/PurgeActionsAction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.Date;
+import org.apache.nifi.action.Action;
+import org.apache.nifi.admin.dao.ActionDAO;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.authorization.AuthorityProvider;
+
+/**
+ * Purges actions up to a specified end date.
+ */
+public class PurgeActionsAction implements AdministrationAction<Void> {
+
+    private final Date end;
+    private final Action purgeAction;
+
+    public PurgeActionsAction(Date end, Action purgeAction) {
+        this.end = end;
+        this.purgeAction = purgeAction;
+    }
+
+    @Override
+    public Void execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) {
+        ActionDAO actionDao = daoFactory.getActionDAO();
+
+        // remove the corresponding actions
+        actionDao.deleteActions(end);
+
+        // create a purge action
+        actionDao.createAction(purgeAction);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/RequestUserAccountAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/RequestUserAccountAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/RequestUserAccountAction.java
new file mode 100644
index 0000000..3dce6d9
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/RequestUserAccountAction.java
@@ -0,0 +1,67 @@
+/*
+ * 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.Date;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.security.util.CertificateUtils;
+import org.apache.nifi.user.AccountStatus;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ *
+ */
+public class RequestUserAccountAction implements AdministrationAction<NiFiUser> {
+
+    private final String dn;
+    private final String justification;
+
+    public RequestUserAccountAction(String dn, String justification) {
+        this.dn = dn;
+        this.justification = justification;
+    }
+
+    @Override
+    public NiFiUser execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        UserDAO userDao = daoFactory.getUserDAO();
+
+        // determine if this user already exists
+        NiFiUser user = userDao.findUserByDn(dn);
+        if (user != null) {
+            throw new IllegalArgumentException(String.format("User account for %s already exists.", dn));
+        }
+
+        // create the user
+        user = new NiFiUser();
+        user.setDn(dn);
+        user.setUserName(CertificateUtils.extractUsername(dn));
+        user.setJustification(justification);
+        user.setStatus(AccountStatus.PENDING);
+
+        // update user timestamps
+        Date now = new Date();
+        user.setCreation(now);
+
+        // create the new user account
+        userDao.createUser(user);
+
+        return user;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/SeedUserAccountsAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/SeedUserAccountsAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/SeedUserAccountsAction.java
new file mode 100644
index 0000000..72d68db
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/SeedUserAccountsAction.java
@@ -0,0 +1,164 @@
+/*
+ * 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.HashSet;
+import java.util.Set;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.admin.service.AdministrationException;
+import org.apache.nifi.authorization.Authority;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.authorization.exception.AuthorityAccessException;
+import org.apache.nifi.authorization.exception.UnknownIdentityException;
+import org.apache.nifi.security.util.CertificateUtils;
+import org.apache.nifi.user.AccountStatus;
+import org.apache.nifi.user.NiFiUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Seeds the user accounts. This action is performed at start up because it
+ * takes the users specified in the authority provider and makes them available
+ * to be seen in the UI. This happens because the UI loads the users from the
+ * cache. Without pre loading the users, the table in the UI would only show a
+ * given user once they have visited the application.
+ */
+public class SeedUserAccountsAction extends AbstractUserAction<Void> {
+
+    private static final Logger logger = LoggerFactory.getLogger(SeedUserAccountsAction.class);
+
+    @Override
+    public Void execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException {
+        UserDAO userDao = daoFactory.getUserDAO();
+        Set<String> authorizedDns = new HashSet<>();
+
+        // get the current user cache
+        final Set<NiFiUser> existingUsers;
+        try {
+            existingUsers = userDao.findUsers();
+        } catch (Exception e) {
+            // unable to access local cache... start up failure
+            logger.error(String.format("Unable to get existing user base. Cannot proceed until these users can be "
+                    + "verified against the current authority provider: %s", e));
+            throw new AdministrationException(e);
+        }
+
+        try {
+            // all users for all roles
+            for (final Authority authority : Authority.values()) {
+                authorizedDns.addAll(authorityProvider.getUsers(authority));
+            }
+        } catch (AuthorityAccessException aae) {
+            // unable to access the authority provider... honor the cache
+            logger.warn("Unable to access authority provider due to " + aae);
+            return null;
+        }
+
+        final Set<NiFiUser> accountsToRevoke = new HashSet<>(existingUsers);
+
+        // persist the users
+        for (String dn : authorizedDns) {
+            NiFiUser user = null;
+            try {
+                // locate the user for this dn
+                user = userDao.findUserByDn(dn);
+                boolean newAccount = false;
+
+                // if the user does not exist, create a new account
+                if (user == null) {
+                    logger.info(String.format("Creating user account: %s", dn));
+                    newAccount = true;
+
+                    // create the user
+                    user = new NiFiUser();
+                    user.setDn(dn);
+                    user.setUserName(CertificateUtils.extractUsername(dn));
+                    user.setJustification("User details specified by authority provider.");
+                } else {
+                    logger.info(String.format("User account already created: %s. Updating authorities...", dn));
+                }
+
+                // verify the account
+                verifyAccount(authorityProvider, user);
+
+                // persist the account accordingly
+                if (newAccount) {
+                    CreateUserAction createUser = new CreateUserAction(user);
+                    createUser.execute(daoFactory, authorityProvider);
+                } else {
+                    // this is not a new user and we have just verified their 
+                    // account, do not revoke...
+                    accountsToRevoke.remove(user);
+
+                    // persist the user
+                    UpdateUserCacheAction updateUser = new UpdateUserCacheAction(user);
+                    updateUser.execute(daoFactory, authorityProvider);
+
+                    // persist the user's authorities
+                    UpdateUserAuthoritiesCacheAction updateUserAuthorities = new UpdateUserAuthoritiesCacheAction(user);
+                    updateUserAuthorities.execute(daoFactory, authorityProvider);
+                }
+            } catch (DataAccessException dae) {
+                if (user != null) {
+                    logger.warn(String.format("Unable to access account details in local cache for user %s: %s", user, dae.getMessage()));
+                } else {
+                    logger.warn(String.format("Unable to access account details in local cache: %s", dae.getMessage()));
+                }
+            } catch (UnknownIdentityException uie) {
+                if (user != null) {
+                    logger.warn(String.format("Unable to find account details in authority provider for user %s: %s", user, uie.getMessage()));
+                } else {
+                    logger.warn(String.format("Unable to find account details in authority provider: %s", uie.getMessage()));
+                }
+            } catch (AuthorityAccessException aae) {
+                logger.warn("Unable to access authority provider due to " + aae);
+
+                // unable to access authority provider for this user, honor the cache for now
+                accountsToRevoke.remove(user);
+            }
+        }
+
+        // remove all users that are no longer in the provider
+        for (final NiFiUser user : accountsToRevoke) {
+            // allow pending requests to remain...
+            if (AccountStatus.PENDING.equals(user.getStatus())) {
+                continue;
+            }
+
+            try {
+                logger.info(String.format("User not authorized with configured provider: %s. Disabling account...", user.getDn()));
+
+                // disable the account and reset its last verified timestamp since it was not found 
+                // in the current configured authority provider
+                user.setStatus(AccountStatus.DISABLED);
+                user.setLastVerified(null);
+
+                // update the user record
+                UpdateUserCacheAction updateUser = new UpdateUserCacheAction(user);
+                updateUser.execute(daoFactory, authorityProvider);
+            } catch (final Exception e) {
+                // unable to revoke access for someone we know is not authorized... fail start up
+                logger.error(String.format("Unable to revoke access for user %s that is no longer authorized: %s", user, e));
+                throw new AdministrationException(e);
+            }
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UngroupUserAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UngroupUserAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UngroupUserAction.java
new file mode 100644
index 0000000..01eaf5f
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UngroupUserAction.java
@@ -0,0 +1,69 @@
+/*
+ * 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 org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.UserDAO;
+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.exception.AuthorityAccessException;
+import org.apache.nifi.authorization.exception.UnknownIdentityException;
+import org.apache.nifi.user.NiFiUser;
+
+/**
+ *
+ */
+public class UngroupUserAction extends AbstractUserAction<Void> {
+
+    private final String userId;
+
+    public UngroupUserAction(String userId) {
+        this.userId = userId;
+    }
+
+    @Override
+    public Void execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) {
+        final UserDAO userDao = daoFactory.getUserDAO();
+
+        // get the user in question
+        final NiFiUser user = userDao.findUserById(userId);
+
+        // ensure the user exists
+        if (user == null) {
+            throw new AccountNotFoundException(String.format("Unable to find account with ID %s.", userId));
+        }
+
+        // set the user group
+        user.setUserGroup(null);
+
+        // update the user locally
+        userDao.updateUser(user);
+
+        try {
+            // update the authority provider
+            authorityProvider.ungroupUser(user.getDn());
+        } catch (UnknownIdentityException uie) {
+            throw new AccountNotFoundException(String.format("Unable to ungroup user '%s': %s", user.getDn(), uie.getMessage()), uie);
+        } catch (AuthorityAccessException aae) {
+            throw new AdministrationException(String.format("Unable to ungroup user '%s': %s", user.getDn(), aae.getMessage()), aae);
+        }
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UngroupUserGroupAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UngroupUserGroupAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UngroupUserGroupAction.java
new file mode 100644
index 0000000..fa24fbe
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UngroupUserGroupAction.java
@@ -0,0 +1,57 @@
+/*
+ * 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 org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.UserDAO;
+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.exception.AuthorityAccessException;
+import org.apache.nifi.authorization.exception.UnknownIdentityException;
+
+/**
+ *
+ */
+public class UngroupUserGroupAction extends AbstractUserAction<Void> {
+
+    private final String group;
+
+    public UngroupUserGroupAction(String group) {
+        this.group = group;
+    }
+
+    @Override
+    public Void execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) {
+        final UserDAO userDao = daoFactory.getUserDAO();
+
+        // update the user locally
+        userDao.ungroup(group);
+
+        try {
+            // update the authority provider
+            authorityProvider.ungroup(group);
+        } catch (UnknownIdentityException uie) {
+            throw new AccountNotFoundException(String.format("Unable to ungroup '%s': %s", group, uie.getMessage()), uie);
+        } catch (AuthorityAccessException aae) {
+            throw new AdministrationException(String.format("Unable to ungroup '%s': %s", group, aae.getMessage()), aae);
+        }
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UpdateUserAction.java
----------------------------------------------------------------------
diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UpdateUserAction.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UpdateUserAction.java
new file mode 100644
index 0000000..cef21d7
--- /dev/null
+++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/service/action/UpdateUserAction.java
@@ -0,0 +1,124 @@
+/*
+ * 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.Date;
+import java.util.Set;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.DataAccessException;
+import org.apache.nifi.admin.dao.UserDAO;
+import org.apache.nifi.admin.service.AccountNotFoundException;
+import org.apache.nifi.admin.service.AdministrationException;
+import org.apache.nifi.authorization.Authority;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.apache.nifi.authorization.exception.AuthorityAccessException;
+import org.apache.nifi.authorization.exception.IdentityAlreadyExistsException;
+import org.apache.nifi.authorization.exception.UnknownIdentityException;
+import org.apache.nifi.user.AccountStatus;
+import org.apache.nifi.user.NiFiUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Sets user authorities.
+ */
+public class UpdateUserAction extends AbstractUserAction<NiFiUser> {
+
+    private static final Logger logger = LoggerFactory.getLogger(UpdateUserAction.class);
+
+    private final String id;
+    private final Set<Authority> authorities;
+
+    public UpdateUserAction(String id, Set<Authority> authorities) {
+        this.id = id;
+        this.authorities = authorities;
+    }
+
+    @Override
+    public NiFiUser execute(DAOFactory daoFactory, AuthorityProvider authorityProvider) throws DataAccessException, AdministrationException {
+        UserDAO userDao = daoFactory.getUserDAO();
+
+        // get the user
+        NiFiUser user = userDao.findUserById(id);
+
+        // ensure the user exists
+        if (user == null) {
+            throw new AccountNotFoundException(String.format("Unable to find account with ID %s.", id));
+        }
+
+        // determine whether this users exists
+        boolean doesDnExist = false;
+        try {
+            doesDnExist = authorityProvider.doesDnExist(user.getDn());
+        } catch (AuthorityAccessException aae) {
+            throw new AdministrationException(String.format("Unable to access authority details: %s", aae.getMessage()), aae);
+        }
+
+        // if the user already doesn't exist, add them
+        if (!doesDnExist) {
+            try {
+                // add the account account and group if necessary
+                authorityProvider.addUser(user.getDn(), user.getUserGroup());
+            } catch (final IdentityAlreadyExistsException iaee) {
+                logger.warn(String.format("User '%s' already exists in the authority provider.  Continuing with user update.", user.getDn()));
+            } catch (AuthorityAccessException aae) {
+                throw new AdministrationException(String.format("Unable to access authorities for '%s': %s", user.getDn(), aae.getMessage()), aae);
+            }
+        }
+
+        try {
+            // update the authority provider as approprivate
+            authorityProvider.setAuthorities(user.getDn(), authorities);
+        } catch (UnknownIdentityException uie) {
+            throw new AccountNotFoundException(String.format("Unable to modify authorities for '%s': %s.", user.getDn(), uie.getMessage()), uie);
+        } catch (AuthorityAccessException aae) {
+            throw new AdministrationException(String.format("Unable to access authorities for '%s': %s.", user.getDn(), aae.getMessage()), aae);
+        }
+
+        try {
+            // get the user group
+            user.setUserGroup(authorityProvider.getGroupForUser(user.getDn()));
+        } catch (UnknownIdentityException uie) {
+            throw new AccountNotFoundException(String.format("Unable to determine the group for '%s': %s.", user.getDn(), uie.getMessage()), uie);
+        } catch (AuthorityAccessException aae) {
+            throw new AdministrationException(String.format("Unable to access the group for '%s': %s.", user.getDn(), aae.getMessage()), aae);
+        }
+
+        // since all the authorities were updated accordingly, set the authorities
+        user.getAuthorities().clear();
+        user.getAuthorities().addAll(authorities);
+
+        // update the users status in case they were previously pending or disabled
+        user.setStatus(AccountStatus.ACTIVE);
+
+        // update the users last verified time - this timestamp shouldn't be recorded
+        // until the both the user's authorities and group have been synced
+        Date now = new Date();
+        user.setLastVerified(now);
+
+        // persist the user's updates
+        UpdateUserCacheAction updateUser = new UpdateUserCacheAction(user);
+        updateUser.execute(daoFactory, authorityProvider);
+
+        // persist the user's authorities
+        UpdateUserAuthoritiesCacheAction updateUserAuthorities = new UpdateUserAuthoritiesCacheAction(user);
+        updateUserAuthorities.execute(daoFactory, authorityProvider);
+
+        // return the user
+        return user;
+    }
+}