http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/authorization/user/StandardNiFiUser.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/authorization/user/StandardNiFiUser.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/authorization/user/StandardNiFiUser.java
new file mode 100644
index 0000000..3a8a8bc
--- /dev/null
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/authorization/user/StandardNiFiUser.java
@@ -0,0 +1,189 @@
+/*
+ * 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.registry.authorization.user;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * An implementation of NiFiUser.
+ */
+public class StandardNiFiUser implements NiFiUser {
+
+    public static final String ANONYMOUS_IDENTITY = "anonymous";
+    public static final StandardNiFiUser ANONYMOUS = new 
Builder().identity(ANONYMOUS_IDENTITY).anonymous(true).build();
+
+    private final String identity;
+    private final Set<String> groups;
+    private final NiFiUser chain;
+    private final String clientAddress;
+    private final boolean isAnonymous;
+
+    private StandardNiFiUser(final Builder builder) {
+        this.identity = builder.identity;
+        this.groups = builder.groups == null ? null : 
Collections.unmodifiableSet(builder.groups);
+        this.chain = builder.chain;
+        this.clientAddress = builder.clientAddress;
+        this.isAnonymous = builder.isAnonymous;
+    }
+
+    /**
+     * This static builder allows the chain and clientAddress to be populated 
without allowing calling code to provide a non-anonymous identity of the 
anonymous user.
+     *
+     * @param chain the proxied entities in {@see NiFiUser} form
+     * @param clientAddress the address the request originated from
+     * @return an anonymous user instance with the identity "anonymous"
+     */
+    public static StandardNiFiUser populateAnonymousUser(NiFiUser chain, 
String clientAddress) {
+        return new 
Builder().identity(ANONYMOUS_IDENTITY).chain(chain).clientAddress(clientAddress).anonymous(true).build();
+    }
+
+    @Override
+    public String getIdentity() {
+        return identity;
+    }
+
+    @Override
+    public Set<String> getGroups() {
+        return groups;
+    }
+
+    @Override
+    public NiFiUser getChain() {
+        return chain;
+    }
+
+    @Override
+    public boolean isAnonymous() {
+        return isAnonymous;
+    }
+
+    @Override
+    public String getClientAddress() {
+        return clientAddress;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        if (!(obj instanceof NiFiUser)) {
+            return false;
+        }
+
+        final NiFiUser other = (NiFiUser) obj;
+        return Objects.equals(this.identity, other.getIdentity());
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 53 * hash + Objects.hashCode(this.identity);
+        return hash;
+    }
+
+    @Override
+    public String toString() {
+        final String formattedGroups;
+        if (groups == null) {
+            formattedGroups = "none";
+        } else {
+            formattedGroups = StringUtils.join(groups, ", ");
+        }
+
+        return String.format("identity[%s], groups[%s]", getIdentity(), 
formattedGroups);
+    }
+
+    /**
+     * Builder for a StandardNiFiUser
+     */
+    public static class Builder {
+
+        private String identity;
+        private Set<String> groups;
+        private NiFiUser chain;
+        private String clientAddress;
+        private boolean isAnonymous = false;
+
+        /**
+         * Sets the identity.
+         *
+         * @param identity the identity string for the user (i.e. "Andy" or 
"CN=alopresto, OU=Apache NiFi")
+         * @return the builder
+         */
+        public Builder identity(final String identity) {
+            this.identity = identity;
+            return this;
+        }
+
+        /**
+         * Sets the groups.
+         *
+         * @param groups the user groups
+         * @return the builder
+         */
+        public Builder groups(final Set<String> groups) {
+            this.groups = groups;
+            return this;
+        }
+
+        /**
+         * Sets the chain.
+         *
+         * @param chain the proxy chain that leads to this users
+         * @return the builder
+         */
+        public Builder chain(final NiFiUser chain) {
+            this.chain = chain;
+            return this;
+        }
+
+        /**
+         * Sets the client address.
+         *
+         * @param clientAddress the source address of the request
+         * @return the builder
+         */
+        public Builder clientAddress(final String clientAddress) {
+            this.clientAddress = clientAddress;
+            return this;
+        }
+
+        /**
+         * Sets whether this user is the canonical "anonymous" user
+         *
+         * @param isAnonymous true to represent the canonical "anonymous" user
+         * @return the builder
+         */
+        private Builder anonymous(final boolean isAnonymous) {
+            this.isAnonymous = isAnonymous;
+            return this;
+        }
+
+        /**
+         * @return builds a StandardNiFiUser from the current state of the 
builder
+         */
+        public StandardNiFiUser build() {
+            return new StandardNiFiUser(this);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
index 35c6b55..0fc10a4 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
@@ -42,6 +42,7 @@ import javax.persistence.metamodel.Metamodel;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -166,6 +167,10 @@ public class DatabaseMetadataService implements 
MetadataService {
         return buckets;
     }
 
+    private Set<BucketEntity> getBuckets(Set<String> bucketIds) {
+        return new HashSet<>(bucketRepository.findByIdIn(bucketIds));
+    }
+
     // 
------------------------------------------------------------------------------------
 
     @Override
@@ -218,6 +223,18 @@ public class DatabaseMetadataService implements 
MetadataService {
         }
     }
 
+    @Override
+    public List<BucketItemEntity> getBucketItems(final QueryParameters params, 
final Set<String> bucketIds) {
+        Set<BucketEntity> filterBuckets = getBuckets(bucketIds);
+        if (params.getNumRows() != null && params.getPageNum() != null) {
+            return getPagedBucketItems(params, filterBuckets);
+        } else if (params.getSortParameters() != null && 
params.getSortParameters().size() > 0) {
+            return getSortedBucketItems(params, filterBuckets);
+        } else {
+            return getBucketItems(filterBuckets);
+        }
+    }
+
     private List<BucketItemEntity> getBucketItems(final BucketEntity bucket) {
         final List<BucketItemEntity> bucketItems = new ArrayList<>();
         for (BucketItemEntity item : itemRepository.findByBucket(bucket)) {
@@ -244,6 +261,32 @@ public class DatabaseMetadataService implements 
MetadataService {
         return items;
     }
 
+    private List<BucketItemEntity> getBucketItems(final Set<BucketEntity> 
buckets) {
+        final List<BucketItemEntity> bucketItems = new ArrayList<>();
+        for (BucketItemEntity item : itemRepository.findByBucketIn(buckets)) {
+            bucketItems.add(item);
+        }
+        return bucketItems;
+    }
+
+    private List<BucketItemEntity> getPagedBucketItems(final QueryParameters 
params, final Set<BucketEntity> buckets) {
+        final Pageable pageable = getPageRequest(params);
+        final List<BucketItemEntity> items = new ArrayList<>();
+        for (BucketItemEntity item : itemRepository.findByBucketIn(buckets, 
pageable)) {
+            items.add(item);
+        }
+        return items;
+    }
+
+    private List<BucketItemEntity> getSortedBucketItems(final QueryParameters 
params, final Set<BucketEntity> buckets) {
+        final Sort sort = getSort(params);
+        final List<BucketItemEntity> items = new ArrayList<>();
+        for (BucketItemEntity item : itemRepository.findByBucketIn(buckets, 
sort)) {
+            items.add(item);
+        }
+        return items;
+    }
+
     // 
------------------------------------------------------------------------------------
 
     @Override
@@ -254,8 +297,14 @@ public class DatabaseMetadataService implements 
MetadataService {
     }
 
     @Override
-    public FlowEntity getFlowById(final String flowIdentifier) {
-        return flowRepository.findOne(flowIdentifier);
+    public FlowEntity getFlowById(final String bucketIdentifier, final String 
flowIdentifier) {
+        FlowEntity flow = flowRepository.findOne(flowIdentifier);
+
+        if (flow.getBucket() == null || 
!bucketIdentifier.equals(flow.getBucket().getId())) {
+            return null;
+        }
+
+        return flow;
     }
 
     @Override
@@ -285,12 +334,18 @@ public class DatabaseMetadataService implements 
MetadataService {
 
     @Override
     public List<FlowEntity> getFlows(final QueryParameters params) {
+        return getFlows(params, null);
+    }
+
+    @Override
+    public List<FlowEntity> getFlows(final QueryParameters params, Set<String> 
bucketIds) {
+        Set<BucketEntity> filterBuckets = getBuckets(bucketIds);
         if (params.getNumRows() != null && params.getPageNum() != null) {
-            return getPagedFlows(params);
+            return getPagedFlows(params, filterBuckets);
         } else if (params.getSortParameters() != null && 
params.getSortParameters().size() > 0) {
-            return getSortedFlows(params);
+            return getSortedFlows(params, filterBuckets);
         } else {
-            return getAllFlows();
+            return getAllFlows(filterBuckets);
         }
     }
 
@@ -320,6 +375,20 @@ public class DatabaseMetadataService implements 
MetadataService {
         return flows;
     }
 
+    private List<FlowEntity> getAllFlows(Set<BucketEntity> buckets) {
+        return flowRepository.findByBucketIn(buckets);
+    }
+
+    private List<FlowEntity> getPagedFlows(final QueryParameters params, 
Set<BucketEntity> buckets) {
+        final Pageable pageable = getPageRequest(params);
+        return flowRepository.findByBucketIn(buckets, pageable);
+    }
+
+    private List<FlowEntity> getSortedFlows(final QueryParameters params, 
Set<BucketEntity> buckets) {
+        final Sort sort = getSort(params);
+        return flowRepository.findByBucketIn(buckets, sort);
+    }
+
     // 
------------------------------------------------------------------------------------
 
     @Override
@@ -329,9 +398,18 @@ public class DatabaseMetadataService implements 
MetadataService {
     }
 
     @Override
-    public FlowSnapshotEntity getFlowSnapshot(final String flowIdentifier, 
final Integer version) {
+    public FlowSnapshotEntity getFlowSnapshot(final String bucketIdentifier, 
final String flowIdentifier, final Integer version) {
         final FlowSnapshotEntityKey key = new 
FlowSnapshotEntityKey(flowIdentifier, version);
-        return flowSnapshotRepository.findOne(key);
+        FlowSnapshotEntity flowSnapshot = flowSnapshotRepository.findOne(key);
+
+        if (flowSnapshot == null
+                || flowSnapshot.getFlow() == null
+                || flowSnapshot.getFlow().getBucket() == null
+                || 
!bucketIdentifier.equals(flowSnapshot.getFlow().getBucket().getId())) {
+            return null;
+        }
+
+        return flowSnapshot;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketItemRepository.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketItemRepository.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketItemRepository.java
index 85d98ad..2f188e1 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketItemRepository.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketItemRepository.java
@@ -24,6 +24,7 @@ import org.springframework.data.domain.Sort;
 import org.springframework.data.repository.Repository;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * Repository for BucketItems that exposes only the methods from 
PagingAndSortingRepository.
@@ -81,4 +82,30 @@ public interface BucketItemRepository extends 
Repository<BucketItemEntity,String
      */
     List<BucketItemEntity> findByBucket(BucketEntity bucket, Pageable 
pageable);
 
+    /**
+     * Find all items by buckets.
+     *
+     * @param buckets the buckets to find items for
+     * @return the list of items for the buckets
+     */
+    List<BucketItemEntity> findByBucketIn(Set<BucketEntity> buckets);
+
+    /**
+     * Find all items by buckets with sorting.
+     *
+     * @param buckets the buckets to find items for
+     * @param sort the sort params
+     * @return the list of items for the buckets
+     */
+    List<BucketItemEntity> findByBucketIn(Set<BucketEntity> buckets, Sort 
sort);
+
+    /**
+     * Find all items by buckets with paging/sorting.
+     *
+     * @param buckets the buckets to find items for
+     * @param pageable the pageable params
+     * @return the list of items for the buckets based on the pageable params
+     */
+    List<BucketItemEntity> findByBucketIn(Set<BucketEntity> buckets, Pageable 
pageable);
+
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketRepository.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketRepository.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketRepository.java
index e917c2d..f7fb7fb 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketRepository.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/BucketRepository.java
@@ -20,6 +20,7 @@ import org.apache.nifi.registry.db.entity.BucketEntity;
 import org.springframework.data.repository.PagingAndSortingRepository;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * Spring Data Repository for BucketEntity.
@@ -28,4 +29,6 @@ public interface BucketRepository extends 
PagingAndSortingRepository<BucketEntit
 
     List<BucketEntity> findByNameIgnoreCase(String name);
 
+    List<BucketEntity> findByIdIn(Set<String> id);
+
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowRepository.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowRepository.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowRepository.java
index ac20f81..bfda5d0 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowRepository.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/repository/FlowRepository.java
@@ -16,10 +16,14 @@
  */
 package org.apache.nifi.registry.db.repository;
 
+import org.apache.nifi.registry.db.entity.BucketEntity;
 import org.apache.nifi.registry.db.entity.FlowEntity;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
 import org.springframework.data.repository.PagingAndSortingRepository;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * Spring Data Repository for FlowEntity.
@@ -28,4 +32,30 @@ public interface FlowRepository extends 
PagingAndSortingRepository<FlowEntity,St
 
     List<FlowEntity> findByNameIgnoreCase(String name);
 
+    /**
+     * Find all flows by buckets.
+     *
+     * @param buckets the buckets to find items for
+     * @return the list of items for the buckets
+     */
+    List<FlowEntity> findByBucketIn(Set<BucketEntity> buckets);
+
+    /**
+     * Find all flows by buckets with sorting.
+     *
+     * @param buckets the buckets to find flows for
+     * @param sort the sort params
+     * @return the list of flows for the buckets
+     */
+    List<FlowEntity> findByBucketIn(Set<BucketEntity> buckets, Sort sort);
+
+    /**
+     * Find all flows by buckets with paging/sorting.
+     *
+     * @param buckets the buckets to find flows for
+     * @param pageable the pageable params
+     * @return the list of flows for the buckets based on the pageable params
+     */
+    List<FlowEntity> findByBucketIn(Set<BucketEntity> buckets, Pageable 
pageable);
+
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/exception/AdministrationException.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/exception/AdministrationException.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/exception/AdministrationException.java
new file mode 100644
index 0000000..8f9180c
--- /dev/null
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/exception/AdministrationException.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.registry.exception;
+
+/**
+ *
+ */
+public class AdministrationException extends RuntimeException {
+
+    public AdministrationException(Throwable cause) {
+        super(cause);
+    }
+
+    public AdministrationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public AdministrationException(String message) {
+        super(message);
+    }
+
+    public AdministrationException() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/AuthorizationService.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/AuthorizationService.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/AuthorizationService.java
new file mode 100644
index 0000000..c62d170
--- /dev/null
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/AuthorizationService.java
@@ -0,0 +1,695 @@
+/*
+ * 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.registry.service;
+
+import org.apache.nifi.registry.authorization.AccessPolicyProvider;
+import 
org.apache.nifi.registry.authorization.AccessPolicyProviderInitializationContext;
+import org.apache.nifi.registry.authorization.AuthorizableLookup;
+import org.apache.nifi.registry.authorization.exception.AccessDeniedException;
+import 
org.apache.nifi.registry.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.registry.authorization.AuthorizeAccess;
+import org.apache.nifi.registry.authorization.Authorizer;
+import org.apache.nifi.registry.authorization.AuthorizerCapabilityDetection;
+import org.apache.nifi.registry.authorization.AuthorizerConfigurationContext;
+import 
org.apache.nifi.registry.authorization.exception.AuthorizerCreationException;
+import 
org.apache.nifi.registry.authorization.exception.AuthorizerDestructionException;
+import org.apache.nifi.registry.authorization.ConfigurableAccessPolicyProvider;
+import org.apache.nifi.registry.authorization.ConfigurableUserGroupProvider;
+import org.apache.nifi.registry.authorization.Group;
+import org.apache.nifi.registry.authorization.ManagedAuthorizer;
+import org.apache.nifi.registry.authorization.RequestAction;
+import org.apache.nifi.registry.authorization.UserAndGroups;
+import org.apache.nifi.registry.authorization.UserGroupProvider;
+import 
org.apache.nifi.registry.authorization.UserGroupProviderInitializationContext;
+import org.apache.nifi.registry.authorization.resource.ResourceFactory;
+import org.apache.nifi.registry.authorization.resource.ResourceType;
+import org.apache.nifi.registry.authorization.user.NiFiUserUtils;
+import org.apache.nifi.registry.bucket.Bucket;
+import org.apache.nifi.registry.model.authorization.AccessPolicy;
+import org.apache.nifi.registry.model.authorization.AccessPolicySummary;
+import org.apache.nifi.registry.model.authorization.Resource;
+import org.apache.nifi.registry.model.authorization.Tenant;
+import org.apache.nifi.registry.model.authorization.User;
+import org.apache.nifi.registry.model.authorization.UserGroup;
+import org.apache.nifi.registry.service.params.QueryParameters;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+
+@Service
+public class AuthorizationService {
+
+    public static final String MSG_NON_MANAGED_AUTHORIZER = "This NiFi 
Registry is not configured to internally manage users, groups, or policies. 
Please contact your system administrator.";
+    public static final String MSG_NON_CONFIGURABLE_POLICIES = "This NiFi 
Registry is not configured to allow configurable policies. Please contact your 
system administrator.";
+    public static final String MSG_NON_CONFIGURABLE_USERS = "This NiFi 
Registry is not configured to allow configurable users and groups. Please 
contact your system administrator.";
+
+    private AuthorizableLookup authorizableLookup;
+    private Authorizer authorizer;
+    private RegistryService registryService;
+    private UserGroupProvider userGroupProvider;
+    private AccessPolicyProvider accessPolicyProvider;
+
+    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+    private final Lock readLock = lock.readLock();
+    private final Lock writeLock = lock.writeLock();
+
+    @Autowired
+    public AuthorizationService(
+            final AuthorizableLookup authorizableLookup,
+            final Authorizer authorizer,
+            final RegistryService registryService) {
+        this.authorizableLookup = authorizableLookup;
+        this.authorizer = authorizer;
+        this.registryService = registryService;
+
+        if 
(AuthorizerCapabilityDetection.isManagedAuthorizer(this.authorizer)) {
+            this.accessPolicyProvider = ((ManagedAuthorizer) 
authorizer).getAccessPolicyProvider();
+        } else {
+            this.accessPolicyProvider = 
createExceptionThrowingAccessPolicyProvider();
+        }
+        this.userGroupProvider = accessPolicyProvider.getUserGroupProvider();
+    }
+
+
+    // ---------------------- Authorization methods 
-------------------------------------
+
+    public void authorizeAccess(final AuthorizeAccess authorizeAccess) {
+        authorizeAccess.authorize(authorizableLookup);
+    }
+
+
+    // ---------------------- Tenant methods 
--------------------------------------------
+
+    public Tenant getTenant(String identifier) {
+        this.readLock.lock();
+        try {
+            org.apache.nifi.registry.authorization.User user = 
userGroupProvider.getUser(identifier);
+            if (user != null) {
+                return tenantToDTO(user);
+            } else {
+                org.apache.nifi.registry.authorization.Group group = 
userGroupProvider.getGroup(identifier);
+                return tenantToDTO(group);
+            }
+        } finally {
+            this.readLock.unlock();
+        }
+    }
+
+
+    // ---------------------- User methods 
----------------------------------------------
+
+    public User createUser(User user) {
+        verifyUserGroupProviderIsConfigurable();
+        writeLock.lock();
+        try {
+            final org.apache.nifi.registry.authorization.User createdUser =
+                ((ConfigurableUserGroupProvider) 
userGroupProvider).addUser(userFromDTO(user));
+            return userToDTO(createdUser);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    public List<User> getUsers() {
+        this.readLock.lock();
+        try {
+            return 
userGroupProvider.getUsers().stream().map(this::userToDTO).collect(Collectors.toList());
+        } finally {
+            this.readLock.unlock();
+        }
+    }
+
+    public User getUser(String identifier) {
+        this.readLock.lock();
+        try {
+            return userToDTO(userGroupProvider.getUser(identifier));
+        } finally {
+            this.readLock.unlock();
+        }
+    }
+
+    public User updateUser(User user) {
+        verifyUserGroupProviderIsConfigurable();
+        this.writeLock.lock();
+        try {
+            final org.apache.nifi.registry.authorization.User updatedUser =
+                    ((ConfigurableUserGroupProvider) 
userGroupProvider).updateUser(userFromDTO(user));
+            return userToDTO(updatedUser);
+        } finally {
+            this.writeLock.unlock();
+        }
+    }
+
+    public User deleteUser(String identifier) {
+        verifyUserGroupProviderIsConfigurable();
+        this.writeLock.lock();
+        try {
+            User deletedUserDTO = getUser(identifier);
+            ((ConfigurableUserGroupProvider) 
userGroupProvider).deleteUser(identifier);
+            return deletedUserDTO;
+        } finally {
+            this.writeLock.unlock();
+        }
+    }
+
+
+    // ---------------------- User Group methods 
--------------------------------------
+
+    public UserGroup createUserGroup(UserGroup userGroup) {
+        verifyUserGroupProviderIsConfigurable();
+        writeLock.lock();
+        try {
+            final org.apache.nifi.registry.authorization.Group createdGroup =
+                    ((ConfigurableUserGroupProvider) 
userGroupProvider).addGroup(userGroupFromDTO(userGroup));
+            return userGroupToDTO(createdGroup);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    public List<UserGroup> getUserGroups() {
+        this.readLock.lock();
+        try {
+            return 
userGroupProvider.getGroups().stream().map(this::userGroupToDTO).collect(Collectors.toList());
+        } finally {
+            this.readLock.unlock();
+        }
+    }
+
+    public List<UserGroup> getUserGroupsForUser(String userIdentifier) {
+        this.readLock.lock();
+        try {
+            return userGroupProvider.getGroups()
+                    .stream()
+                    .filter(group -> group.getUsers().contains(userIdentifier))
+                    .map(this::userGroupToDTO)
+                    .collect(Collectors.toList());
+        } finally {
+            this.readLock.unlock();
+        }
+    }
+
+    public UserGroup getUserGroup(String identifier) {
+        this.readLock.lock();
+        try {
+            return userGroupToDTO(userGroupProvider.getGroup(identifier));
+        } finally {
+            this.readLock.unlock();
+        }
+    }
+
+    public UserGroup updateUserGroup(UserGroup userGroup) {
+        verifyUserGroupProviderIsConfigurable();
+        writeLock.lock();
+        try {
+            final org.apache.nifi.registry.authorization.Group updatedGroup =
+                    ((ConfigurableUserGroupProvider) 
userGroupProvider).updateGroup(userGroupFromDTO(userGroup));
+            return userGroupToDTO(updatedGroup);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    public UserGroup deleteUserGroup(String identifier) {
+        verifyUserGroupProviderIsConfigurable();
+        writeLock.lock();
+        try {
+            final UserGroup userGroupDTO = getUserGroup(identifier);
+            ((ConfigurableUserGroupProvider) 
userGroupProvider).deleteGroup(identifier);
+            return userGroupDTO;
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+
+    // ---------------------- Access Policy methods 
----------------------------------------
+
+    public AccessPolicy createAccessPolicy(AccessPolicy accessPolicy) {
+        verifyAccessPolicyProviderIsConfigurable();
+        writeLock.lock();
+        try {
+            org.apache.nifi.registry.authorization.AccessPolicy 
createdAccessPolicy =
+                    ((ConfigurableAccessPolicyProvider) 
accessPolicyProvider).addAccessPolicy(accessPolicyFromDTO(accessPolicy));
+            return accessPolicyToDTO(createdAccessPolicy);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    public AccessPolicy getAccessPolicy(String identifier) {
+        readLock.lock();
+        try {
+            return 
accessPolicyToDTO(accessPolicyProvider.getAccessPolicy(identifier));
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    public AccessPolicy getAccessPolicy(String resource, RequestAction action) 
{
+        readLock.lock();
+        try {
+            return 
accessPolicyToDTO(accessPolicyProvider.getAccessPolicy(resource, action));
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    public List<AccessPolicy> getAccessPolicies() {
+        readLock.lock();
+        try {
+            return 
accessPolicyProvider.getAccessPolicies().stream().map(this::accessPolicyToDTO).collect(Collectors.toList());
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    public List<AccessPolicySummary> getAccessPolicySummaries() {
+        readLock.lock();
+        try {
+            return 
accessPolicyProvider.getAccessPolicies().stream().map(this::accessPolicyToSummaryDTO).collect(Collectors.toList());
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    public List<AccessPolicy> getAccessPoliciesForUser(String userIdentifier) {
+        readLock.lock();
+        try {
+            return accessPolicyProvider.getAccessPolicies().stream()
+                    .filter(accessPolicy -> 
accessPolicy.getUsers().contains(userIdentifier))
+                    .map(this::accessPolicyToDTO)
+                    .collect(Collectors.toList());
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    public List<AccessPolicySummary> getAccessPolicySummariesForUser(String 
userIdentifier) {
+        readLock.lock();
+        try {
+            return accessPolicyProvider.getAccessPolicies().stream()
+                    .filter(accessPolicy -> 
accessPolicy.getUsers().contains(userIdentifier))
+                    .map(this::accessPolicyToSummaryDTO)
+                    .collect(Collectors.toList());
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    public List<AccessPolicySummary> 
getAccessPolicySummariesForUserGroup(String userGroupIdentifier) {
+        readLock.lock();
+        try {
+            return accessPolicyProvider.getAccessPolicies().stream()
+                    .filter(accessPolicy -> 
accessPolicy.getGroups().contains(userGroupIdentifier))
+                    .map(this::accessPolicyToSummaryDTO)
+                    .collect(Collectors.toList());
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    public AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) {
+        verifyAccessPolicyProviderIsConfigurable();
+        writeLock.lock();
+        try {
+            // Don't allow changing action or resource of existing policy 
(should only be adding/removing users/groups)
+            org.apache.nifi.registry.authorization.AccessPolicy 
currentAccessPolicy =
+                    
accessPolicyProvider.getAccessPolicy(accessPolicy.getIdentifier());
+            accessPolicy.setResource(currentAccessPolicy.getResource());
+            accessPolicy.setAction(currentAccessPolicy.getAction().toString());
+
+            org.apache.nifi.registry.authorization.AccessPolicy 
updateAccessPolicy =
+                    ((ConfigurableAccessPolicyProvider) 
accessPolicyProvider).updateAccessPolicy(accessPolicyFromDTO(accessPolicy));
+            return accessPolicyToDTO(updateAccessPolicy);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    public AccessPolicy deleteAccessPolicy(String identifier) {
+        verifyAccessPolicyProviderIsConfigurable();
+        writeLock.lock();
+        try {
+            AccessPolicy deletedAccessPolicyDTO = getAccessPolicy(identifier);
+            ((ConfigurableAccessPolicyProvider) 
accessPolicyProvider).deleteAccessPolicy(identifier);
+            return deletedAccessPolicyDTO;
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+
+    // ---------------------- Resource Lookup methods 
--------------------------------------
+
+    public List<Resource> getAuthorizedResources(RequestAction actionType, 
ResourceType resourceType) {
+        final List<Resource> authorizedResources =
+                getAllAuthorizableResources()
+                        .stream()
+                        .filter(resource -> {
+                            String resourceId = resource.getIdentifier();
+                            if (resourceType != null) {
+                                if 
(!resourceId.startsWith(resourceType.getValue())) {
+                                    return false;
+                                }
+                            }
+                            try {
+                                authorizableLookup
+                                        
.getAuthorizableByResource(resource.getIdentifier())
+                                        .authorize(authorizer, actionType, 
NiFiUserUtils.getNiFiUser());
+                            } catch (AccessDeniedException e) {
+                                return false;
+                            }
+                            return true;
+
+                        })
+                        .map(AuthorizationService::resourceToDTO)
+                        .collect(Collectors.toList());
+
+        return authorizedResources;
+    }
+
+    public List<Resource> getAuthorizedResources(RequestAction actionType) {
+        return getAuthorizedResources(actionType, null);
+    }
+
+    public List<Resource> getResources() {
+        final List<Resource> dtoResources =
+                getAllAuthorizableResources()
+                        .stream()
+                        .map(AuthorizationService::resourceToDTO)
+                        .collect(Collectors.toList());
+        return dtoResources;
+    }
+
+
+    // ---------------------- Private Helper methods 
--------------------------------------
+
+    private void verifyUserGroupProviderIsConfigurable() {
+        if (!(userGroupProvider instanceof ConfigurableUserGroupProvider)) {
+            throw new IllegalStateException(MSG_NON_CONFIGURABLE_USERS);
+        }
+    }
+
+    private void verifyAccessPolicyProviderIsConfigurable() {
+        if (!(accessPolicyProvider instanceof 
ConfigurableAccessPolicyProvider)) {
+            throw new IllegalStateException(MSG_NON_CONFIGURABLE_POLICIES);
+        }
+    }
+
+    private List<org.apache.nifi.registry.authorization.Resource> 
getAllAuthorizableResources() {
+        final List<org.apache.nifi.registry.authorization.Resource> resources 
= new ArrayList<>();
+        resources.add(ResourceFactory.getPoliciesResource());
+        resources.add(ResourceFactory.getTenantResource());
+        resources.add(ResourceFactory.getProxyResource());
+        resources.add(ResourceFactory.getResourceResource());
+
+        // add all buckets
+        resources.add(ResourceFactory.getBucketsResource());
+        for (final Bucket bucket : 
registryService.getBuckets(QueryParameters.EMPTY_PARAMETERS)) {
+            
resources.add(ResourceFactory.getChildResource(ResourceType.Bucket, 
bucket.getIdentifier(), bucket.getName()));
+        }
+
+        return resources;
+    }
+
+    private org.apache.nifi.registry.model.authorization.User userToDTO(
+            final org.apache.nifi.registry.authorization.User user) {
+        if (user == null) {
+            return null;
+        }
+        String userIdentifier = user.getIdentifier();
+        Collection<UserGroup> userGroups = 
getUserGroupsForUser(userIdentifier);
+        Collection<AccessPolicySummary> accessPolicySummaries = 
getAccessPolicySummariesForUser(userIdentifier);
+
+        return userToDTO(user, userGroups, accessPolicySummaries);
+    }
+
+    private org.apache.nifi.registry.model.authorization.UserGroup 
userGroupToDTO(
+            final org.apache.nifi.registry.authorization.Group userGroup) {
+        if (userGroup == null) {
+            return null;
+        }
+        Collection<Tenant> userTenants = userGroup.getUsers() != null
+                ? 
userGroup.getUsers().stream().map(this::getTenant).collect(Collectors.toSet()) 
: null;
+        Collection<AccessPolicySummary> accessPolicySummaries = 
getAccessPolicySummariesForUserGroup(userGroup.getIdentifier());
+
+        return userGroupToDTO(userGroup, userTenants, accessPolicySummaries);
+    }
+
+    private org.apache.nifi.registry.model.authorization.AccessPolicy 
accessPolicyToDTO(
+            final org.apache.nifi.registry.authorization.AccessPolicy 
accessPolicy) {
+        if (accessPolicy == null) {
+            return null;
+        }
+
+        Collection<Tenant> users = accessPolicy.getUsers() != null
+                ? 
accessPolicy.getUsers().stream().map(this::getTenant).collect(Collectors.toList())
 : null;
+        Collection<Tenant> userGroups = accessPolicy.getGroups() != null
+                ? 
accessPolicy.getGroups().stream().map(this::getTenant).collect(Collectors.toList())
 : null;
+
+        Boolean isConfigurable = 
AuthorizerCapabilityDetection.isAccessPolicyConfigurable(authorizer, 
accessPolicy);
+
+        return accessPolicyToDTO(accessPolicy, userGroups, users, 
isConfigurable);
+    }
+
+    private org.apache.nifi.registry.model.authorization.AccessPolicySummary 
accessPolicyToSummaryDTO(
+            final org.apache.nifi.registry.authorization.AccessPolicy 
accessPolicy) {
+        if (accessPolicy == null) {
+            return null;
+        }
+
+        Boolean isConfigurable = 
AuthorizerCapabilityDetection.isAccessPolicyConfigurable(authorizer, 
accessPolicy);
+
+        final AccessPolicySummary accessPolicySummaryDTO = new 
AccessPolicySummary();
+        accessPolicySummaryDTO.setIdentifier(accessPolicy.getIdentifier());
+        accessPolicySummaryDTO.setAction(accessPolicy.getAction().toString());
+        accessPolicySummaryDTO.setResource(accessPolicy.getResource());
+        accessPolicySummaryDTO.setConfigurable(isConfigurable);
+        return accessPolicySummaryDTO;
+    }
+
+    private static Resource 
resourceToDTO(org.apache.nifi.registry.authorization.Resource resource) {
+        if (resource == null) {
+            return null;
+        }
+        Resource resourceDto = new Resource();
+        resourceDto.setIdentifier(resource.getIdentifier());
+        resourceDto.setName(resource.getName());
+        return resourceDto;
+    }
+
+    private static Tenant 
tenantToDTO(org.apache.nifi.registry.authorization.User user) {
+        if (user == null) {
+            return null;
+        }
+        return new Tenant(user.getIdentifier(), user.getIdentity());
+    }
+
+    private static Tenant 
tenantToDTO(org.apache.nifi.registry.authorization.Group group) {
+        if (group == null) {
+            return null;
+        }
+        return new Tenant(group.getIdentifier(), group.getName());
+    }
+
+    private static org.apache.nifi.registry.authorization.User userFromDTO(
+            final org.apache.nifi.registry.model.authorization.User userDTO) {
+        if (userDTO == null) {
+            return null;
+        }
+        return new org.apache.nifi.registry.authorization.User.Builder()
+                .identifier(userDTO.getIdentifier() != null ? 
userDTO.getIdentifier() : UUID.randomUUID().toString())
+                .identity(userDTO.getIdentity())
+                .build();
+    }
+
+    private static org.apache.nifi.registry.model.authorization.User userToDTO(
+            final org.apache.nifi.registry.authorization.User user,
+            final Collection<? extends Tenant> userGroups,
+            final Collection<? extends AccessPolicySummary> accessPolicies) {
+
+        if (user == null) {
+            return null;
+        }
+        User userDTO = new User(user.getIdentifier(), user.getIdentity());
+        userDTO.addUserGroups(userGroups);
+        userDTO.addAccessPolicies(accessPolicies);
+        return userDTO;
+    }
+
+    private static org.apache.nifi.registry.authorization.Group 
userGroupFromDTO(
+            final org.apache.nifi.registry.model.authorization.UserGroup 
userGroupDTO) {
+        if (userGroupDTO == null) {
+            return null;
+        }
+        org.apache.nifi.registry.authorization.Group.Builder groupBuilder = 
new org.apache.nifi.registry.authorization.Group.Builder()
+                .identifier(userGroupDTO.getIdentifier() != null ? 
userGroupDTO.getIdentifier() : UUID.randomUUID().toString())
+                .name(userGroupDTO.getIdentity());
+        Set<Tenant> users = userGroupDTO.getUsers();
+        if (users != null) {
+            
groupBuilder.addUsers(users.stream().map(Tenant::getIdentifier).collect(Collectors.toSet()));
+        }
+        return groupBuilder.build();
+    }
+
+    private static org.apache.nifi.registry.model.authorization.UserGroup 
userGroupToDTO(
+            final org.apache.nifi.registry.authorization.Group userGroup,
+            final Collection<? extends Tenant> users,
+            final Collection<? extends AccessPolicySummary> accessPolicies) {
+        if (userGroup == null) {
+            return null;
+        }
+        UserGroup userGroupDTO = new UserGroup(userGroup.getIdentifier(), 
userGroup.getName());
+        userGroupDTO.addUsers(users);
+        userGroupDTO.addAccessPolicies(accessPolicies);
+        return userGroupDTO;
+    }
+
+    private static org.apache.nifi.registry.authorization.AccessPolicy 
accessPolicyFromDTO(
+            final org.apache.nifi.registry.model.authorization.AccessPolicy 
accessPolicyDTO) {
+        org.apache.nifi.registry.authorization.AccessPolicy.Builder 
accessPolicyBuilder =
+                new 
org.apache.nifi.registry.authorization.AccessPolicy.Builder()
+                        .identifier(accessPolicyDTO.getIdentifier() != null ? 
accessPolicyDTO.getIdentifier() : UUID.randomUUID().toString())
+                        .resource(accessPolicyDTO.getResource())
+                        
.action(RequestAction.valueOfValue(accessPolicyDTO.getAction()));
+
+        Set<Tenant> dtoUsers = accessPolicyDTO.getUsers();
+        if (accessPolicyDTO.getUsers() != null) {
+            
accessPolicyBuilder.addUsers(dtoUsers.stream().map(Tenant::getIdentifier).collect(Collectors.toSet()));
+        }
+
+        Set<Tenant> dtoUserGroups = accessPolicyDTO.getUserGroups();
+        if (dtoUserGroups != null) {
+            
accessPolicyBuilder.addGroups(dtoUserGroups.stream().map(Tenant::getIdentifier).collect(Collectors.toSet()));
+        }
+
+        return accessPolicyBuilder.build();
+    }
+
+    private static org.apache.nifi.registry.model.authorization.AccessPolicy 
accessPolicyToDTO(
+            final org.apache.nifi.registry.authorization.AccessPolicy 
accessPolicy,
+            final Collection<? extends Tenant> userGroups,
+            final Collection<? extends Tenant> users,
+            final Boolean isConfigurable) {
+
+        if (accessPolicy == null) {
+            return null;
+        }
+
+        final AccessPolicy accessPolicyDTO = new AccessPolicy();
+        accessPolicyDTO.setIdentifier(accessPolicy.getIdentifier());
+        accessPolicyDTO.setAction(accessPolicy.getAction().toString());
+        accessPolicyDTO.setResource(accessPolicy.getResource());
+        accessPolicyDTO.setConfigurable(isConfigurable);
+        accessPolicyDTO.addUsers(users);
+        accessPolicyDTO.addUserGroups(userGroups);
+        return accessPolicyDTO;
+    }
+
+    private static AccessPolicyProvider 
createExceptionThrowingAccessPolicyProvider() {
+
+        return new AccessPolicyProvider() {
+            @Override
+            public Set<org.apache.nifi.registry.authorization.AccessPolicy> 
getAccessPolicies() throws AuthorizationAccessException {
+                throw new IllegalStateException(MSG_NON_MANAGED_AUTHORIZER);
+            }
+
+            @Override
+            public org.apache.nifi.registry.authorization.AccessPolicy 
getAccessPolicy(String identifier) throws AuthorizationAccessException {
+                throw new IllegalStateException(MSG_NON_MANAGED_AUTHORIZER);
+            }
+
+            @Override
+            public org.apache.nifi.registry.authorization.AccessPolicy 
getAccessPolicy(String resourceIdentifier, RequestAction action) throws 
AuthorizationAccessException {
+                throw new IllegalStateException(MSG_NON_MANAGED_AUTHORIZER);
+            }
+
+            @Override
+            public UserGroupProvider getUserGroupProvider() {
+                return new UserGroupProvider() {
+                    @Override
+                    public Set<org.apache.nifi.registry.authorization.User> 
getUsers() throws AuthorizationAccessException {
+                        throw new 
IllegalStateException(MSG_NON_MANAGED_AUTHORIZER);
+                    }
+
+                    @Override
+                    public org.apache.nifi.registry.authorization.User 
getUser(String identifier) throws AuthorizationAccessException {
+                        throw new 
IllegalStateException(MSG_NON_MANAGED_AUTHORIZER);
+                    }
+
+                    @Override
+                    public org.apache.nifi.registry.authorization.User 
getUserByIdentity(String identity) throws AuthorizationAccessException {
+                        throw new 
IllegalStateException(MSG_NON_MANAGED_AUTHORIZER);
+                    }
+
+                    @Override
+                    public Set<Group> getGroups() throws 
AuthorizationAccessException {
+                        throw new 
IllegalStateException(MSG_NON_MANAGED_AUTHORIZER);
+                    }
+
+                    @Override
+                    public Group getGroup(String identifier) throws 
AuthorizationAccessException {
+                        throw new 
IllegalStateException(MSG_NON_MANAGED_AUTHORIZER);
+                    }
+
+                    @Override
+                    public UserAndGroups getUserAndGroups(String identity) 
throws AuthorizationAccessException {
+                        throw new 
IllegalStateException(MSG_NON_MANAGED_AUTHORIZER);
+                    }
+
+                    @Override
+                    public void 
initialize(UserGroupProviderInitializationContext initializationContext) throws 
AuthorizerCreationException {
+
+                    }
+
+                    @Override
+                    public void onConfigured(AuthorizerConfigurationContext 
configurationContext) throws AuthorizerCreationException {
+
+                    }
+
+                    @Override
+                    public void preDestruction() throws 
AuthorizerDestructionException {
+
+                    }
+                };
+            }
+
+            @Override
+            public void initialize(AccessPolicyProviderInitializationContext 
initializationContext) throws AuthorizerCreationException {
+            }
+
+            @Override
+            public void onConfigured(AuthorizerConfigurationContext 
configurationContext) throws AuthorizerCreationException {
+            }
+
+            @Override
+            public void preDestruction() throws AuthorizerDestructionException 
{
+            }
+        };
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
index 3c17cee..2a85c84 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/MetadataService.java
@@ -96,6 +96,15 @@ public interface MetadataService {
     List<BucketItemEntity> getBucketItems(QueryParameters queryParameters, 
BucketEntity bucket);
 
     /**
+     * Retrieves items for the given buckets.
+     *
+     * @param bucketIds the ids of buckets to retrieve items for
+     * @param queryParameters the parameters for retrieving the items, or null
+     * @return the set of items for the bucket
+     */
+    List<BucketItemEntity> getBucketItems(QueryParameters queryParameters, 
Set<String> bucketIds);
+
+    /**
      * Creates a versioned flow in the given bucket.
      *
      * @param flow the versioned flow to create
@@ -107,10 +116,11 @@ public interface MetadataService {
     /**
      * Retrieves the versioned flow with the given id.
      *
+     * @param bucketIdentifier the identifier of the bucket storing the flow
      * @param flowIdentifier the identifier of the flow to retrieve
      * @return the versioned flow with the given id, or null if no flow with 
the given id exists
      */
-    FlowEntity getFlowById(String flowIdentifier);
+    FlowEntity getFlowById(String bucketIdentifier, String flowIdentifier);
 
     /**
      * Retrieves the versioned flows with the given name. The name comparison 
must be case-insensitive.
@@ -144,6 +154,15 @@ public interface MetadataService {
     List<FlowEntity> getFlows(QueryParameters queryParameters);
 
     /**
+     * Retrieves items for the given buckets.
+     *
+     * @param bucketIds the ids of buckets to retrieve items for
+     * @param queryParameters the parameters for retrieving the items, or null
+     * @return the set of items for the bucket
+     */
+    List<FlowEntity> getFlows(QueryParameters queryParameters, Set<String> 
bucketIds);
+
+    /**
      * Creates a versioned flow snapshot.
      *
      * @param flowSnapshot the snapshot to create
@@ -155,11 +174,12 @@ public interface MetadataService {
     /**
      * Retrieves the snapshot for the given flow identifier and snapshot 
version.
      *
+     * @param bucketIdentifier the identifier of the bucket storign the flow
      * @param flowIdentifier the identifier of the flow the snapshot belongs to
      * @param version the version of the snapshot
      * @return the versioned flow snapshot for the given flow identifier and 
version, or null if none exists
      */
-    FlowSnapshotEntity getFlowSnapshot(String flowIdentifier, Integer version);
+    FlowSnapshotEntity getFlowSnapshot(String bucketIdentifier, String 
flowIdentifier, Integer version);
 
     /**
      * Deletes the flow snapshot.

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
index fc067e6..f0fc927 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
@@ -261,6 +261,21 @@ public class RegistryService {
         }
     }
 
+    public List<BucketItem> getBucketItems(final QueryParameters 
queryParameters, final Set<String> bucketIdentifiers) {
+        if (bucketIdentifiers == null || bucketIdentifiers.isEmpty()) {
+            throw new IllegalArgumentException("Bucket Identifiers cannot be 
null or empty");
+        }
+
+        readLock.lock();
+        try {
+            final List<BucketItem> bucketItems = new ArrayList<>();
+            metadataService.getBucketItems(queryParameters, 
bucketIdentifiers).stream().forEach(b -> addBucketItem(bucketItems, b));
+            return bucketItems;
+        } finally {
+            readLock.unlock();
+        }
+    }
+
     private void addBucketItem(final List<BucketItem> bucketItems, final 
BucketItemEntity itemEntity) {
         if (itemEntity instanceof FlowEntity) {
             final FlowEntity flowEntity = (FlowEntity) itemEntity;
@@ -326,14 +341,14 @@ public class RegistryService {
         }
     }
 
-    public VersionedFlow getFlow(final String flowIdentifier, final boolean 
verbose) {
+    public VersionedFlow getFlow(final String bucketIdentifier, final String 
flowIdentifier, final boolean verbose) {
         if (StringUtils.isBlank(flowIdentifier)) {
             throw new IllegalArgumentException("Flow Identifier cannot be null 
or blank");
         }
 
         readLock.lock();
         try {
-            final FlowEntity flowEntity = 
metadataService.getFlowById(flowIdentifier);
+            final FlowEntity flowEntity = 
metadataService.getFlowById(bucketIdentifier, flowIdentifier);
             if (flowEntity == null) {
                 throw new ResourceNotFoundException("VersionedFlow does not 
exist for identifier: " + flowIdentifier);
             }
@@ -375,6 +390,17 @@ public class RegistryService {
         }
     }
 
+    public List<VersionedFlow> getFlows(final QueryParameters queryParameters, 
final Set<String> bucketIds) {
+        readLock.lock();
+        try {
+            // return non-verbose set of all flows
+            final List<FlowEntity> flows = 
metadataService.getFlows(queryParameters, bucketIds);
+            return flows.stream().map(f -> DataModelMapper.map(f, 
false)).collect(Collectors.toList());
+        } finally {
+            readLock.unlock();
+        }
+    }
+
     public VersionedFlow updateFlow(final VersionedFlow versionedFlow) {
         if (versionedFlow == null) {
             throw new IllegalArgumentException("VersionedFlow cannot be null");
@@ -384,10 +410,14 @@ public class RegistryService {
             throw new IllegalArgumentException("VersionedFlow identifier 
cannot be null or blank");
         }
 
+        if (StringUtils.isBlank(versionedFlow.getBucketIdentifier())) {
+            throw new IllegalArgumentException("VersionedFlow bucket 
identifier cannot be null or blank");
+        }
+
         writeLock.lock();
         try {
             // ensure a flow with the given id exists
-            final FlowEntity existingFlow = 
metadataService.getFlowById(versionedFlow.getIdentifier());
+            final FlowEntity existingFlow = 
metadataService.getFlowById(versionedFlow.getBucketIdentifier(), 
versionedFlow.getIdentifier());
             if (existingFlow == null) {
                 throw new ResourceNotFoundException("VersionedFlow does not 
exist for identifier: " + versionedFlow.getIdentifier());
             }
@@ -422,7 +452,10 @@ public class RegistryService {
         }
     }
 
-    public VersionedFlow deleteFlow(final String flowIdentifier) {
+    public VersionedFlow deleteFlow(final String bucketIdentifier, final 
String flowIdentifier) {
+        if (StringUtils.isBlank(bucketIdentifier)) {
+            throw new IllegalArgumentException("Bucket Identifier cannot be 
null or blank");
+        }
         if (StringUtils.isBlank(flowIdentifier)) {
             throw new IllegalArgumentException("Flow Identifier cannot be null 
or blank");
         }
@@ -430,7 +463,7 @@ public class RegistryService {
         writeLock.lock();
         try {
             // ensure the flow exists
-            final FlowEntity existingFlow = 
metadataService.getFlowById(flowIdentifier);
+            final FlowEntity existingFlow = 
metadataService.getFlowById(bucketIdentifier, flowIdentifier);
             if (existingFlow == null) {
                 throw new ResourceNotFoundException("VersionedFlow does not 
exist for identifier: " + flowIdentifier);
             }
@@ -472,7 +505,7 @@ public class RegistryService {
             }
 
             // ensure the flow exists
-            final FlowEntity existingFlow = 
metadataService.getFlowById(snapshotMetadata.getFlowIdentifier());
+            final FlowEntity existingFlow = 
metadataService.getFlowById(snapshotMetadata.getBucketIdentifier(), 
snapshotMetadata.getFlowIdentifier());
             if (existingFlow == null) {
                 throw new ResourceNotFoundException("VersionedFlow does not 
exist for identifier: " + snapshotMetadata.getFlowIdentifier());
             }
@@ -518,9 +551,13 @@ public class RegistryService {
         }
     }
 
-    public VersionedFlowSnapshot getFlowSnapshot(final String flowIdentifier, 
final Integer version) {
+    public VersionedFlowSnapshot getFlowSnapshot(final String 
bucketIdentifier, final String flowIdentifier, final Integer version) {
+        if (StringUtils.isBlank(bucketIdentifier)) {
+            throw new IllegalArgumentException("Bucket identifier cannot be 
null or blank");
+        }
+
         if (StringUtils.isBlank(flowIdentifier)) {
-            throw new IllegalArgumentException("Flow Identifier cannot be null 
or blank");
+            throw new IllegalArgumentException("Flow identifier cannot be null 
or blank");
         }
 
         if (version == null) {
@@ -530,17 +567,13 @@ public class RegistryService {
         readLock.lock();
         try {
             // ensure the snapshot exists
-            final FlowSnapshotEntity snapshotEntity = 
metadataService.getFlowSnapshot(flowIdentifier, version);
+            final FlowSnapshotEntity snapshotEntity = 
metadataService.getFlowSnapshot(bucketIdentifier, flowIdentifier, version);
             if (snapshotEntity == null) {
                 throw new ResourceNotFoundException("VersionedFlowSnapshot 
does not exist for flow " + flowIdentifier + " and version " + version);
             }
 
-            final FlowEntity flow = snapshotEntity.getFlow();
-            final String flowId = flow.getId();
-            final String bucketId = flow.getBucket().getId();
-
             // get the serialized bytes of the snapshot
-            final byte[] serializedSnapshot = 
flowPersistenceProvider.getSnapshot(bucketId, flowId, version);
+            final byte[] serializedSnapshot = 
flowPersistenceProvider.getSnapshot(bucketIdentifier, flowIdentifier, version);
 
             if (serializedSnapshot == null || serializedSnapshot.length == 0) {
                 throw new IllegalStateException("No serialized content found 
for snapshot with flow identifier "
@@ -554,9 +587,13 @@ public class RegistryService {
         }
     }
 
-    public VersionedFlowSnapshotMetadata deleteFlowSnapshot(final String 
flowIdentifier, final Integer version) {
+    public VersionedFlowSnapshotMetadata deleteFlowSnapshot(final String 
bucketIdentifier, final String flowIdentifier, final Integer version) {
+        if (StringUtils.isBlank(bucketIdentifier)) {
+            throw new IllegalArgumentException("Bucket identifier cannot be 
null or blank");
+        }
+
         if (StringUtils.isBlank(flowIdentifier)) {
-            throw new IllegalArgumentException("Flow Identifier cannot be null 
or blank");
+            throw new IllegalArgumentException("Flow identifier cannot be null 
or blank");
         }
 
         if (version == null) {
@@ -566,18 +603,14 @@ public class RegistryService {
         writeLock.lock();
         try {
             // ensure the snapshot exists
-            final FlowSnapshotEntity snapshotEntity = 
metadataService.getFlowSnapshot(flowIdentifier, version);
+            final FlowSnapshotEntity snapshotEntity = 
metadataService.getFlowSnapshot(bucketIdentifier, flowIdentifier, version);
             if (snapshotEntity == null) {
                 throw new ResourceNotFoundException("VersionedFlowSnapshot 
does not exist for flow "
                         + flowIdentifier + " and version " + version);
             }
 
-            final FlowEntity flow = snapshotEntity.getFlow();
-            final String flowId = flow.getId();
-            final String bucketId = flow.getBucket().getId();
-
             // delete the content of the snapshot
-            flowPersistenceProvider.deleteSnapshot(bucketId, flowId, version);
+            flowPersistenceProvider.deleteSnapshot(bucketIdentifier, 
flowIdentifier, version);
 
             // delete the snapshot itself
             metadataService.deleteFlowSnapshot(snapshotEntity);

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/params/QueryParameters.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/params/QueryParameters.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/params/QueryParameters.java
index 3c62a9d..9f30f75 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/params/QueryParameters.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/params/QueryParameters.java
@@ -26,6 +26,8 @@ import java.util.List;
  */
 public class QueryParameters {
 
+    public static final QueryParameters EMPTY_PARAMETERS = new 
QueryParameters.Builder().build();
+
     private final Integer pageNum;
 
     private final Integer numRows;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/main/xsd/authorizers.xsd
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/main/xsd/authorizers.xsd 
b/nifi-registry-framework/src/main/xsd/authorizers.xsd
new file mode 100644
index 0000000..278ff09
--- /dev/null
+++ b/nifi-registry-framework/src/main/xsd/authorizers.xsd
@@ -0,0 +1,67 @@
+<?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";>
+
+    <!-- user group providers type -->
+    <xs:complexType name="UserGroupProvider">
+        <xs:sequence>
+            <xs:element name="identifier" type="xs:string"/>
+            <xs:element name="class" type="xs:string"/>
+            <xs:element name="property" type="Prop" minOccurs="0" 
maxOccurs="unbounded" />
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- access policy provider type -->
+    <xs:complexType name="AccessPolicyProvider">
+        <xs:sequence>
+            <xs:element name="identifier" type="xs:string"/>
+            <xs:element name="class" type="xs:string"/>
+            <xs:element name="property" type="Prop" minOccurs="0" 
maxOccurs="unbounded" />
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- authorizers type -->
+    <xs:complexType name="Authorizer">
+        <xs:sequence>
+            <xs:element name="identifier" type="xs:string"/>
+            <xs:element name="class" type="xs:string"/>
+            <xs:element name="classpath" type="xs:string" minOccurs="0"/>
+            <xs:element name="property" type="Prop" minOccurs="0" 
maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- Name/Value properties-->
+    <xs:complexType name="Prop">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="name" type="xs:string"></xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <!-- authorizers -->
+    <xs:element name="authorizers">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="userGroupProvider" type="UserGroupProvider" 
minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="accessPolicyProvider" 
type="AccessPolicyProvider" minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="authorizer" type="Authorizer" minOccurs="0" 
maxOccurs="unbounded"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+</xs:schema>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java
 
b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java
index d4b42cf..2efa320 100644
--- 
a/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java
+++ 
b/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/TestRegistryService.java
@@ -356,8 +356,8 @@ public class TestRegistryService {
 
     @Test(expected = ResourceNotFoundException.class)
     public void testGetFlowDoesNotExist() {
-        when(metadataService.getFlowById(any(String.class))).thenReturn(null);
-        registryService.getFlow("flow1", false);
+        when(metadataService.getFlowById(any(String.class), 
any(String.class))).thenReturn(null);
+        registryService.getFlow("bucket1","flow1", false);
     }
 
     @Test
@@ -376,9 +376,9 @@ public class TestRegistryService {
         flowEntity.setModified(new Date());
         flowEntity.setBucket(existingBucket);
 
-        
when(metadataService.getFlowById(flowEntity.getId())).thenReturn(flowEntity);
+        when(metadataService.getFlowById(existingBucket.getId(), 
flowEntity.getId())).thenReturn(flowEntity);
 
-        final VersionedFlow versionedFlow = 
registryService.getFlow(flowEntity.getId(), false);
+        final VersionedFlow versionedFlow = 
registryService.getFlow(existingBucket.getId(), flowEntity.getId(), false);
         assertNotNull(versionedFlow);
         assertEquals(flowEntity.getId(), versionedFlow.getIdentifier());
         assertEquals(flowEntity.getName(), versionedFlow.getName());
@@ -475,9 +475,10 @@ public class TestRegistryService {
     @Test(expected = ResourceNotFoundException.class)
     public void testUpdateFlowDoesNotExist() {
         final VersionedFlow versionedFlow = new VersionedFlow();
+        versionedFlow.setBucketIdentifier("b1");
         versionedFlow.setIdentifier("flow1");
 
-        
when(metadataService.getFlowById(versionedFlow.getIdentifier())).thenReturn(null);
+        when(metadataService.getFlowById(versionedFlow.getBucketIdentifier(), 
versionedFlow.getIdentifier())).thenReturn(null);
 
         registryService.updateFlow(versionedFlow);
     }
@@ -498,7 +499,7 @@ public class TestRegistryService {
         flowToUpdate.setModified(new Date());
         flowToUpdate.setBucket(existingBucket);
 
-        
when(metadataService.getFlowById(flowToUpdate.getId())).thenReturn(flowToUpdate);
+        when(metadataService.getFlowById(existingBucket.getId(), 
flowToUpdate.getId())).thenReturn(flowToUpdate);
 
         final FlowEntity otherFlow = new FlowEntity();
         otherFlow.setId("flow2");
@@ -512,6 +513,7 @@ public class TestRegistryService {
 
         final VersionedFlow versionedFlow = new VersionedFlow();
         versionedFlow.setIdentifier(flowToUpdate.getId());
+        versionedFlow.setBucketIdentifier(existingBucket.getId());
         versionedFlow.setName(otherFlow.getName());
 
         registryService.updateFlow(versionedFlow);
@@ -533,12 +535,13 @@ public class TestRegistryService {
         flowToUpdate.setModified(new Date());
         flowToUpdate.setBucket(existingBucket);
 
-        
when(metadataService.getFlowById(flowToUpdate.getId())).thenReturn(flowToUpdate);
+        when(metadataService.getFlowById(existingBucket.getId(), 
flowToUpdate.getId())).thenReturn(flowToUpdate);
         
when(metadataService.getFlowsByName(flowToUpdate.getName())).thenReturn(Collections.singletonList(flowToUpdate));
 
         
doAnswer(updateFlowAnswer()).when(metadataService).updateFlow(any(FlowEntity.class));
 
         final VersionedFlow versionedFlow = new VersionedFlow();
+        versionedFlow.setBucketIdentifier(flowToUpdate.getBucket().getId());
         versionedFlow.setIdentifier(flowToUpdate.getId());
         versionedFlow.setName("New Flow Name");
         versionedFlow.setDescription("This is a new description");
@@ -560,8 +563,8 @@ public class TestRegistryService {
 
     @Test(expected = ResourceNotFoundException.class)
     public void testDeleteFlowDoesNotExist() {
-        when(metadataService.getFlowById(any(String.class))).thenReturn(null);
-        registryService.deleteFlow("flow1");
+        when(metadataService.getFlowById(any(String.class), 
any(String.class))).thenReturn(null);
+        registryService.deleteFlow("b1", "flow1");
     }
 
     @Test
@@ -580,10 +583,10 @@ public class TestRegistryService {
         flowToDelete.setModified(new Date());
         flowToDelete.setBucket(existingBucket);
 
-        
when(metadataService.getFlowById(flowToDelete.getId())).thenReturn(flowToDelete);
+        when(metadataService.getFlowById(existingBucket.getId(), 
flowToDelete.getId())).thenReturn(flowToDelete);
         
when(metadataService.getFlowsByName(flowToDelete.getName())).thenReturn(Collections.singletonList(flowToDelete));
 
-        final VersionedFlow deletedFlow = 
registryService.deleteFlow(flowToDelete.getId());
+        final VersionedFlow deletedFlow = 
registryService.deleteFlow(existingBucket.getId(), flowToDelete.getId());
         assertNotNull(deletedFlow);
         assertEquals(flowToDelete.getId(), deletedFlow.getIdentifier());
 
@@ -662,7 +665,7 @@ public class TestRegistryService {
 
         
when(metadataService.getBucketById(existingBucket.getId())).thenReturn(existingBucket);
 
-        
when(metadataService.getFlowById(snapshot.getSnapshotMetadata().getFlowIdentifier())).thenReturn(null);
+        when(metadataService.getFlowById(existingBucket.getId(), 
snapshot.getSnapshotMetadata().getFlowIdentifier())).thenReturn(null);
 
         registryService.createFlowSnapshot(snapshot);
     }
@@ -701,7 +704,7 @@ public class TestRegistryService {
 
         existingFlow.setSnapshots(Collections.singleton(existingSnapshot));
 
-        
when(metadataService.getFlowById(existingFlow.getId())).thenReturn(existingFlow);
+        when(metadataService.getFlowById(existingBucket.getId(), 
existingFlow.getId())).thenReturn(existingFlow);
 
         registryService.createFlowSnapshot(snapshot);
     }
@@ -740,7 +743,7 @@ public class TestRegistryService {
 
         existingFlow.setSnapshots(Collections.singleton(existingSnapshot));
 
-        
when(metadataService.getFlowById(existingFlow.getId())).thenReturn(existingFlow);
+        when(metadataService.getFlowById(existingBucket.getId(), 
existingFlow.getId())).thenReturn(existingFlow);
 
         // set the version to something that is not the next one-up version
         snapshot.getSnapshotMetadata().setVersion(100);
@@ -768,7 +771,7 @@ public class TestRegistryService {
         existingFlow.setModified(new Date());
         existingFlow.setBucket(existingBucket);
 
-        
when(metadataService.getFlowById(existingFlow.getId())).thenReturn(existingFlow);
+        when(metadataService.getFlowById(existingBucket.getId(), 
existingFlow.getId())).thenReturn(existingFlow);
 
         final VersionedFlowSnapshot createdSnapshot = 
registryService.createFlowSnapshot(snapshot);
         assertNotNull(createdSnapshot);
@@ -799,7 +802,7 @@ public class TestRegistryService {
         existingFlow.setModified(new Date());
         existingFlow.setBucket(existingBucket);
 
-        
when(metadataService.getFlowById(existingFlow.getId())).thenReturn(existingFlow);
+        when(metadataService.getFlowById(existingBucket.getId(), 
existingFlow.getId())).thenReturn(existingFlow);
 
         // set the first version to something other than 1
         snapshot.getSnapshotMetadata().setVersion(100);
@@ -808,18 +811,20 @@ public class TestRegistryService {
 
     @Test(expected = ResourceNotFoundException.class)
     public void testGetSnapshotDoesNotExistInMetadataProvider() {
+        final String bucketId = "b1";
         final String flowId = "flow1";
         final Integer version = 1;
-        when(metadataService.getFlowSnapshot(flowId, 
version)).thenReturn(null);
-        registryService.getFlowSnapshot(flowId, version);
+        when(metadataService.getFlowSnapshot(bucketId, flowId, 
version)).thenReturn(null);
+        registryService.getFlowSnapshot(bucketId, flowId, version);
     }
 
     @Test(expected = IllegalStateException.class)
     public void testGetSnapshotDoesNotExistInPersistenceProvider() {
         final FlowSnapshotEntity existingSnapshot = createFlowSnapshotEntity();
         final FlowSnapshotEntityKey key = existingSnapshot.getId();
+        final String bucketId = existingSnapshot.getFlow().getBucket().getId();
 
-        when(metadataService.getFlowSnapshot(key.getFlowId(), 
key.getVersion())).thenReturn(existingSnapshot);
+        when(metadataService.getFlowSnapshot(bucketId, key.getFlowId(), 
key.getVersion())).thenReturn(existingSnapshot);
 
         when(flowPersistenceProvider.getSnapshot(
                 existingSnapshot.getFlow().getBucket().getId(),
@@ -827,15 +832,16 @@ public class TestRegistryService {
                 existingSnapshot.getId().getVersion()
         )).thenReturn(null);
 
-        registryService.getFlowSnapshot(existingSnapshot.getFlow().getId(), 
existingSnapshot.getId().getVersion());
+        registryService.getFlowSnapshot(bucketId, 
existingSnapshot.getFlow().getId(), existingSnapshot.getId().getVersion());
     }
 
     @Test
     public void testGetSnapshotExists() {
         final FlowSnapshotEntity existingSnapshot = createFlowSnapshotEntity();
         final FlowSnapshotEntityKey key = existingSnapshot.getId();
+        final String bucketId = existingSnapshot.getFlow().getBucket().getId();
 
-        when(metadataService.getFlowSnapshot(key.getFlowId(), 
key.getVersion()))
+        when(metadataService.getFlowSnapshot(bucketId, key.getFlowId(), 
key.getVersion()))
                 .thenReturn(existingSnapshot);
 
         // return a non-null, non-zero-length array so something gets passed 
to the serializer
@@ -849,27 +855,29 @@ public class TestRegistryService {
         
when(snapshotSerializer.deserialize(any(InputStream.class))).thenReturn(snapshotToDeserialize);
 
         final VersionedFlowSnapshot returnedSnapshot = 
registryService.getFlowSnapshot(
-                existingSnapshot.getFlow().getId(), 
existingSnapshot.getId().getVersion());
+                bucketId, existingSnapshot.getFlow().getId(), 
existingSnapshot.getId().getVersion());
         assertNotNull(returnedSnapshot);
     }
 
     @Test(expected = ResourceNotFoundException.class)
     public void testDeleteSnapshotDoesNotExist() {
+        final String bucketId = "b1";
         final String flowId = "flow1";
         final Integer version = 1;
-        when(metadataService.getFlowSnapshot(flowId, 
version)).thenReturn(null);
-        registryService.deleteFlowSnapshot(flowId, version);
+        when(metadataService.getFlowSnapshot(bucketId, flowId, 
version)).thenReturn(null);
+        registryService.deleteFlowSnapshot(bucketId, flowId, version);
     }
 
     @Test
     public void testDeleteSnapshotExists() {
         final FlowSnapshotEntity existingSnapshot = createFlowSnapshotEntity();
         final FlowSnapshotEntityKey key = existingSnapshot.getId();
+        final String bucketId = existingSnapshot.getFlow().getBucket().getId();
 
-        when(metadataService.getFlowSnapshot(key.getFlowId(), 
key.getVersion()))
+        when(metadataService.getFlowSnapshot(bucketId, key.getFlowId(), 
key.getVersion()))
                 .thenReturn(existingSnapshot);
 
-        final VersionedFlowSnapshotMetadata deletedSnapshot = 
registryService.deleteFlowSnapshot(key.getFlowId(), key.getVersion());
+        final VersionedFlowSnapshotMetadata deletedSnapshot = 
registryService.deleteFlowSnapshot(bucketId, key.getFlowId(), key.getVersion());
         assertNotNull(deletedSnapshot);
         assertEquals(existingSnapshot.getId().getFlowId(), 
deletedSnapshot.getFlowIdentifier());
 

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-jetty/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-jetty/pom.xml b/nifi-registry-jetty/pom.xml
index e47a354..8961ae1 100644
--- a/nifi-registry-jetty/pom.xml
+++ b/nifi-registry-jetty/pom.xml
@@ -30,11 +30,6 @@
             <version>0.0.1-SNAPSHOT</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.nifi.registry</groupId>
-            <artifactId>nifi-registry-security</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
-        </dependency>
-        <dependency>
             <groupId>org.eclipse.jetty</groupId>
             <artifactId>jetty-server</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java
 
b/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java
index 6aac4a6..b3ebf9d 100644
--- 
a/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java
+++ 
b/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java
@@ -17,7 +17,11 @@
 package org.apache.nifi.registry.properties;
 
 import java.io.File;
+import java.util.Enumeration;
+import java.util.HashSet;
 import java.util.Properties;
+import java.util.Set;
+
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,7 +47,11 @@ public class NiFiRegistryProperties extends Properties {
     public static final String SECURITY_TRUSTSTORE_TYPE = 
"nifi.registry.security.truststoreType";
     public static final String SECURITY_TRUSTSTORE_PASSWD = 
"nifi.registry.security.truststorePasswd";
     public static final String SECURITY_NEED_CLIENT_AUTH = 
"nifi.registry.security.needClientAuth";
-    public static final String SECURITY_AUTHORIZED_USERS = 
"nifi.registry.security.authorized.users";
+    public static final String SECURITY_AUTHORIZERS_CONFIGURATION_FILE = 
"nifi.registry.security.authorizers.configuration.file";
+    public static final String SECURITY_AUTHORIZER = 
"nifi.registry.security.authorizer";
+    public static final String SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX = 
"nifi.registry.security.identity.mapping.pattern.";
+    public static final String SECURITY_IDENTITY_MAPPING_VALUE_PREFIX = 
"nifi.registry.security.identity.mapping.value.";
+
 
     public static final String PROVIDERS_CONFIGURATION_FILE = 
"nifi.registry.providers.configuration.file";
 
@@ -54,6 +62,7 @@ public class NiFiRegistryProperties extends Properties {
     public static final String DEFAULT_WEB_WORKING_DIR = "./work/jetty";
     public static final String DEFAULT_WAR_DIR = "./lib";
     public static final String DEFAULT_PROVIDERS_CONFIGURATION_FILE = 
"./conf/providers.xml";
+    public static final String DEFAULT_SECURITY_AUTHORIZERS_CONFIGURATION_FILE 
= "./conf/authorizers.xml";
 
     public int getWebThreads() {
         int webThreads = 200;
@@ -142,14 +151,6 @@ public class NiFiRegistryProperties extends Properties {
         return new File(getProperty(WEB_WORKING_DIR, DEFAULT_WEB_WORKING_DIR));
     }
 
-    public File getAuthorizedUsersFile() {
-        final String authorizedUsersFile = 
getProperty(SECURITY_AUTHORIZED_USERS);
-        if (StringUtils.isBlank(authorizedUsersFile)) {
-            return null;
-        }
-        return new File(authorizedUsersFile);
-    }
-
     public File getProvidersConfigurationFile() {
         final String value = getProperty(PROVIDERS_CONFIGURATION_FILE);
         if (StringUtils.isBlank(value)) {
@@ -167,4 +168,28 @@ public class NiFiRegistryProperties extends Properties {
         return getProperty(DATABASE_URL_APPEND);
     }
 
+
+    public File getAuthorizersConfigurationFile() {
+        final String value = 
getProperty(SECURITY_AUTHORIZERS_CONFIGURATION_FILE);
+        if (StringUtils.isBlank(value)) {
+            return new File(DEFAULT_SECURITY_AUTHORIZERS_CONFIGURATION_FILE);
+        } else {
+            return new File(value);
+        }
+    }
+
+    /**
+     * Retrieves all known property keys.
+     *
+     * @return all known property keys
+     */
+    public Set<String> getPropertyKeys() {
+        Set<String> propertyNames = new HashSet<>();
+        Enumeration e = this.propertyNames();
+        for (; e.hasMoreElements(); ){
+            propertyNames.add((String) e.nextElement());
+        }
+
+        return propertyNames;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMapping.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMapping.java
 
b/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMapping.java
new file mode 100644
index 0000000..df3bbe6
--- /dev/null
+++ 
b/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMapping.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.registry.properties.util;
+
+import java.util.regex.Pattern;
+
+/**
+ * Holder to pass around the key, pattern, and replacement from an identity 
mapping in NiFiProperties.
+ */
+public class IdentityMapping {
+
+    private final String key;
+    private final Pattern pattern;
+    private final String replacementValue;
+
+    public IdentityMapping(String key, Pattern pattern, String 
replacementValue) {
+        this.key = key;
+        this.pattern = pattern;
+        this.replacementValue = replacementValue;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public Pattern getPattern() {
+        return pattern;
+    }
+
+    public String getReplacementValue() {
+        return replacementValue;
+    }
+
+}

Reply via email to