http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/impl/StandardUserService.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/impl/StandardUserService.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/impl/StandardUserService.java
new file mode 100644
index 0000000..424816f
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/impl/StandardUserService.java
@@ -0,0 +1,642 @@
+/*
+ * 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 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;
+
+import org.apache.nifi.admin.dao.DataAccessException;
+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;
+import org.apache.nifi.admin.service.action.DisableUserGroupAction;
+import org.apache.nifi.admin.service.action.FindUserByDnAction;
+import org.apache.nifi.admin.service.action.FindUserByIdAction;
+import org.apache.nifi.admin.service.action.GetUserGroupAction;
+import org.apache.nifi.admin.service.action.GetUsersAction;
+import org.apache.nifi.admin.service.action.HasPendingUserAccounts;
+import org.apache.nifi.admin.service.action.InvalidateUserAccountAction;
+import org.apache.nifi.admin.service.action.InvalidateUserGroupAccountsAction;
+import org.apache.nifi.admin.service.action.RequestUserAccountAction;
+import org.apache.nifi.admin.service.action.SeedUserAccountsAction;
+import org.apache.nifi.admin.service.action.UpdateUserAction;
+import org.apache.nifi.admin.service.action.UpdateUserGroupAction;
+import org.apache.nifi.admin.service.action.UngroupUserAction;
+import org.apache.nifi.admin.service.action.UngroupUserGroupAction;
+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;
+import org.apache.nifi.util.NiFiProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class StandardUserService implements UserService {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(StandardUserService.class);
+
+    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+    private final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
+    private final ReentrantReadWriteLock.WriteLock writeLock = 
lock.writeLock();
+
+    private TransactionBuilder transactionBuilder;
+    private NiFiProperties properties;
+
+    /**
+     * Seed any users from the authority provider that are not already present.
+     */
+    public void seedUserAccounts() {
+        // do not seed node's user cache. when/if the node disconnects its
+        // cache will be populated lazily (as needed)
+        if (properties.isNode()) {
+            return;
+        }
+
+        Transaction transaction = null;
+        writeLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // seed the accounts
+            SeedUserAccountsAction seedUserAccounts = new 
SeedUserAccountsAction();
+            transaction.execute(seedUserAccounts);
+
+            // commit the transaction
+            transaction.commit();
+        } catch (AdministrationException ae) {
+            rollback(transaction);
+            throw ae;
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public NiFiUser createPendingUserAccount(String dn, String justification) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // create the account request
+            RequestUserAccountAction requestUserAccount = new 
RequestUserAccountAction(dn, justification);
+            NiFiUser user = transaction.execute(requestUserAccount);
+
+            // commit the transaction
+            transaction.commit();
+
+            // return the nifi user
+            return user;
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public NiFiUserGroup updateGroup(final String group, final Set<String> 
userIds, final Set<Authority> authorities) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // if user ids have been specified, invalidate the user accounts 
before performing
+            // the desired updates. if case of an error, this will ensure that 
these users are
+            // authorized the next time the access the application
+            if (userIds != null) {
+                for (final String userId : userIds) {
+                    invalidateUserAccount(userId);
+                }
+            }
+
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // set the authorities for each user in this group if specified
+            final UpdateUserGroupAction updateUserGroup = new 
UpdateUserGroupAction(group, userIds, authorities);
+            transaction.execute(updateUserGroup);
+
+            // get all the users that are now in this group
+            final GetUserGroupAction getUserGroup = new 
GetUserGroupAction(group);
+            final NiFiUserGroup userGroup = transaction.execute(getUserGroup);
+
+            // commit the transaction
+            transaction.commit();
+
+            return userGroup;
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public void ungroupUser(String id) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // ungroup the specified user
+            final UngroupUserAction ungroupUser = new UngroupUserAction(id);
+            transaction.execute(ungroupUser);
+
+            // commit the transaction
+            transaction.commit();
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public void ungroup(String group) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // ungroup the specified user
+            final UngroupUserGroupAction ungroupUserGroup = new 
UngroupUserGroupAction(group);
+            transaction.execute(ungroupUserGroup);
+
+            // commit the transaction
+            transaction.commit();
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public NiFiUser checkAuthorization(String dn) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // create the connection
+            transaction = transactionBuilder.start();
+
+            // determine how long the cache is valid for
+            final int cacheSeconds;
+            try {
+                cacheSeconds = (int) 
FormatUtils.getTimeDuration(properties.getUserCredentialCacheDuration(), 
TimeUnit.SECONDS);
+            } catch (IllegalArgumentException iae) {
+                throw new AdministrationException("User credential cache 
duration is not configured correctly.");
+            }
+
+            // attempt to authorize the user
+            AuthorizeUserAction authorizeUser = new AuthorizeUserAction(dn, 
cacheSeconds);
+            NiFiUser user = transaction.execute(authorizeUser);
+
+            // commit the transaction
+            transaction.commit();
+
+            // return the nifi user
+            return user;
+        } catch (DataAccessException | TransactionException dae) {
+            rollback(transaction);
+            throw new AdministrationException(dae);
+        } catch (AccountDisabledException | AccountPendingException ade) {
+            rollback(transaction);
+            throw ade;
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public void deleteUser(String id) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // create the connection
+            transaction = transactionBuilder.start();
+
+            // delete the user
+            DeleteUserAction deleteUser = new DeleteUserAction(id);
+            transaction.execute(deleteUser);
+
+            // commit the transaction
+            transaction.commit();
+        } catch (DataAccessException | TransactionException dae) {
+            rollback(transaction);
+            throw new AdministrationException(dae);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public NiFiUser disable(String id) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // create the connection
+            transaction = transactionBuilder.start();
+
+            // disable the user
+            DisableUserAction disableUser = new DisableUserAction(id);
+            NiFiUser user = transaction.execute(disableUser);
+
+            // commit the transaction
+            transaction.commit();
+
+            // return the user
+            return user;
+        } catch (DataAccessException | TransactionException dae) {
+            rollback(transaction);
+            throw new AdministrationException(dae);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public NiFiUserGroup disableGroup(String group) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // create the connection
+            transaction = transactionBuilder.start();
+
+            // disable the user
+            DisableUserGroupAction disableUser = new 
DisableUserGroupAction(group);
+            NiFiUserGroup userGroup = transaction.execute(disableUser);
+
+            // commit the transaction
+            transaction.commit();
+
+            // return the user
+            return userGroup;
+        } catch (DataAccessException | TransactionException dae) {
+            rollback(transaction);
+            throw new AdministrationException(dae);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public NiFiUser update(String id, Set<Authority> authorities) {
+        Transaction transaction = null;
+
+        // may be empty but not null
+        if (authorities == null) {
+            throw new IllegalArgumentException("The specified authorities 
cannot be null.");
+        }
+
+        writeLock.lock();
+        try {
+            // invalidate the user account in preparation for potential 
subsequent errors
+            invalidateUserAccount(id);
+
+            // at this point the current user account has been invalidated so 
we will
+            // attempt to update the account. if any part fails we are assured 
the
+            // user will be need to be given approval before they access the 
system at
+            // a later time
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // update the user authorities
+            UpdateUserAction setUserAuthorities = new UpdateUserAction(id, 
authorities);
+            NiFiUser user = transaction.execute(setUserAuthorities);
+
+            // commit the transaction
+            transaction.commit();
+
+            // return the user
+            return user;
+        } catch (TransactionException | DataAccessException e) {
+            rollback(transaction);
+            throw new AdministrationException(e);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Invalidates the user with the specified id. This is done to ensure a 
user
+     * account will need to be re-validated in case an error occurs while
+     * modifying a user account. This method should only be invoked from within
+     * a write lock.
+     *
+     * @param id user account identifier
+     */
+    @Override
+    public void invalidateUserAccount(String id) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // invalidate the user account
+            InvalidateUserAccountAction invalidateUserAccount = new 
InvalidateUserAccountAction(id);
+            transaction.execute(invalidateUserAccount);
+
+            // commit the transaction
+            transaction.commit();
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public void invalidateUserGroupAccount(String group) {
+        Transaction transaction = null;
+
+        writeLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // invalidate the user account
+            InvalidateUserGroupAccountsAction invalidateUserGroupAccounts = 
new InvalidateUserGroupAccountsAction(group);
+            transaction.execute(invalidateUserGroupAccounts);
+
+            // commit the transaction
+            transaction.commit();
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            writeLock.unlock();
+        }
+    }
+
+    // -----------------
+    // read only methods
+    // -----------------
+    @Override
+    public Boolean hasPendingUserAccount() {
+        Transaction transaction = null;
+
+        readLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            final HasPendingUserAccounts hasPendingAccounts = new 
HasPendingUserAccounts();
+            final Boolean hasPendingUserAccounts = 
transaction.execute(hasPendingAccounts);
+
+            // commit the transaction
+            transaction.commit();
+
+            return hasPendingUserAccounts;
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            readLock.unlock();
+        }
+    }
+
+    @Override
+    public DownloadAuthorization authorizeDownload(final List<String> dnChain, 
final Map<String, String> 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<NiFiUser> getUsers() {
+        Transaction transaction = null;
+
+        readLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // get all users
+            GetUsersAction getUsers = new GetUsersAction();
+            Collection<NiFiUser> users = transaction.execute(getUsers);
+
+            // commit the transaction
+            transaction.commit();
+
+            // return the users
+            return users;
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            readLock.unlock();
+        }
+    }
+
+    @Override
+    public NiFiUser getUserById(String id) {
+        Transaction transaction = null;
+
+        readLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // return the desired user
+            FindUserByIdAction findUserById = new FindUserByIdAction(id);
+            NiFiUser user = transaction.execute(findUserById);
+
+            // commit the transaction
+            transaction.commit();
+
+            // return the user
+            return user;
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            readLock.unlock();
+        }
+    }
+
+    @Override
+    public NiFiUser getUserByDn(String dn) {
+        Transaction transaction = null;
+
+        readLock.lock();
+        try {
+            // start the transaction
+            transaction = transactionBuilder.start();
+
+            // return the desired user
+            FindUserByDnAction findUserByDn = new FindUserByDnAction(dn);
+            NiFiUser user = transaction.execute(findUserByDn);
+
+            // commit the transaction
+            transaction.commit();
+
+            // return the user
+            return user;
+        } catch (TransactionException | DataAccessException te) {
+            rollback(transaction);
+            throw new AdministrationException(te);
+        } catch (Throwable t) {
+            rollback(transaction);
+            throw t;
+        } finally {
+            closeQuietly(transaction);
+            readLock.unlock();
+        }
+    }
+
+    private void rollback(final Transaction transaction) {
+        if (transaction != null) {
+            transaction.rollback();
+        }
+    }
+
+    private void closeQuietly(final Transaction transaction) {
+        if (transaction != null) {
+            try {
+                transaction.close();
+            } catch (final IOException ioe) {
+            }
+        }
+    }
+
+    public void setTransactionBuilder(TransactionBuilder transactionBuilder) {
+        this.transactionBuilder = transactionBuilder;
+    }
+
+    public void setProperties(NiFiProperties properties) {
+        this.properties = properties;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/Transaction.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/Transaction.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/Transaction.java
new file mode 100644
index 0000000..4792581
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/Transaction.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.transaction;
+
+import java.io.Closeable;
+import org.apache.nifi.admin.service.action.AdministrationAction;
+
+/**
+ * Defines a transaction.
+ */
+public interface Transaction extends Closeable {
+
+    /**
+     * Executes the specified action within the current transaction.
+     *
+     * @param <T> type of action to execute
+     * @param action action to execute
+     * @return executed action
+     * @throws IllegalStateException - if there is no current transaction
+     */
+    <T> T execute(AdministrationAction<T> action);
+
+    /**
+     * Commits the current transaction.
+     *
+     * @throws TransactionException - if the transaction is unable to be
+     * committed
+     */
+    void commit() throws TransactionException;
+
+    /**
+     * Rolls back the current transaction.
+     */
+    void rollback();
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/TransactionBuilder.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/TransactionBuilder.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/TransactionBuilder.java
new file mode 100644
index 0000000..2d2ef82
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/TransactionBuilder.java
@@ -0,0 +1,25 @@
+/*
+ * 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.transaction;
+
+/**
+ *
+ */
+public interface TransactionBuilder {
+
+    Transaction start() throws TransactionException;
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/TransactionException.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/TransactionException.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/TransactionException.java
new file mode 100644
index 0000000..924e01f
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/TransactionException.java
@@ -0,0 +1,40 @@
+/*
+ * 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.transaction;
+
+/**
+ * Exception to indicate that the user account is disabled.
+ */
+public class TransactionException extends RuntimeException {
+
+    public TransactionException(String message, Throwable cause, boolean 
enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+
+    public TransactionException(Throwable cause) {
+        super(cause);
+    }
+
+    public TransactionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public TransactionException(String message) {
+        super(message);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/impl/StandardTransaction.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/impl/StandardTransaction.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/impl/StandardTransaction.java
new file mode 100644
index 0000000..a3cfb5e
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/impl/StandardTransaction.java
@@ -0,0 +1,93 @@
+/*
+ * 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.transaction.impl;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.apache.nifi.admin.RepositoryUtils;
+import org.apache.nifi.admin.dao.DAOFactory;
+import org.apache.nifi.admin.dao.impl.DAOFactoryImpl;
+import org.apache.nifi.admin.service.action.AdministrationAction;
+import org.apache.nifi.admin.service.transaction.TransactionException;
+import org.apache.nifi.admin.service.transaction.Transaction;
+import org.apache.nifi.authorization.AuthorityProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Transaction implementation that uses the specified SQL Connection and
+ * AuthorityProvider.
+ */
+public class StandardTransaction implements Transaction {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(StandardTransaction.class);
+
+    private final AuthorityProvider authorityProvider;
+    private Connection connection;
+
+    public StandardTransaction(AuthorityProvider authorityProvider, Connection 
connection) {
+        this.authorityProvider = authorityProvider;
+        this.connection = connection;
+    }
+
+    @Override
+    public <T> T execute(AdministrationAction<T> action) {
+        // ensure the transaction has been started
+        if (connection == null) {
+            throw new IllegalStateException("This transaction is not active.");
+        }
+
+        // create a dao factory
+        DAOFactory daoFactory = new DAOFactoryImpl(connection);
+
+        // execute the specified action
+        return action.execute(daoFactory, authorityProvider);
+    }
+
+    @Override
+    public void commit() throws TransactionException {
+        // ensure there is an active transaction
+        if (connection == null) {
+            throw new IllegalStateException("No active transaction.");
+        }
+
+        try {
+            // commit the transaction
+            connection.commit();
+        } catch (SQLException sqle) {
+            throw new TransactionException(sqle.getMessage());
+        }
+    }
+
+    @Override
+    public void rollback() {
+        // ensure there is an active transaction
+        if (connection != null) {
+            // rollback the transaction
+            RepositoryUtils.rollback(connection, logger);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (connection != null) {
+            RepositoryUtils.closeQuietly(connection);
+            connection = null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/impl/StandardTransactionBuilder.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/impl/StandardTransactionBuilder.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/impl/StandardTransactionBuilder.java
new file mode 100644
index 0000000..b6e5a30
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/transaction/impl/StandardTransactionBuilder.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.transaction.impl;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import javax.sql.DataSource;
+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.AuthorityProvider;
+
+/**
+ *
+ */
+public class StandardTransactionBuilder implements TransactionBuilder {
+
+    private DataSource dataSource;
+    private AuthorityProvider authorityProvider;
+
+    @Override
+    public Transaction start() throws TransactionException {
+        try {
+            // get a new connection
+            Connection connection = dataSource.getConnection();
+            connection.setAutoCommit(false);
+
+            // create a new transaction
+            return new StandardTransaction(authorityProvider, connection);
+        } catch (SQLException sqle) {
+            throw new TransactionException(sqle.getMessage());
+        }
+    }
+
+    /* setters */
+    public void setDataSource(DataSource dataSource) {
+        this.dataSource = dataSource;
+    }
+
+    public void setAuthorityProvider(AuthorityProvider authorityProvider) {
+        this.authorityProvider = authorityProvider;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java
new file mode 100644
index 0000000..b3e9547
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java
@@ -0,0 +1,490 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+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;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import org.apache.nifi.authorization.annotation.AuthorityProviderContext;
+import org.apache.nifi.authorization.exception.AuthorityAccessException;
+import org.apache.nifi.authorization.exception.IdentityAlreadyExistsException;
+import org.apache.nifi.authorization.exception.ProviderCreationException;
+import org.apache.nifi.authorization.exception.ProviderDestructionException;
+import org.apache.nifi.authorization.exception.UnknownIdentityException;
+import org.apache.nifi.authorization.generated.AuthorityProviders;
+import org.apache.nifi.authorization.generated.Property;
+import org.apache.nifi.authorization.generated.Provider;
+import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.NarCloseable;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.xml.sax.SAXException;
+
+/**
+ * Factory bean for loading the configured authority provider.
+ */
+public class AuthorityProviderFactoryBean implements FactoryBean, 
ApplicationContextAware, DisposableBean, AuthorityProviderLookup {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(AuthorityProviderFactoryBean.class);
+    private static final String AUTHORITY_PROVIDERS_XSD = 
"/authority-providers.xsd";
+    private static final String JAXB_GENERATED_PATH = 
"org.apache.nifi.authorization.generated";
+    private static final JAXBContext JAXB_CONTEXT = initializeJaxbContext();
+
+    /**
+     * Load the JAXBContext.
+     */
+    private static JAXBContext initializeJaxbContext() {
+        try {
+            return JAXBContext.newInstance(JAXB_GENERATED_PATH, 
AuthorityProviderFactoryBean.class.getClassLoader());
+        } catch (JAXBException e) {
+            throw new RuntimeException("Unable to create JAXBContext.");
+        }
+    }
+
+    private ApplicationContext applicationContext;
+    private AuthorityProvider authorityProvider;
+    private NiFiProperties properties;
+    private final Map<String, AuthorityProvider> authorityProviders = new 
HashMap<>();
+
+    @Override
+    public AuthorityProvider getAuthorityProvider(String identifier) {
+        return authorityProviders.get(identifier);
+    }
+
+    @Override
+    public Object getObject() throws Exception {
+        if (authorityProvider == null) {
+            // look up the authority provider to use
+            final String authorityProviderIdentifier = 
properties.getProperty(NiFiProperties.SECURITY_USER_AUTHORITY_PROVIDER);
+
+            // ensure the authority provider class name was specified
+            if (StringUtils.isBlank(authorityProviderIdentifier)) {
+                // if configured for ssl, the authority provider must be 
specified
+                if (properties.getSslPort() != null) {
+                    throw new Exception("When running securely, the authority 
provider identifier must be specified in the nifi properties file.");
+                }
+
+                // use a default provider... only allowable when running not 
securely
+                authorityProvider = createDefaultProvider();
+            } else {
+                final AuthorityProviders authorityProviderConfiguration = 
loadAuthorityProvidersConfiguration();
+
+                // create each authority provider
+                for (final Provider provider : 
authorityProviderConfiguration.getProvider()) {
+                    authorityProviders.put(provider.getIdentifier(), 
createAuthorityProvider(provider.getIdentifier(), provider.getClazz()));
+                }
+
+                // configure each authority provider
+                for (final Provider provider : 
authorityProviderConfiguration.getProvider()) {
+                    final AuthorityProvider instance = 
authorityProviders.get(provider.getIdentifier());
+                    
instance.onConfigured(loadAuthorityProviderConfiguration(provider));
+                }
+
+                // get the authority provider instance
+                authorityProvider = 
getAuthorityProvider(authorityProviderIdentifier);
+
+                // ensure it was found
+                if (authorityProvider == null) {
+                    throw new Exception(String.format("The specified authority 
provider '%s' could not be found.", authorityProviderIdentifier));
+                }
+            }
+        }
+
+        return authorityProvider;
+    }
+
+    private AuthorityProviders loadAuthorityProvidersConfiguration() throws 
Exception {
+        final File authorityProvidersConfigurationFile = 
properties.getAuthorityProviderConfiguraitonFile();
+
+        // load the users from the specified file
+        if (authorityProvidersConfigurationFile.exists()) {
+            try {
+                // find the schema
+                final SchemaFactory schemaFactory = 
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+                final Schema schema = 
schemaFactory.newSchema(AuthorityProviders.class.getResource(AUTHORITY_PROVIDERS_XSD));
+
+                // attempt to unmarshal
+                final Unmarshaller unmarshaller = 
JAXB_CONTEXT.createUnmarshaller();
+                unmarshaller.setSchema(schema);
+                final JAXBElement<AuthorityProviders> element = 
unmarshaller.unmarshal(new StreamSource(authorityProvidersConfigurationFile), 
AuthorityProviders.class);
+                return element.getValue();
+            } catch (SAXException | JAXBException e) {
+                throw new Exception("Unable to load the authority provider 
configuration file at: " + 
authorityProvidersConfigurationFile.getAbsolutePath());
+            }
+        } else {
+            throw new Exception("Unable to find the authority provider 
configuration file at " + 
authorityProvidersConfigurationFile.getAbsolutePath());
+        }
+    }
+
+    private AuthorityProvider createAuthorityProvider(final String identifier, 
final String authorityProviderClassName) throws Exception {
+        // get the classloader for the specified authority provider
+        final ClassLoader authorityProviderClassLoader = 
ExtensionManager.getClassLoader(authorityProviderClassName);
+        if (authorityProviderClassLoader == null) {
+            throw new Exception(String.format("The specified authority 
provider class '%s' is not known to this nifi.", authorityProviderClassName));
+        }
+
+        // get the current context classloader
+        final ClassLoader currentClassLoader = 
Thread.currentThread().getContextClassLoader();
+
+        final AuthorityProvider instance;
+        try {
+            // set the appropriate class loader
+            
Thread.currentThread().setContextClassLoader(authorityProviderClassLoader);
+
+            // attempt to load the class
+            Class<?> rawAuthorityProviderClass = 
Class.forName(authorityProviderClassName, true, authorityProviderClassLoader);
+            Class<? extends AuthorityProvider> authorityProviderClass = 
rawAuthorityProviderClass.asSubclass(AuthorityProvider.class);
+
+            // otherwise create a new instance
+            Constructor constructor = authorityProviderClass.getConstructor();
+            instance = (AuthorityProvider) constructor.newInstance();
+
+            // method injection
+            performMethodInjection(instance, authorityProviderClass);
+
+            // field injection
+            performFieldInjection(instance, authorityProviderClass);
+
+            // call post construction lifecycle event
+            instance.initialize(new 
StandardAuthorityProviderInitializationContext(identifier, this));
+        } finally {
+            if (currentClassLoader != null) {
+                
Thread.currentThread().setContextClassLoader(currentClassLoader);
+            }
+        }
+
+        return withNarLoader(instance);
+    }
+
+    private AuthorityProviderConfigurationContext 
loadAuthorityProviderConfiguration(final Provider provider) {
+        final Map<String, String> providerProperties = new HashMap<>();
+
+        for (final Property property : provider.getProperty()) {
+            providerProperties.put(property.getName(), property.getValue());
+        }
+
+        return new 
StandardAuthorityProviderConfigurationContext(provider.getIdentifier(), 
providerProperties);
+    }
+
+    private void performMethodInjection(final AuthorityProvider instance, 
final Class authorityProviderClass) throws IllegalAccessException, 
IllegalArgumentException, InvocationTargetException {
+        for (final Method method : authorityProviderClass.getMethods()) {
+            if (method.isAnnotationPresent(AuthorityProviderContext.class)) {
+                // make the method accessible
+                final boolean isAccessible = method.isAccessible();
+                method.setAccessible(true);
+
+                try {
+                    final Class<?>[] argumentTypes = 
method.getParameterTypes();
+
+                    // look for setters (single argument)
+                    if (argumentTypes.length == 1) {
+                        final Class<?> argumentType = argumentTypes[0];
+
+                        // look for well known types
+                        if 
(NiFiProperties.class.isAssignableFrom(argumentType)) {
+                            // nifi properties injection
+                            method.invoke(instance, properties);
+                        } else if 
(ApplicationContext.class.isAssignableFrom(argumentType)) {
+                            // spring application context injection
+                            method.invoke(instance, applicationContext);
+                        }
+                    }
+                } finally {
+                    method.setAccessible(isAccessible);
+                }
+            }
+        }
+
+        final Class parentClass = authorityProviderClass.getSuperclass();
+        if (parentClass != null && 
AuthorityProvider.class.isAssignableFrom(parentClass)) {
+            performMethodInjection(instance, parentClass);
+        }
+    }
+
+    private void performFieldInjection(final AuthorityProvider instance, final 
Class authorityProviderClass) throws IllegalArgumentException, 
IllegalAccessException {
+        for (final Field field : authorityProviderClass.getDeclaredFields()) {
+            if (field.isAnnotationPresent(AuthorityProviderContext.class)) {
+                // make the method accessible
+                final boolean isAccessible = field.isAccessible();
+                field.setAccessible(true);
+
+                try {
+                    // get the type
+                    final Class<?> fieldType = field.getType();
+
+                    // only consider this field if it isn't set yet
+                    if (field.get(instance) == null) {
+                        // look for well known types
+                        if (NiFiProperties.class.isAssignableFrom(fieldType)) {
+                            // nifi properties injection
+                            field.set(instance, properties);
+                        } else if 
(ApplicationContext.class.isAssignableFrom(fieldType)) {
+                            // spring application context injection
+                            field.set(instance, applicationContext);
+                        }
+                    }
+
+                } finally {
+                    field.setAccessible(isAccessible);
+                }
+            }
+        }
+
+        final Class parentClass = authorityProviderClass.getSuperclass();
+        if (parentClass != null && 
AuthorityProvider.class.isAssignableFrom(parentClass)) {
+            performFieldInjection(instance, parentClass);
+        }
+    }
+
+    /**
+     * @return a default provider to use when running unsecurely with no
+     * provider configured
+     */
+    private AuthorityProvider createDefaultProvider() {
+        return new AuthorityProvider() {
+            @Override
+            public boolean doesDnExist(String dn) throws 
AuthorityAccessException {
+                return false;
+            }
+
+            @Override
+            public Set<Authority> getAuthorities(String dn) throws 
UnknownIdentityException, AuthorityAccessException {
+                return EnumSet.noneOf(Authority.class);
+            }
+
+            @Override
+            public void setAuthorities(String dn, Set<Authority> authorities) 
throws UnknownIdentityException, AuthorityAccessException {
+            }
+
+            @Override
+            public Set<String> getUsers(Authority authority) throws 
AuthorityAccessException {
+                return new HashSet<>();
+            }
+
+            @Override
+            public void revokeUser(String dn) throws UnknownIdentityException, 
AuthorityAccessException {
+            }
+
+            @Override
+            public void addUser(String dn, String group) throws 
IdentityAlreadyExistsException, AuthorityAccessException {
+            }
+
+            @Override
+            public String getGroupForUser(String dn) throws 
UnknownIdentityException, AuthorityAccessException {
+                return null;
+            }
+
+            @Override
+            public void revokeGroup(String group) throws 
UnknownIdentityException, AuthorityAccessException {
+            }
+
+            @Override
+            public void setUsersGroup(Set<String> dn, String group) throws 
UnknownIdentityException, AuthorityAccessException {
+            }
+
+            @Override
+            public void ungroupUser(String dn) throws 
UnknownIdentityException, AuthorityAccessException {
+            }
+
+            @Override
+            public void ungroup(String group) throws AuthorityAccessException {
+            }
+
+            @Override
+            public DownloadAuthorization authorizeDownload(List<String> 
dnChain, Map<String, String> attributes) throws UnknownIdentityException, 
AuthorityAccessException {
+                return DownloadAuthorization.approved();
+            }
+
+            @Override
+            public void initialize(AuthorityProviderInitializationContext 
initializationContext) throws ProviderCreationException {
+            }
+
+            @Override
+            public void onConfigured(AuthorityProviderConfigurationContext 
configurationContext) throws ProviderCreationException {
+            }
+
+            @Override
+            public void preDestruction() throws ProviderDestructionException {
+            }
+        };
+    }
+
+    /**
+     * Decorates the base provider to ensure the nar context classloader is 
used
+     * when invoking the underlying methods.
+     *
+     * @param baseProvider base provider
+     * @return provider
+     */
+    public AuthorityProvider withNarLoader(final AuthorityProvider 
baseProvider) {
+        return new AuthorityProvider() {
+            @Override
+            public boolean doesDnExist(String dn) throws 
AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    return baseProvider.doesDnExist(dn);
+                }
+            }
+
+            @Override
+            public Set<Authority> getAuthorities(String dn) throws 
UnknownIdentityException, AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    return baseProvider.getAuthorities(dn);
+                }
+            }
+
+            @Override
+            public void setAuthorities(String dn, Set<Authority> authorities) 
throws UnknownIdentityException, AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    baseProvider.setAuthorities(dn, authorities);
+                }
+            }
+
+            @Override
+            public Set<String> getUsers(Authority authority) throws 
AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    return baseProvider.getUsers(authority);
+                }
+            }
+
+            @Override
+            public void revokeUser(String dn) throws UnknownIdentityException, 
AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    baseProvider.revokeUser(dn);
+                }
+            }
+
+            @Override
+            public void addUser(String dn, String group) throws 
IdentityAlreadyExistsException, AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    baseProvider.addUser(dn, group);
+                }
+            }
+
+            @Override
+            public String getGroupForUser(String dn) throws 
UnknownIdentityException, AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    return baseProvider.getGroupForUser(dn);
+                }
+            }
+
+            @Override
+            public void revokeGroup(String group) throws 
UnknownIdentityException, AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    baseProvider.revokeGroup(group);
+                }
+            }
+
+            @Override
+            public void setUsersGroup(Set<String> dns, String group) throws 
UnknownIdentityException, AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    baseProvider.setUsersGroup(dns, group);
+                }
+            }
+
+            @Override
+            public void ungroupUser(String dn) throws 
UnknownIdentityException, AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    baseProvider.ungroupUser(dn);
+                }
+            }
+
+            @Override
+            public void ungroup(String group) throws AuthorityAccessException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    baseProvider.ungroup(group);
+                }
+            }
+
+            @Override
+            public DownloadAuthorization authorizeDownload(List<String> 
dnChain, Map<String, String> 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()) {
+                    baseProvider.initialize(initializationContext);
+                }
+            }
+
+            @Override
+            public void onConfigured(AuthorityProviderConfigurationContext 
configurationContext) throws ProviderCreationException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    baseProvider.onConfigured(configurationContext);
+                }
+            }
+
+            @Override
+            public void preDestruction() throws ProviderDestructionException {
+                try (final NarCloseable narCloseable = 
NarCloseable.withNarLoader()) {
+                    baseProvider.preDestruction();
+                }
+            }
+        };
+    }
+
+    @Override
+    public Class getObjectType() {
+        return AuthorityProvider.class;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return true;
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) 
throws BeansException {
+        this.applicationContext = applicationContext;
+    }
+
+    @Override
+    public void destroy() throws Exception {
+        if (authorityProvider != null) {
+            authorityProvider.preDestruction();
+        }
+    }
+
+    public void setProperties(NiFiProperties properties) {
+        this.properties = properties;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderConfigurationContext.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderConfigurationContext.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderConfigurationContext.java
new file mode 100644
index 0000000..0535e27
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderConfigurationContext.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.authorization;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ *
+ */
+public class StandardAuthorityProviderConfigurationContext implements 
AuthorityProviderConfigurationContext {
+
+    private final String identifier;
+    private final Map<String, String> properties;
+
+    public StandardAuthorityProviderConfigurationContext(String identifier, 
Map<String, String> properties) {
+        this.identifier = identifier;
+        this.properties = properties;
+    }
+
+    @Override
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return Collections.unmodifiableMap(properties);
+    }
+
+    @Override
+    public String getProperty(String property) {
+        return properties.get(property);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderInitializationContext.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderInitializationContext.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderInitializationContext.java
new file mode 100644
index 0000000..e4b16c4
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderInitializationContext.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+/**
+ *
+ */
+public class StandardAuthorityProviderInitializationContext implements 
AuthorityProviderInitializationContext {
+
+    private final String identifier;
+    private final AuthorityProviderLookup authorityProviderLookup;
+
+    public StandardAuthorityProviderInitializationContext(String identifier, 
AuthorityProviderLookup authorityProviderLookup) {
+        this.identifier = identifier;
+        this.authorityProviderLookup = authorityProviderLookup;
+    }
+
+    @Override
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public AuthorityProviderLookup getAuthorityProviderLookup() {
+        return authorityProviderLookup;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/History.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/History.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/History.java
new file mode 100644
index 0000000..8536871
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/History.java
@@ -0,0 +1,56 @@
+/*
+ * 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.history;
+
+import java.util.Collection;
+import java.util.Date;
+import org.apache.nifi.action.Action;
+
+/**
+ * The result of running an action query.
+ */
+public class History {
+
+    private Integer total;
+    private Date lastRefreshed;
+    private Collection<Action> actions;
+
+    public Collection<Action> getActions() {
+        return actions;
+    }
+
+    public void setActions(Collection<Action> actions) {
+        this.actions = actions;
+    }
+
+    public Integer getTotal() {
+        return total;
+    }
+
+    public void setTotal(Integer totalRecordCount) {
+        this.total = totalRecordCount;
+    }
+
+    public Date getLastRefreshed() {
+        return lastRefreshed;
+    }
+
+    public void setLastRefreshed(Date lastRefreshed) {
+        this.lastRefreshed = lastRefreshed;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/HistoryQuery.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/HistoryQuery.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/HistoryQuery.java
new file mode 100644
index 0000000..53cc13c
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/HistoryQuery.java
@@ -0,0 +1,99 @@
+/*
+ * 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.history;
+
+import java.util.Date;
+
+/**
+ *
+ */
+public class HistoryQuery {
+
+    private String userName;
+    private String sourceId;
+    private Date startDate;
+    private Date endDate;
+    private Integer offset;
+    private Integer count;
+    private String sortColumn;
+    private String sortOrder;
+
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+    public String getSourceId() {
+        return sourceId;
+    }
+
+    public void setSourceId(String sourceId) {
+        this.sourceId = sourceId;
+    }
+
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+
+    public Integer getCount() {
+        return count;
+    }
+
+    public void setCount(Integer count) {
+        this.count = count;
+    }
+
+    public String getSortColumn() {
+        return sortColumn;
+    }
+
+    public void setSortColumn(String sortColumn) {
+        this.sortColumn = sortColumn;
+    }
+
+    public String getSortOrder() {
+        return sortOrder;
+    }
+
+    public void setSortOrder(String sortOrder) {
+        this.sortOrder = sortOrder;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/PreviousValue.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/PreviousValue.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/PreviousValue.java
new file mode 100644
index 0000000..6ece5cf
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/history/PreviousValue.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.history;
+
+import java.util.Date;
+
+/**
+ *
+ */
+public class PreviousValue {
+
+    private String previousValue;
+    private Date timestamp;
+    private String userName;
+
+    public String getPreviousValue() {
+        return previousValue;
+    }
+
+    public void setPreviousValue(String previousValue) {
+        this.previousValue = previousValue;
+    }
+
+    public Date getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(Date timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/AccountStatus.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/AccountStatus.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/AccountStatus.java
new file mode 100644
index 0000000..d7becf1
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/AccountStatus.java
@@ -0,0 +1,47 @@
+/*
+ * 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.user;
+
+/**
+ * Represents the status of a user's account.
+ */
+public enum AccountStatus {
+
+    ACTIVE,
+    PENDING,
+    DISABLED;
+
+    /**
+     * Returns the matching status or null if the specified status does not
+     * match any statuses.
+     *
+     * @param rawStatus string form of status
+     * @return account status object
+     */
+    public static AccountStatus valueOfStatus(String rawStatus) {
+        AccountStatus desiredStatus = null;
+
+        for (AccountStatus status : values()) {
+            if (status.toString().equals(rawStatus)) {
+                desiredStatus = status;
+                break;
+            }
+        }
+
+        return desiredStatus;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUser.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUser.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUser.java
new file mode 100644
index 0000000..a47bde9
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUser.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.user;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
+import org.apache.nifi.authorization.Authority;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * An NiFiUser.
+ */
+public class NiFiUser implements Serializable {
+
+    public static final String ANONYMOUS_USER_DN = "anonymous";
+
+    private String id;
+    private String dn;
+    private String userName;
+    private String userGroup;
+    private String justification;
+
+    private Date creation;
+    private Date lastVerified;
+    private Date lastAccessed;
+
+    private AccountStatus status;
+    private EnumSet<Authority> authorities;
+
+    private NiFiUser chain;
+
+    /* getters / setters */
+    public Date getCreation() {
+        return creation;
+    }
+
+    public void setCreation(Date creation) {
+        this.creation = creation;
+    }
+
+    public String getDn() {
+        return dn;
+    }
+
+    public void setDn(String dn) {
+        this.dn = dn;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getUserGroup() {
+        return userGroup;
+    }
+
+    public void setUserGroup(String userGroup) {
+        this.userGroup = userGroup;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getJustification() {
+        return justification;
+    }
+
+    public void setJustification(String justification) {
+        this.justification = justification;
+    }
+
+    public AccountStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(AccountStatus status) {
+        this.status = status;
+    }
+
+    public Date getLastVerified() {
+        return lastVerified;
+    }
+
+    public void setLastVerified(Date lastVerified) {
+        this.lastVerified = lastVerified;
+    }
+
+    public Date getLastAccessed() {
+        return lastAccessed;
+    }
+
+    public void setLastAccessed(Date lastAccessed) {
+        this.lastAccessed = lastAccessed;
+    }
+
+    public NiFiUser getChain() {
+        return chain;
+    }
+
+    public void setChain(NiFiUser chain) {
+        this.chain = chain;
+    }
+
+    public Set<Authority> getAuthorities() {
+        if (authorities == null) {
+            authorities = EnumSet.noneOf(Authority.class);
+        }
+        return authorities;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final NiFiUser other = (NiFiUser) obj;
+        if (!Objects.equals(this.dn, other.dn)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 53 * hash + Objects.hashCode(this.dn);
+        return hash;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("dn[%s], userName[%s], justification[%s], 
authorities[%s]", getDn(), getUserName(), getJustification(), 
StringUtils.join(getAuthorities(), ", "));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUserGroup.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUserGroup.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUserGroup.java
new file mode 100644
index 0000000..7586fd1
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUserGroup.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.user;
+
+import java.util.Set;
+
+/**
+ *
+ */
+public class NiFiUserGroup {
+
+    private String group;
+    private Set<NiFiUser> users;
+
+    public String getGroup() {
+        return group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    public Set<NiFiUser> getUsers() {
+        return users;
+    }
+
+    public void setUsers(Set<NiFiUser> users) {
+        this.users = users;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml
new file mode 100644
index 0000000..a36619f
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans default-lazy-init="true"
+       xmlns="http://www.springframework.org/schema/beans";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:context="http://www.springframework.org/schema/context";
+       xmlns:aop="http://www.springframework.org/schema/aop";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+    http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.1.xsd
+    http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd";>
+
+    <!-- user authority provider -->
+    <bean id="authorityProvider" 
class="org.apache.nifi.authorization.AuthorityProviderFactoryBean" 
depends-on="clusterManager flowController">
+        <property name="properties" ref="nifiProperties"/>
+    </bean>
+
+    <!-- initialize the user data source -->
+    <bean id="userDataSource" 
class="org.apache.nifi.admin.UserDataSourceFactoryBean" 
destroy-method="shutdown">
+        <property name="properties" ref="nifiProperties"/>
+    </bean>
+
+    <!-- initialize the data source -->
+    <bean id="auditDataSource" 
class="org.apache.nifi.admin.AuditDataSourceFactoryBean" 
destroy-method="shutdown" depends-on="userDataSource">
+        <property name="properties" ref="nifiProperties"/>
+    </bean>
+
+    <!-- initialize the user transaction builder -->
+    <bean id="userTransactionBuilder" 
class="org.apache.nifi.admin.service.transaction.impl.StandardTransactionBuilder">
+        <property name="authorityProvider" ref="authorityProvider"/>
+        <property name="dataSource" ref="userDataSource"/>
+    </bean>
+    
+    <!-- initialize the audit transaction builder -->
+    <bean id="auditTransactionBuilder" 
class="org.apache.nifi.admin.service.transaction.impl.StandardTransactionBuilder">
+        <property name="authorityProvider" ref="authorityProvider"/>
+        <property name="dataSource" ref="auditDataSource"/>
+    </bean>
+
+    <!-- administration service -->
+    <bean id="userService" 
class="org.apache.nifi.admin.service.impl.StandardUserService" 
init-method="seedUserAccounts">
+        <property name="transactionBuilder" ref="userTransactionBuilder"/>
+        <property name="properties" ref="nifiProperties"/>
+    </bean>
+
+    <!-- audit service -->
+    <bean id="auditService" 
class="org.apache.nifi.admin.service.impl.StandardAuditService">
+        <property name="transactionBuilder" ref="auditTransactionBuilder"/>
+    </bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/nifi/blob/aa998847/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authority-providers.xsd
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authority-providers.xsd
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authority-providers.xsd
new file mode 100644
index 0000000..122fa2c
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authority-providers.xsd
@@ -0,0 +1,49 @@
+<?xml version="1.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.
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";>
+    <!-- role -->
+    <xs:complexType name="Provider">
+        <xs:sequence>
+            <xs:element name="identifier" type="NonEmptyStringType"/>
+            <xs:element name="class" type="NonEmptyStringType"/>
+            <xs:element name="property" type="Property" minOccurs="0" 
maxOccurs="unbounded" />
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- Name/Value properties-->
+    <xs:complexType name="Property">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="name" 
type="NonEmptyStringType"></xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="NonEmptyStringType">
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <!-- users -->
+    <xs:element name="authorityProviders">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="provider" type="Provider" minOccurs="0" 
maxOccurs="unbounded"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+</xs:schema>
\ No newline at end of file

Reply via email to