NIFIREG-58 Add current user permissions

For authorizable resources, such as tenants and buckets and bucket
items, add a permissions fields that indicates actions available to the
current user such as read, write, delete.

Adds permission details to the response of the GET /access endpoint
of the Web API that shows the available action to top level resources,
such as /buckets, /tenants, and /policies.

Add a configurable flag to tenants indicating if they are configurable
or read-only based on the Authorizer & UserGroupProvider that is
managing them.

This closes #43.

Signed-off-by: Bryan Bende <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/nifi-registry/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi-registry/commit/04cf2322
Tree: http://git-wip-us.apache.org/repos/asf/nifi-registry/tree/04cf2322
Diff: http://git-wip-us.apache.org/repos/asf/nifi-registry/diff/04cf2322

Branch: refs/heads/master
Commit: 04cf232206f5e67d37dbd263e6995d66be0dd7a0
Parents: a931858
Author: Kevin Doran <[email protected]>
Authored: Wed Nov 29 15:47:49 2017 -0500
Committer: Bryan Bende <[email protected]>
Committed: Mon Dec 11 10:12:16 2017 -0500

----------------------------------------------------------------------
 .../apache/nifi/registry/client/UserClient.java |  10 +-
 .../registry/client/impl/JerseyUserClient.java  |   6 +-
 .../org/apache/nifi/registry/bucket/Bucket.java |  24 +-
 .../apache/nifi/registry/bucket/BucketItem.java |  11 +
 .../authorization/AccessPolicySummary.java      |   2 +-
 .../model/authorization/AccessStatus.java       |  69 ----
 .../model/authorization/CurrentUser.java        |  96 ++++++
 .../model/authorization/Permissions.java        | 121 +++++++
 .../registry/model/authorization/Tenant.java    |  16 +-
 .../nifi/registry/model/authorization/User.java |   2 +-
 .../registry/model/authorization/UserGroup.java |   2 +-
 .../StandardAuthorizableLookup.java             |   5 +-
 .../authorization/resource/ResourceFactory.java |   3 +-
 .../ldap/tenants/LdapUserGroupProvider.java     |   2 +-
 .../registry/service/AuthorizationService.java  | 163 +++++----
 .../service/AuthorizationServiceSpec.groovy     |  36 --
 .../registry/web/api/AccessPolicyResource.java  |   2 +-
 .../nifi/registry/web/api/AccessResource.java   |  38 +--
 .../registry/web/api/BucketFlowResource.java    |  20 +-
 .../nifi/registry/web/api/BucketResource.java   |  62 +---
 .../nifi/registry/web/api/ItemResource.java     |   6 +
 .../security/NiFiRegistrySecurityConfig.java    |  35 +-
 .../web/security/PermissionsService.java        |  92 +++++
 .../apache/nifi/registry/web/api/BucketsIT.java |  21 +-
 .../apache/nifi/registry/web/api/FlowsIT.java   |  76 +----
 .../registry/web/api/IntegrationTestUtils.java  | 120 +++++++
 .../nifi/registry/web/api/SecureFileIT.java     |   9 +-
 .../nifi/registry/web/api/SecureKerberosIT.java |  44 ++-
 .../nifi/registry/web/api/SecureLdapIT.java     | 338 ++++++++++++++-----
 .../web/api/SecureNiFiRegistryClientIT.java     |  10 +-
 .../web/api/UnsecuredNiFiRegistryClientIT.java  |  12 +-
 31 files changed, 989 insertions(+), 464 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/UserClient.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/UserClient.java
 
b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/UserClient.java
index 5529f60..99ce08d 100644
--- 
a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/UserClient.java
+++ 
b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/UserClient.java
@@ -16,7 +16,7 @@
  */
 package org.apache.nifi.registry.client;
 
-import org.apache.nifi.registry.model.authorization.AccessStatus;
+import org.apache.nifi.registry.model.authorization.CurrentUser;
 
 import java.io.IOException;
 
@@ -31,12 +31,12 @@ public interface UserClient {
      * If the UserClient was obtained without proxied entities, then it would 
represent the identity of the certificate
      * in the keystore used by the client.
      *
-     * If the registry is not in secure mode, or if the user is unauthorized 
for any reason, an exception
-     * will be thrown.
+     * If the registry is not in secure mode, the anonymous identity is 
expected to be returned along with a flag indicating
+     * the user is anonymous.
      *
      * @return the access status of the current user
-     * @throws NiFiRegistryException if the user is unauthorized, or the 
proxying user is not a valid proxy, or nifi-registry is not secured
+     * @throws NiFiRegistryException if the proxying user is not a valid proxy 
or identity claim is otherwise invalid
      */
-    AccessStatus getAccessStatus() throws NiFiRegistryException, IOException;
+    CurrentUser getAccessStatus() throws NiFiRegistryException, IOException;
 
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyUserClient.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyUserClient.java
 
b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyUserClient.java
index b5c9770..1167266 100644
--- 
a/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyUserClient.java
+++ 
b/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/impl/JerseyUserClient.java
@@ -18,7 +18,7 @@ package org.apache.nifi.registry.client.impl;
 
 import org.apache.nifi.registry.client.NiFiRegistryException;
 import org.apache.nifi.registry.client.UserClient;
-import org.apache.nifi.registry.model.authorization.AccessStatus;
+import org.apache.nifi.registry.model.authorization.CurrentUser;
 
 import javax.ws.rs.client.WebTarget;
 import java.io.IOException;
@@ -39,9 +39,9 @@ public class JerseyUserClient extends AbstractJerseyClient 
implements UserClient
     }
 
     @Override
-    public AccessStatus getAccessStatus() throws NiFiRegistryException, 
IOException {
+    public CurrentUser getAccessStatus() throws NiFiRegistryException, 
IOException {
         return executeAction("Error retrieving access status for the current 
user", () -> {
-            return getRequestBuilder(accessTarget).get(AccessStatus.class);
+            return getRequestBuilder(accessTarget).get(CurrentUser.class);
         });
     }
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java
 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java
index 8bf1c8b..929972e 100644
--- 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java
+++ 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java
@@ -19,13 +19,12 @@ package org.apache.nifi.registry.bucket;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import org.apache.nifi.registry.link.LinkableEntity;
+import org.apache.nifi.registry.model.authorization.Permissions;
 
 import javax.validation.constraints.Min;
 import javax.validation.constraints.NotBlank;
 import javax.xml.bind.annotation.XmlRootElement;
-import java.util.HashSet;
 import java.util.Objects;
-import java.util.Set;
 
 @XmlRootElement
 @ApiModel(value = "bucket")
@@ -42,7 +41,7 @@ public class Bucket extends LinkableEntity {
 
     private String description;
 
-    private Set<String> authorizedActions;
+    private Permissions permissions;
 
     @ApiModelProperty("An ID to uniquely identify this object.")
     public String getIdentifier() {
@@ -80,22 +79,13 @@ public class Bucket extends LinkableEntity {
         this.description = description;
     }
 
-    @ApiModelProperty(value = "A list of actions the client is authorized to 
perform for this bucket.", readOnly = true)
-    public Set<String> getAuthorizedActions() {
-        return authorizedActions;
+    @ApiModelProperty(value = "The access that the current user has to this 
bucket.", readOnly = true)
+    public Permissions getPermissions() {
+        return permissions;
     }
 
-    public void setAuthorizedActions(Set<String> authorizedActions) {
-        this.authorizedActions = authorizedActions;
-    }
-
-    public void addAuthorizedAction(String action) {
-        if (action != null) {
-            if (this.authorizedActions == null) {
-                this.authorizedActions = new HashSet<>();
-            }
-            authorizedActions.add(action);
-        }
+    public void setPermissions(Permissions permissions) {
+        this.permissions = permissions;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java
 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java
index 9a96635..9d61a62 100644
--- 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java
+++ 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java
@@ -19,6 +19,7 @@ package org.apache.nifi.registry.bucket;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import org.apache.nifi.registry.link.LinkableEntity;
+import org.apache.nifi.registry.model.authorization.Permissions;
 
 import javax.validation.constraints.Min;
 import javax.validation.constraints.NotBlank;
@@ -51,6 +52,7 @@ public abstract class BucketItem extends LinkableEntity {
     @NotNull
     private final BucketItemType type;
 
+    private Permissions permissions;
 
     public BucketItem(final BucketItemType type) {
         this.type = type;
@@ -124,6 +126,15 @@ public abstract class BucketItem extends LinkableEntity {
         return type;
     }
 
+    @ApiModelProperty(value = "The access that the current user has to the 
bucket containing this item.", readOnly = true)
+    public Permissions getPermissions() {
+        return permissions;
+    }
+
+    public void setPermissions(Permissions permissions) {
+        this.permissions = permissions;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hashCode(this.getIdentifier());

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/AccessPolicySummary.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/AccessPolicySummary.java
 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/AccessPolicySummary.java
index e27fbd9..662c999 100644
--- 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/AccessPolicySummary.java
+++ 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/AccessPolicySummary.java
@@ -61,7 +61,7 @@ public class AccessPolicySummary {
         this.action = action;
     }
 
-    @ApiModelProperty("Indicates if this access policy is configurable, based 
on which authorizer has been configured to manage it.")
+    @ApiModelProperty(value = "Indicates if this access policy is 
configurable, based on which Authorizer has been configured to manage it.", 
readOnly = true)
     public Boolean getConfigurable() {
         return configurable;
     }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/AccessStatus.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/AccessStatus.java
 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/AccessStatus.java
deleted file mode 100644
index 2c66387..0000000
--- 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/AccessStatus.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.registry.model.authorization;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-
-@ApiModel("accessStatus")
-public class AccessStatus {
-
-    public static enum Status {
-        UNKNOWN,
-        ACTIVE
-    }
-
-    private String identity;
-    private Status status;
-    private String message;
-
-    @ApiModelProperty(
-            value = "The user identity.",
-            readOnly = true
-    )
-    public String getIdentity() {
-        return identity;
-    }
-
-    public void setIdentity(String identity) {
-        this.identity = identity;
-    }
-
-    @ApiModelProperty(
-            value = "The user access status.",
-            readOnly = true
-    )
-    public String getStatus() {
-        return status.toString();
-    }
-
-    public void setStatus(String status) {
-        this.status = Status.valueOf(status);
-    }
-
-    @ApiModelProperty(
-            value = "Additional details about the user access status.",
-            readOnly = true
-    )
-    public String getMessage() {
-        return message;
-    }
-
-    public void setMessage(String message) {
-        this.message = message;
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/CurrentUser.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/CurrentUser.java
 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/CurrentUser.java
new file mode 100644
index 0000000..7dbf932
--- /dev/null
+++ 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/CurrentUser.java
@@ -0,0 +1,96 @@
+/*
+ * 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.model.authorization;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel("currentUser")
+public class CurrentUser {
+
+    private String identity;
+    private boolean anonymous;
+
+    private Permissions administrationPermissions;
+    private Permissions bucketsPermissions;
+    private Permissions tenantsPermissions;
+    private Permissions policiesPermissions;
+    private Permissions resourcesPermissions;
+
+    @ApiModelProperty("The identity of the current user")
+    public String getIdentity() {
+        return identity;
+    }
+
+    public void setIdentity(String identity) {
+        this.identity = identity;
+    }
+
+    @ApiModelProperty("Indicates if the current user is anonymous")
+    public boolean isAnonymous() {
+        return anonymous;
+    }
+
+    public void setAnonymous(boolean anonymous) {
+        this.anonymous = anonymous;
+    }
+
+    @ApiModelProperty("The access that the current user has to the 
administration section of the NiFi Regsitry UI")
+    public Permissions getAdministrationPermissions() {
+        return administrationPermissions;
+    }
+
+    public void setAdministrationPermissions(Permissions 
administrationPermissions) {
+        this.administrationPermissions = administrationPermissions;
+    }
+
+    @ApiModelProperty("The access that the current user has to the top level 
/buckets resource of this NiFi Registry")
+    public Permissions getBucketsPermissions() {
+        return bucketsPermissions;
+    }
+
+    public void setBucketsPermissions(Permissions bucketsPermissions) {
+        this.bucketsPermissions = bucketsPermissions;
+    }
+
+    @ApiModelProperty("The access that the current user has to the top level 
/tenants resource of this NiFi Registry")
+    public Permissions getTenantsPermissions() {
+        return tenantsPermissions;
+    }
+
+    public void setTenantsPermissions(Permissions tenantsPermissions) {
+        this.tenantsPermissions = tenantsPermissions;
+    }
+
+    @ApiModelProperty("The access that the current user has to the top level 
/policies resource of this NiFi Registry")
+    public Permissions getPoliciesPermissions() {
+        return policiesPermissions;
+    }
+
+    public void setPoliciesPermissions(Permissions policiesPermissions) {
+        this.policiesPermissions = policiesPermissions;
+    }
+
+    @ApiModelProperty("The access that the current user has to the top level 
/resources resource of this NiFi Registry")
+    public Permissions getResourcesPermissions() {
+        return resourcesPermissions;
+    }
+
+    public void setResourcesPermissions(Permissions resourcesPermissions) {
+        this.resourcesPermissions = resourcesPermissions;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Permissions.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Permissions.java
 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Permissions.java
new file mode 100644
index 0000000..1dabc91
--- /dev/null
+++ 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Permissions.java
@@ -0,0 +1,121 @@
+/*
+ * 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.model.authorization;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel("permissions")
+public class Permissions {
+
+    private boolean canRead = false;
+    private boolean canWrite = false;
+    private boolean canDelete = false;
+
+    public Permissions() {
+    }
+
+    public Permissions(Permissions permissions) {
+        if (permissions == null) {
+            throw new IllegalArgumentException("Cannot call copy constructor 
with null argument");
+        }
+
+        this.canRead = permissions.getCanRead();
+        this.canWrite = permissions.getCanWrite();
+        this.canDelete = permissions.getCanDelete();
+    }
+
+    /**
+     * @return Indicates whether the user can read a given resource.
+     */
+    @ApiModelProperty(
+            value = "Indicates whether the user can read a given resource.",
+            readOnly = true
+    )
+    public boolean getCanRead() {
+        return canRead;
+    }
+
+    public void setCanRead(boolean canRead) {
+        this.canRead = canRead;
+    }
+
+    public Permissions withCanRead(boolean canRead) {
+        setCanRead(canRead);
+        return this;
+    }
+
+    /**
+     * @return Indicates whether the user can write a given resource.
+     */
+    @ApiModelProperty(
+            value = "Indicates whether the user can write a given resource.",
+            readOnly = true
+    )
+    public boolean getCanWrite() {
+        return canWrite;
+    }
+
+    public void setCanWrite(boolean canWrite) {
+        this.canWrite = canWrite;
+    }
+
+    public Permissions withCanWrite(boolean canWrite) {
+        setCanWrite(canWrite);
+        return this;
+    }
+
+    /**
+     * @return Indicates whether the user can delete a given resource.
+     */
+    @ApiModelProperty(
+            value = "Indicates whether the user can delete a given resource.",
+            readOnly = true
+    )
+    public boolean getCanDelete() {
+        return canDelete;
+    }
+
+    public void setCanDelete(boolean canDelete) {
+        this.canDelete = canDelete;
+    }
+
+    public Permissions withCanDelete(boolean canDelete) {
+        setCanDelete(canDelete);
+        return this;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Permissions that = (Permissions) o;
+
+        if (canRead != that.canRead) return false;
+        if (canWrite != that.canWrite) return false;
+        return canDelete == that.canDelete;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = (canRead ? 1 : 0);
+        result = 31 * result + (canWrite ? 1 : 0);
+        result = 31 * result + (canDelete ? 1 : 0);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java
 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java
index 87f1242..a40fc3e 100644
--- 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java
+++ 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java
@@ -31,6 +31,7 @@ public class Tenant {
 
     private String identifier;
     private String identity;
+    private Boolean configurable;
     private Set<AccessPolicySummary> accessPolicies;
 
     public Tenant() {}
@@ -43,7 +44,7 @@ public class Tenant {
     /**
      * @return tenant's unique identifier
      */
-    @ApiModelProperty(value = "The computer-generated identifier of the 
tenant.")
+    @ApiModelProperty(value = "The computer-generated identifier of the 
tenant.", readOnly = true)
     public String getIdentifier() {
         return identifier;
     }
@@ -55,7 +56,7 @@ public class Tenant {
     /**
      * @return tenant's identity
      */
-    @ApiModelProperty(value = "The identity provider's identity of the 
tenant.")
+    @ApiModelProperty(value = "The human-facing identity of the tenant. This 
can only be changed if the tenant is configurable.")
     public String getIdentity() {
         return identity;
     }
@@ -64,8 +65,17 @@ public class Tenant {
         this.identity = identity;
     }
 
+    @ApiModelProperty(value = "Indicates if this tenant is configurable, based 
on which UserGroupProvider has been configured to manage it.", readOnly = true)
+    public Boolean getConfigurable() {
+        return configurable;
+    }
+
+    public void setConfigurable(Boolean configurable) {
+        this.configurable = configurable;
+    }
+
     @ApiModelProperty(
-            value = "The access policies granted to this tenant. This field is 
read only",
+            value = "The access policies granted to this tenant.",
             readOnly = true
     )
     public Set<AccessPolicySummary> getAccessPolicies() {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java
 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java
index 449a274..a477401 100644
--- 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java
+++ 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java
@@ -35,7 +35,7 @@ public class User extends Tenant {
     }
 
     @ApiModelProperty(
-            value = "The groups to which the user belongs. This field is read 
only.",
+            value = "The groups to which the user belongs.",
             readOnly = true
     )
     public Set<Tenant> getUserGroups() {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java
 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java
index 4b14a20..1d59bdd 100644
--- 
a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java
+++ 
b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java
@@ -41,7 +41,7 @@ public class UserGroup extends Tenant {
     /**
      * @return The users that belong to this user group.
      */
-    @ApiModelProperty(value = "The users that belong to this user group.")
+    @ApiModelProperty(value = "The users that belong to this user group. This 
can only be changed if this group is configurable.")
     public Set<Tenant> getUsers() {
         return users;
     }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/StandardAuthorizableLookup.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/StandardAuthorizableLookup.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/StandardAuthorizableLookup.java
index af48908..dfd9adc 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/StandardAuthorizableLookup.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/StandardAuthorizableLookup.java
@@ -17,12 +17,11 @@
 package org.apache.nifi.registry.security.authorization;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.registry.security.authorization.Resource;
+import org.apache.nifi.registry.exception.ResourceNotFoundException;
+import 
org.apache.nifi.registry.security.authorization.resource.AccessPolicyAuthorizable;
 import org.apache.nifi.registry.security.authorization.resource.Authorizable;
 import 
org.apache.nifi.registry.security.authorization.resource.ResourceFactory;
 import org.apache.nifi.registry.security.authorization.resource.ResourceType;
-import 
org.apache.nifi.registry.security.authorization.resource.AccessPolicyAuthorizable;
-import org.apache.nifi.registry.exception.ResourceNotFoundException;
 import org.springframework.stereotype.Component;
 
 @Component

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/resource/ResourceFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/resource/ResourceFactory.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/resource/ResourceFactory.java
index c12256c..52c91c5 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/resource/ResourceFactory.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/resource/ResourceFactory.java
@@ -82,7 +82,7 @@ public final class ResourceFactory {
 
         @Override
         public String getName() {
-            return "NiFi Resources";
+            return "Resources";
         }
 
         @Override
@@ -126,7 +126,6 @@ public final class ResourceFactory {
         }
     };
 
-
     /**
      * Gets the Resource for proxying a user request.
      *

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java
 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java
index 976d575..9c97a8e 100644
--- 
a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java
+++ 
b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java
@@ -369,7 +369,7 @@ public class LdapUserGroupProvider implements 
UserGroupProvider {
             }
 
             // schedule the background thread to load the users/groups
-            ldapSync.scheduleWithFixedDelay(() -> load(context), syncInterval, 
syncInterval, TimeUnit.SECONDS);
+            ldapSync.scheduleWithFixedDelay(() -> load(context), syncInterval, 
syncInterval, TimeUnit.MILLISECONDS);
         } catch (final AuthorizationAccessException e) {
             throw new SecurityProviderCreationException(e);
         }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/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
index 79ba71c..6c380b1 100644
--- 
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
@@ -19,6 +19,8 @@ package org.apache.nifi.registry.service;
 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.CurrentUser;
+import org.apache.nifi.registry.model.authorization.Permissions;
 import org.apache.nifi.registry.model.authorization.Resource;
 import org.apache.nifi.registry.model.authorization.Tenant;
 import org.apache.nifi.registry.model.authorization.User;
@@ -40,8 +42,10 @@ import 
org.apache.nifi.registry.security.authorization.UserGroupProvider;
 import 
org.apache.nifi.registry.security.authorization.UserGroupProviderInitializationContext;
 import 
org.apache.nifi.registry.security.authorization.exception.AccessDeniedException;
 import 
org.apache.nifi.registry.security.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.registry.security.authorization.resource.Authorizable;
 import 
org.apache.nifi.registry.security.authorization.resource.ResourceFactory;
 import org.apache.nifi.registry.security.authorization.resource.ResourceType;
+import org.apache.nifi.registry.security.authorization.user.NiFiUser;
 import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils;
 import 
org.apache.nifi.registry.security.exception.SecurityProviderCreationException;
 import 
org.apache.nifi.registry.security.exception.SecurityProviderDestructionException;
@@ -99,24 +103,66 @@ public class AuthorizationService {
         authorizeAccess.authorize(authorizableLookup);
     }
 
+    // ---------------------- Permissions methods 
---------------------------------------
 
-    // ---------------------- Tenant methods 
--------------------------------------------
+    public CurrentUser getCurrentUser() {
+        final NiFiUser user = NiFiUserUtils.getNiFiUser();
+        final CurrentUser currentUser = new CurrentUser();
+        currentUser.setIdentity(user.getIdentity());
+        currentUser.setAnonymous(user.isAnonymous());
 
-    public Tenant getTenant(String identifier) {
-        this.readLock.lock();
-        try {
-            org.apache.nifi.registry.security.authorization.User user = 
userGroupProvider.getUser(identifier);
-            if (user != null) {
-                return tenantToDTO(user);
-            } else {
-                org.apache.nifi.registry.security.authorization.Group group = 
userGroupProvider.getGroup(identifier);
-                return tenantToDTO(group);
-            }
-        } finally {
-            this.readLock.unlock();
-        }
+        final Permissions bucketsPermissions = 
getPermissionsForResource(authorizableLookup.getBucketsAuthorizable());
+        currentUser.setBucketsPermissions(bucketsPermissions);
+
+        final Permissions policiesPermissions = 
getPermissionsForResource(authorizableLookup.getPoliciesAuthorizable());
+        currentUser.setPoliciesPermissions(policiesPermissions);
+
+        final Permissions tenantsPermissions = 
getPermissionsForResource(authorizableLookup.getTenantsAuthorizable());
+        currentUser.setTenantsPermissions(tenantsPermissions);
+
+        final Permissions resourcesPermissions = 
getPermissionsForResource(authorizableLookup.getResourcesAuthorizable());
+        currentUser.setResourcesPermissions(resourcesPermissions);
+
+        final Permissions administrationPermissions = new Permissions()
+                .withCanRead(bucketsPermissions.getCanRead() || 
tenantsPermissions.getCanRead() || policiesPermissions.getCanRead())
+                .withCanWrite(bucketsPermissions.getCanWrite() || 
tenantsPermissions.getCanWrite() || policiesPermissions.getCanWrite())
+                .withCanDelete(bucketsPermissions.getCanDelete() || 
tenantsPermissions.getCanDelete() || policiesPermissions.getCanDelete());
+        currentUser.setAdministrationPermissions(administrationPermissions);
+
+        return currentUser;
+    }
+
+    public Permissions getPermissionsForResource(Authorizable 
authorizableResource) {
+        NiFiUser user = NiFiUserUtils.getNiFiUser();
+        final Permissions permissions = new Permissions();
+        permissions.setCanRead(authorizableResource.isAuthorized(authorizer, 
RequestAction.READ, user));
+        permissions.setCanWrite(authorizableResource.isAuthorized(authorizer, 
RequestAction.WRITE, user));
+        permissions.setCanDelete(authorizableResource.isAuthorized(authorizer, 
RequestAction.DELETE, user));
+        return permissions;
     }
 
+    public Permissions getPermissionsForResource(Authorizable 
authorizableResource, Permissions knownParentAuthorizablePermissions) {
+        if (knownParentAuthorizablePermissions == null) {
+            return getPermissionsForResource(authorizableResource);
+        }
+
+        final Permissions permissions = new 
Permissions(knownParentAuthorizablePermissions);
+        NiFiUser user = NiFiUserUtils.getNiFiUser();
+
+        if (!permissions.getCanRead()) {
+            
permissions.setCanRead(authorizableResource.isAuthorized(authorizer, 
RequestAction.READ, user));
+        }
+
+        if (!permissions.getCanWrite()) {
+            
permissions.setCanWrite(authorizableResource.isAuthorized(authorizer, 
RequestAction.WRITE, user));
+        }
+
+        if (!permissions.getCanDelete()) {
+            
permissions.setCanDelete(authorizableResource.isAuthorized(authorizer, 
RequestAction.DELETE, user));
+        }
+
+        return permissions;
+    }
 
     // ---------------------- User methods 
----------------------------------------------
 
@@ -436,11 +482,15 @@ public class AuthorizationService {
 
         Collection<Tenant> groupsContainingUser = 
userGroupProvider.getGroups().stream()
                 .filter(group -> group.getUsers().contains(userIdentifier))
-                .map(AuthorizationService::tenantToDTO)
+                .map(this::tenantToDTO)
                 .collect(Collectors.toList());
         Collection<AccessPolicySummary> accessPolicySummaries = 
getAccessPolicySummariesForUser(userIdentifier);
 
-        return userToDTO(user, groupsContainingUser, accessPolicySummaries);
+        User userDTO = new User(user.getIdentifier(), user.getIdentity());
+        
userDTO.setConfigurable(AuthorizerCapabilityDetection.isUserConfigurable(authorizer,
 user));
+        userDTO.addUserGroups(groupsContainingUser);
+        userDTO.addAccessPolicies(accessPolicySummaries);
+        return userDTO;
     }
 
     private org.apache.nifi.registry.model.authorization.UserGroup 
userGroupToDTO(
@@ -448,11 +498,16 @@ public class AuthorizationService {
         if (userGroup == null) {
             return null;
         }
+
         Collection<Tenant> userTenants = userGroup.getUsers() != null
-                ? 
userGroup.getUsers().stream().map(this::getTenant).collect(Collectors.toSet()) 
: null;
+                ? 
userGroup.getUsers().stream().map(this::tenantIdToDTO).collect(Collectors.toSet())
 : null;
         Collection<AccessPolicySummary> accessPolicySummaries = 
getAccessPolicySummariesForUserGroup(userGroup.getIdentifier());
 
-        return userGroupToDTO(userGroup, userTenants, accessPolicySummaries);
+        UserGroup userGroupDTO = new UserGroup(userGroup.getIdentifier(), 
userGroup.getName());
+        
userGroupDTO.setConfigurable(AuthorizerCapabilityDetection.isGroupConfigurable(authorizer,
 userGroup));
+        userGroupDTO.addUsers(userTenants);
+        userGroupDTO.addAccessPolicies(accessPolicySummaries);
+        return userGroupDTO;
     }
 
     private org.apache.nifi.registry.model.authorization.AccessPolicy 
accessPolicyToDTO(
@@ -462,15 +517,30 @@ public class AuthorizationService {
         }
 
         Collection<Tenant> users = accessPolicy.getUsers() != null
-                ? 
accessPolicy.getUsers().stream().map(this::getTenant).filter(Objects::nonNull).collect(Collectors.toList())
 : null;
+                ? 
accessPolicy.getUsers().stream().map(this::tenantIdToDTO).filter(Objects::nonNull).collect(Collectors.toList())
 : null;
         Collection<Tenant> userGroups = accessPolicy.getGroups() != null
-                ? 
accessPolicy.getGroups().stream().map(this::getTenant).filter(Objects::nonNull).collect(Collectors.toList())
 : null;
+                ? 
accessPolicy.getGroups().stream().map(this::tenantIdToDTO).filter(Objects::nonNull).collect(Collectors.toList())
 : null;
 
         Boolean isConfigurable = 
AuthorizerCapabilityDetection.isAccessPolicyConfigurable(authorizer, 
accessPolicy);
 
         return accessPolicyToDTO(accessPolicy, userGroups, users, 
isConfigurable);
     }
 
+    private Tenant tenantIdToDTO(String identifier) {
+        this.readLock.lock();
+        try {
+            org.apache.nifi.registry.security.authorization.User user = 
userGroupProvider.getUser(identifier);
+            if (user != null) {
+                return tenantToDTO(user);
+            } else {
+                org.apache.nifi.registry.security.authorization.Group group = 
userGroupProvider.getGroup(identifier);
+                return tenantToDTO(group);
+            }
+        } finally {
+            this.readLock.unlock();
+        }
+    }
+
     private org.apache.nifi.registry.model.authorization.AccessPolicySummary 
accessPolicyToSummaryDTO(
             final org.apache.nifi.registry.security.authorization.AccessPolicy 
accessPolicy) {
         if (accessPolicy == null) {
@@ -487,28 +557,30 @@ public class AuthorizationService {
         return accessPolicySummaryDTO;
     }
 
-    private static Resource 
resourceToDTO(org.apache.nifi.registry.security.authorization.Resource 
resource) {
-        if (resource == null) {
+    private Tenant 
tenantToDTO(org.apache.nifi.registry.security.authorization.User user) {
+        if (user == null) {
             return null;
         }
-        Resource resourceDto = new Resource();
-        resourceDto.setIdentifier(resource.getIdentifier());
-        resourceDto.setName(resource.getName());
-        return resourceDto;
+        Tenant tenantDTO = new Tenant(user.getIdentifier(), 
user.getIdentity());
+        return tenantDTO;
     }
 
-    private static Tenant 
tenantToDTO(org.apache.nifi.registry.security.authorization.User user) {
-        if (user == null) {
+    private Tenant 
tenantToDTO(org.apache.nifi.registry.security.authorization.Group group) {
+        if (group == null) {
             return null;
         }
-        return new Tenant(user.getIdentifier(), user.getIdentity());
+        Tenant tenantDTO = new Tenant(group.getIdentifier(), group.getName());
+        return tenantDTO;
     }
 
-    private static Tenant 
tenantToDTO(org.apache.nifi.registry.security.authorization.Group group) {
-        if (group == null) {
+    private static Resource 
resourceToDTO(org.apache.nifi.registry.security.authorization.Resource 
resource) {
+        if (resource == null) {
             return null;
         }
-        return new Tenant(group.getIdentifier(), group.getName());
+        Resource resourceDto = new Resource();
+        resourceDto.setIdentifier(resource.getIdentifier());
+        resourceDto.setName(resource.getName());
+        return resourceDto;
     }
 
     private static org.apache.nifi.registry.security.authorization.User 
userFromDTO(
@@ -522,20 +594,6 @@ public class AuthorizationService {
                 .build();
     }
 
-    private static org.apache.nifi.registry.model.authorization.User userToDTO(
-            final org.apache.nifi.registry.security.authorization.User user,
-            final Collection<? extends Tenant> userGroups,
-            final Collection<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.security.authorization.Group 
userGroupFromDTO(
             final org.apache.nifi.registry.model.authorization.UserGroup 
userGroupDTO) {
         if (userGroupDTO == null) {
@@ -551,19 +609,6 @@ public class AuthorizationService {
         return groupBuilder.build();
     }
 
-    private static org.apache.nifi.registry.model.authorization.UserGroup 
userGroupToDTO(
-            final org.apache.nifi.registry.security.authorization.Group 
userGroup,
-            final Collection<? extends Tenant> users,
-            final Collection<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.security.authorization.AccessPolicy 
accessPolicyFromDTO(
             final org.apache.nifi.registry.model.authorization.AccessPolicy 
accessPolicyDTO) {
         org.apache.nifi.registry.security.authorization.AccessPolicy.Builder 
accessPolicyBuilder =

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-framework/src/test/groovy/org/apache/nifi/registry/service/AuthorizationServiceSpec.groovy
----------------------------------------------------------------------
diff --git 
a/nifi-registry-framework/src/test/groovy/org/apache/nifi/registry/service/AuthorizationServiceSpec.groovy
 
b/nifi-registry-framework/src/test/groovy/org/apache/nifi/registry/service/AuthorizationServiceSpec.groovy
index 93fd452..a7fa5eb 100644
--- 
a/nifi-registry-framework/src/test/groovy/org/apache/nifi/registry/service/AuthorizationServiceSpec.groovy
+++ 
b/nifi-registry-framework/src/test/groovy/org/apache/nifi/registry/service/AuthorizationServiceSpec.groovy
@@ -48,42 +48,6 @@ class AuthorizationServiceSpec extends Specification {
         authorizationService = new AuthorizationService(authorizableLookup, 
authorizer, registryService)
     }
 
-    // ----- Tenant tests -----------------------------------------------------
-
-    def "get tenant"() {
-
-        when: "get tenant for existing user identifier"
-        userGroupProvider.getUser("userId") >> new 
AuthUser.Builder().identifier("userId").identity("username").build()
-        def userResult = authorizationService.getTenant("userId")
-
-        then: "user with identifier is returned as DTO"
-        with(userResult) {
-            identifier == "userId"
-            identity == "username"
-        }
-
-
-        when: "get tenant for existing group identifier"
-        userGroupProvider.getGroup("groupId") >> new 
Group.Builder().identifier("groupId").name("groupname").build()
-        def groupResult = authorizationService.getTenant("groupId")
-
-        then: "group with identifier is returned as DTO"
-        with(groupResult) {
-            identifier == "groupId"
-            identity == "groupname"
-        }
-
-
-        when: "get tenant for non-existent identifier"
-        userGroupProvider.getUser("id") >> null
-        userGroupProvider.getGroup("id") >> null
-        def result = authorizationService.getTenant("id")
-
-        then: "null is returned"
-        result == null
-
-    }
-
     // ----- User tests -------------------------------------------------------
 
     def "create user"() {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java
 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java
index b9cfbb9..84cc555 100644
--- 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java
+++ 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java
@@ -271,7 +271,7 @@ public class AccessPolicyResource extends 
AuthorizableApplicationResource {
         AccessPolicy createdPolicy = 
authorizationService.updateAccessPolicy(requestAccessPolicy);
 
         String locationUri = generateAccessPolicyUri(createdPolicy);
-        return generateCreatedResponse(URI.create(locationUri), 
createdPolicy).build();
+        return generateOkResponse(createdPolicy).build();
     }
 
 

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java
 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java
index 02bc3db..187f976 100644
--- 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java
+++ 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java
@@ -23,7 +23,7 @@ import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.registry.exception.AdministrationException;
-import org.apache.nifi.registry.model.authorization.AccessStatus;
+import org.apache.nifi.registry.model.authorization.CurrentUser;
 import org.apache.nifi.registry.properties.NiFiRegistryProperties;
 import org.apache.nifi.registry.security.authentication.AuthenticationRequest;
 import org.apache.nifi.registry.security.authentication.AuthenticationResponse;
@@ -34,6 +34,7 @@ import 
org.apache.nifi.registry.security.authentication.exception.IdentityAccess
 import 
org.apache.nifi.registry.security.authentication.exception.InvalidCredentialsException;
 import org.apache.nifi.registry.security.authorization.user.NiFiUser;
 import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils;
+import org.apache.nifi.registry.service.AuthorizationService;
 import org.apache.nifi.registry.web.exception.UnauthorizedException;
 import org.apache.nifi.registry.web.security.authentication.jwt.JwtService;
 import 
org.apache.nifi.registry.web.security.authentication.kerberos.KerberosSpnegoIdentityProvider;
@@ -51,6 +52,7 @@ import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -71,6 +73,7 @@ public class AccessResource extends ApplicationResource {
     private static final Logger logger = 
LoggerFactory.getLogger(AccessResource.class);
 
     private NiFiRegistryProperties properties;
+    private AuthorizationService authorizationService;
     private JwtService jwtService;
     private X509IdentityProvider x509IdentityProvider;
     private KerberosSpnegoIdentityProvider kerberosSpnegoIdentityProvider;
@@ -79,6 +82,7 @@ public class AccessResource extends ApplicationResource {
     @Autowired
     public AccessResource(
             NiFiRegistryProperties properties,
+            AuthorizationService authorizationService,
             JwtService jwtService,
             X509IdentityProvider x509IdentityProvider,
             @Nullable KerberosSpnegoIdentityProvider 
kerberosSpnegoIdentityProvider,
@@ -88,43 +92,35 @@ public class AccessResource extends ApplicationResource {
         this.x509IdentityProvider = x509IdentityProvider;
         this.kerberosSpnegoIdentityProvider = kerberosSpnegoIdentityProvider;
         this.identityProvider = identityProvider;
+        this.authorizationService = authorizationService;
     }
 
     /**
-     * Gets the status the client's access.
+     * Gets the current client's identity and authorized permissions.
      *
      * @param httpServletRequest the servlet request
-     * @return A accessStatusEntity
+     * @return An object describing the current client identity, as determined 
by the server, and it's permissions.
      */
     @GET
     @Consumes(MediaType.WILDCARD)
     @Produces(MediaType.APPLICATION_JSON)
     @ApiOperation(
-            value = "Gets the status the client's access",
-            response = AccessStatus.class
+            value = "Returns the current client's authenticated identity and 
permissions to top-level resources",
+            response = CurrentUser.class
     )
     @ApiResponses({
             @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409 
+ " The NiFi Registry might be running unsecured.") })
     public Response getAccessStatus(@Context HttpServletRequest 
httpServletRequest) {
-        // only consider user specific access over https
-        if (!httpServletRequest.isSecure()) {
-            throw new IllegalStateException("User authentication/authorization 
is only supported when running over HTTPS.");
-        }
 
-        final AccessStatus accessStatus = new AccessStatus();
-
-        NiFiUser currentUser = NiFiUserUtils.getNiFiUser();
-        if (currentUser == null || currentUser.getIdentity() == null || 
currentUser.isAnonymous()) {
-            accessStatus.setStatus(AccessStatus.Status.UNKNOWN.name());
-            accessStatus.setMessage("No credentials supplied, unknown user.");
-        } else {
-            final String identity = currentUser.getIdentity();
-            accessStatus.setIdentity(identity);
-            accessStatus.setStatus(AccessStatus.Status.ACTIVE.name());
-            accessStatus.setMessage("You are logged in.");
+        final NiFiUser user = NiFiUserUtils.getNiFiUser();
+        if (user == null) {
+            // Not expected to happen unless the nifi registry server has been 
seriously misconfigured.
+            throw new WebApplicationException(new Throwable("Unable to access 
details for current user."));
         }
 
-        return generateOkResponse(accessStatus).build();
+        final CurrentUser currentUser = authorizationService.getCurrentUser();
+
+        return generateOkResponse(currentUser).build();
     }
 
 

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
index 2b10919..4cd0727 100644
--- 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
+++ 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
@@ -35,6 +35,7 @@ import org.apache.nifi.registry.service.RegistryService;
 import org.apache.nifi.registry.service.QueryParameters;
 import org.apache.nifi.registry.params.SortParameter;
 import org.apache.nifi.registry.web.link.LinkService;
+import org.apache.nifi.registry.web.security.PermissionsService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -68,16 +69,19 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
 
     private final RegistryService registryService;
     private final LinkService linkService;
+    private final PermissionsService permissionsService;
 
     @Autowired
     public BucketFlowResource(
             final RegistryService registryService,
             final LinkService linkService,
+            final PermissionsService permissionsService,
             final AuthorizationService authorizationService,
             final Authorizer authorizer) {
         super(authorizer, authorizationService);
         this.registryService = registryService;
         this.linkService = linkService;
+        this.permissionsService =permissionsService;
     }
 
     @POST
@@ -102,6 +106,7 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
         authorizeBucketAccess(RequestAction.WRITE, bucketId);
         verifyPathParamsMatchBody(bucketId, flow);
         final VersionedFlow createdFlow = registryService.createFlow(bucketId, 
flow);
+        permissionsService.populateItemPermissions(createdFlow);
         linkService.populateFlowLinks(createdFlow);
         return Response.status(Response.Status.OK).entity(createdFlow).build();
     }
@@ -136,6 +141,7 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
         }
 
         final List<VersionedFlow> flows = registryService.getFlows(bucketId);
+        permissionsService.populateItemPermissions(flows);
         linkService.populateFlowLinks(flows);
 
         return Response.status(Response.Status.OK).entity(flows).build();
@@ -166,6 +172,7 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
         authorizeBucketAccess(RequestAction.READ, bucketId);
 
         final VersionedFlow flow = registryService.getFlow(bucketId, flowId);
+        permissionsService.populateItemPermissions(flow);
         linkService.populateFlowLinks(flow);
 
         return Response.status(Response.Status.OK).entity(flow).build();
@@ -200,6 +207,7 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
         authorizeBucketAccess(RequestAction.WRITE, bucketId);
 
         final VersionedFlow updatedFlow = registryService.updateFlow(flow);
+        permissionsService.populateItemPermissions(updatedFlow);
         linkService.populateFlowLinks(updatedFlow);
 
         return Response.status(Response.Status.OK).entity(updatedFlow).build();
@@ -267,6 +275,10 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
         if (createdSnapshot.getSnapshotMetadata() != null) {
             
linkService.populateSnapshotLinks(createdSnapshot.getSnapshotMetadata());
         }
+        if (createdSnapshot.getBucket() != null) {
+            
permissionsService.populateBucketPermissions(createdSnapshot.getBucket());
+            linkService.populateBucketLinks(createdSnapshot.getBucket());
+        }
         return 
Response.status(Response.Status.OK).entity(createdSnapshot).build();
     }
 
@@ -331,7 +343,7 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
         }
 
         final VersionedFlowSnapshot lastSnapshot = 
registryService.getFlowSnapshot(bucketId, flowId, latest.getVersion());
-        populateLinks(lastSnapshot);
+        populateLinksAndPermissions(lastSnapshot);
 
         return 
Response.status(Response.Status.OK).entity(lastSnapshot).build();
     }
@@ -365,6 +377,7 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
         }
 
         linkService.populateSnapshotLinks(latest);
+
         return Response.status(Response.Status.OK).entity(latest).build();
     }
 
@@ -395,12 +408,12 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
         authorizeBucketAccess(RequestAction.READ, bucketId);
 
         final VersionedFlowSnapshot snapshot = 
registryService.getFlowSnapshot(bucketId, flowId, versionNumber);
-        populateLinks(snapshot);
+        populateLinksAndPermissions(snapshot);
 
         return Response.status(Response.Status.OK).entity(snapshot).build();
     }
 
-    private void populateLinks(VersionedFlowSnapshot snapshot) {
+    private void populateLinksAndPermissions(VersionedFlowSnapshot snapshot) {
         if (snapshot.getSnapshotMetadata() != null) {
             linkService.populateSnapshotLinks(snapshot.getSnapshotMetadata());
         }
@@ -410,6 +423,7 @@ public class BucketFlowResource extends 
AuthorizableApplicationResource {
         }
 
         if (snapshot.getBucket() != null) {
+            permissionsService.populateBucketPermissions(snapshot.getBucket());
             linkService.populateBucketLinks(snapshot.getBucket());
         }
 

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
index e9e4d8b..82bb172 100644
--- 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
+++ 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
@@ -35,6 +35,7 @@ import org.apache.nifi.registry.service.AuthorizationService;
 import org.apache.nifi.registry.service.QueryParameters;
 import org.apache.nifi.registry.service.RegistryService;
 import org.apache.nifi.registry.web.link.LinkService;
+import org.apache.nifi.registry.web.security.PermissionsService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -55,9 +56,6 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.EnumSet;
 import java.util.List;
 import java.util.Set;
 
@@ -79,15 +77,19 @@ public class BucketResource extends 
AuthorizableApplicationResource {
 
     private final RegistryService registryService;
 
+    private final PermissionsService permissionsService;
+
     @Autowired
     public BucketResource(
             final RegistryService registryService,
             final LinkService linkService,
+            final PermissionsService permissionsService,
             final AuthorizationService authorizationService,
             final Authorizer authorizer) {
         super(authorizer, authorizationService);
         this.registryService = registryService;
         this.linkService = linkService;
+        this.permissionsService = permissionsService;
     }
 
     @POST
@@ -104,7 +106,7 @@ public class BucketResource extends 
AuthorizableApplicationResource {
     public Response createBucket(final Bucket bucket) {
         authorizeAccess(RequestAction.WRITE);
         final Bucket createdBucket = registryService.createBucket(bucket);
-        populateBucketAuthorizedActions(createdBucket, RequestAction.WRITE);
+        permissionsService.populateBucketPermissions(createdBucket);
         linkService.populateBucketLinks(createdBucket);
         return 
Response.status(Response.Status.OK).entity(createdBucket).build();
     }
@@ -139,7 +141,7 @@ public class BucketResource extends 
AuthorizableApplicationResource {
         }
 
         final List<Bucket> buckets = 
registryService.getBuckets(paramsBuilder.build(), authorizedBucketIds);
-        populateBucketAuthorizedActions(buckets, RequestAction.READ);
+        permissionsService.populateBucketPermissions(buckets);
         linkService.populateBucketLinks(buckets);
 
         return Response.status(Response.Status.OK).entity(buckets).build();
@@ -164,7 +166,7 @@ public class BucketResource extends 
AuthorizableApplicationResource {
 
         authorizeBucketAccess(RequestAction.READ, bucketId);
         final Bucket bucket = registryService.getBucket(bucketId);
-        populateBucketAuthorizedActions(bucket, RequestAction.READ);
+        permissionsService.populateBucketPermissions(bucket);
         linkService.populateBucketLinks(bucket);
 
         return Response.status(Response.Status.OK).entity(bucket).build();
@@ -206,7 +208,7 @@ public class BucketResource extends 
AuthorizableApplicationResource {
         authorizeBucketAccess(RequestAction.WRITE, bucketId);
 
         final Bucket updatedBucket = registryService.updateBucket(bucket);
-        populateBucketAuthorizedActions(updatedBucket, RequestAction.WRITE);
+        permissionsService.populateBucketPermissions(updatedBucket);
         linkService.populateBucketLinks(updatedBucket);
         return 
Response.status(Response.Status.OK).entity(updatedBucket).build();
     }
@@ -258,50 +260,4 @@ public class BucketResource extends 
AuthorizableApplicationResource {
         });
     }
 
-    private void populateBucketAuthorizedActions(Collection<Bucket> buckets, 
RequestAction... knownAuthorizedActions) {
-
-        EnumSet<RequestAction> knownActions = 
EnumSet.noneOf(RequestAction.class);
-        knownActions.addAll(Arrays.asList(knownAuthorizedActions));
-
-        EnumSet<RequestAction> unknownActions = 
EnumSet.allOf(RequestAction.class);
-        unknownActions.removeAll(knownActions);
-
-        // if the user has an authorized action on the top-level /buckets 
resource, that applies to all buckets
-        for (RequestAction action : unknownActions) {
-            try {
-                authorizeAccess(action);
-                knownActions.add(action);
-            } catch (AccessDeniedException e) {
-                // not authorized, do nothing
-            }
-        }
-
-        // now for each bucket, add the known actions and check if the user 
has additional authorized actions for that bucket
-        for (Bucket bucket : buckets) {
-            populateBucketAuthorizedActions(bucket, knownAuthorizedActions);
-        }
-    }
-
-    private void populateBucketAuthorizedActions(Bucket bucket, 
RequestAction... knownAuthorizedActions) {
-
-        EnumSet<RequestAction> knownActions = 
EnumSet.noneOf(RequestAction.class);
-        knownActions.addAll(Arrays.asList(knownAuthorizedActions));
-
-        EnumSet<RequestAction> unknownActions = 
EnumSet.allOf(RequestAction.class);
-        unknownActions.removeAll(knownActions);
-
-        for (RequestAction action : knownAuthorizedActions) {
-            bucket.addAuthorizedAction(action.toString());
-        }
-
-        for (RequestAction action : unknownActions) {
-            try {
-                authorizeBucketAccess(action, bucket.getIdentifier());
-                bucket.addAuthorizedAction(action.toString());
-            } catch (AccessDeniedException e) {
-                // not authorized, do nothing
-            }
-        }
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java
 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java
index 5702540..3e839f0 100644
--- 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java
+++ 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java
@@ -28,6 +28,7 @@ import org.apache.nifi.registry.service.AuthorizationService;
 import org.apache.nifi.registry.service.QueryParameters;
 import org.apache.nifi.registry.service.RegistryService;
 import org.apache.nifi.registry.web.link.LinkService;
+import org.apache.nifi.registry.web.security.PermissionsService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -61,17 +62,20 @@ public class ItemResource extends 
AuthorizableApplicationResource {
     UriInfo uriInfo;
 
     private final LinkService linkService;
+    private final PermissionsService permissionsService;
     private final RegistryService registryService;
 
     @Autowired
     public ItemResource(
             final RegistryService registryService,
             final LinkService linkService,
+            final PermissionsService permissionsService,
             final AuthorizationService authorizationService,
             final Authorizer authorizer) {
         super(authorizer, authorizationService);
         this.registryService = registryService;
         this.linkService = linkService;
+        this.permissionsService = permissionsService;
     }
 
 
@@ -102,6 +106,7 @@ public class ItemResource extends 
AuthorizableApplicationResource {
         }
 
         final List<BucketItem> items = 
registryService.getBucketItems(paramsBuilder.build(), authorizedBucketIds);
+        permissionsService.populateItemPermissions(items);
         linkService.populateItemLinks(items);
 
         return Response.status(Response.Status.OK).entity(items).build();
@@ -132,6 +137,7 @@ public class ItemResource extends 
AuthorizableApplicationResource {
         }
 
         final List<BucketItem> items = 
registryService.getBucketItems(paramsBuilder.build(), bucketId);
+        permissionsService.populateItemPermissions(items);
         linkService.populateItemLinks(items);
 
         return Response.status(Response.Status.OK).entity(items).build();

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
index 3f428ee..dc40f3b 100644
--- 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
+++ 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
@@ -35,8 +35,15 @@ import 
org.springframework.security.config.annotation.web.builders.WebSecurity;
 import 
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import 
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
 import 
org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
 
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
 /**
  * NiFi Registry Web Api Spring security
  */
@@ -44,6 +51,7 @@ import 
org.springframework.security.web.authentication.AnonymousAuthenticationFi
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true)
 public class NiFiRegistrySecurityConfig extends WebSecurityConfigurerAdapter {
+
     private static final Logger logger = 
LoggerFactory.getLogger(NiFiRegistrySecurityConfig.class);
 
     @Autowired
@@ -81,6 +89,9 @@ public class NiFiRegistrySecurityConfig extends 
WebSecurityConfigurerAdapter {
                 .authorizeRequests()
                     .anyRequest().fullyAuthenticated()
                     .and()
+                .exceptionHandling()
+                    
.authenticationEntryPoint(http401AuthenticationEntryPoint())
+                    .and()
                 .sessionManagement()
                     .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
 
@@ -93,8 +104,13 @@ public class NiFiRegistrySecurityConfig extends 
WebSecurityConfigurerAdapter {
         // otp
         // todo, if needed one-time password auth filter goes here
 
-        // anonymous
-        http.anonymous().authenticationFilter(anonymousAuthenticationFilter);
+        if (properties.getSslPort() == null) {
+            // If we are running an unsecured NiFi Registry server, add an
+            // anonymous authentication filter that will populate the
+            // authenticated, anonymous user if no other user identity
+            // is detected earlier in the Spring filter chain.
+            
http.anonymous().authenticationFilter(anonymousAuthenticationFilter);
+        }
     }
 
     @Override
@@ -132,4 +148,19 @@ public class NiFiRegistrySecurityConfig extends 
WebSecurityConfigurerAdapter {
         return jwtAuthenticationProvider;
     }
 
+    private AuthenticationEntryPoint http401AuthenticationEntryPoint() {
+        // This gets used for both secured and unsecured configurations. It 
will be called by Spring Security if a request makes it through the filter 
chain without being authenticated.
+        // For unsecured, this should never be reached because the custom 
AnonymousAuthenticationFilter should always populate a fully-authenticated 
anonymous user
+        // For secured, this will cause attempt to access any API endpoint 
(except those explicitly ignored) without providing credentials to return a 401 
Unauthorized challenge
+        return new AuthenticationEntryPoint() {
+            @Override
+            public void commence(HttpServletRequest request,
+                                 HttpServletResponse response,
+                                 AuthenticationException e) throws 
IOException, ServletException {
+                logger.info("AuthenticationEntryPoint invoked as no user 
identity credentials were found in the request.");
+                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+            }
+        };
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/PermissionsService.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/PermissionsService.java
 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/PermissionsService.java
new file mode 100644
index 0000000..f3ecb11
--- /dev/null
+++ 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/PermissionsService.java
@@ -0,0 +1,92 @@
+/*
+ * 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.web.security;
+
+import org.apache.nifi.registry.bucket.Bucket;
+import org.apache.nifi.registry.bucket.BucketItem;
+import org.apache.nifi.registry.model.authorization.Permissions;
+import org.apache.nifi.registry.security.authorization.AuthorizableLookup;
+import org.apache.nifi.registry.security.authorization.resource.Authorizable;
+import org.apache.nifi.registry.service.AuthorizationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class PermissionsService {
+
+    private AuthorizationService authorizationService;
+    private AuthorizableLookup authorizableLookup;
+
+    @Autowired
+    public PermissionsService(AuthorizationService authorizationService, 
AuthorizableLookup authorizableLookup) {
+        this.authorizationService = authorizationService;
+        this.authorizableLookup = authorizableLookup;
+    }
+
+    public void populateBucketPermissions(final Iterable<Bucket> buckets) {
+        Permissions topLevelBucketPermissions = 
authorizationService.getPermissionsForResource(authorizableLookup.getBucketsAuthorizable());
+        buckets.forEach(b -> populateBucketPermissions(b, 
topLevelBucketPermissions));
+    }
+
+    public void populateBucketPermissions(final Bucket bucket) {
+        populateBucketPermissions(bucket, null);
+    }
+
+    public void populateItemPermissions(final Iterable<? extends BucketItem> 
bucketItems) {
+        Permissions topLevelBucketPermissions = 
authorizationService.getPermissionsForResource(authorizableLookup.getBucketsAuthorizable());
+        bucketItems.forEach(i -> populateItemPermissions(i, 
topLevelBucketPermissions));
+    }
+
+    public void populateItemPermissions(final BucketItem bucketItem) {
+        populateItemPermissions(bucketItem, null);
+    }
+
+    private void populateBucketPermissions(final Bucket bucket, final 
Permissions knownPermissions) {
+
+        if (bucket == null) {
+            return;
+        }
+
+        Permissions bucketPermissions = 
createPermissionsForBucketId(bucket.getIdentifier(), knownPermissions);
+        bucket.setPermissions(bucketPermissions);
+
+    }
+
+    private void populateItemPermissions(final BucketItem bucketItem, final 
Permissions knownPermissions) {
+
+        if (bucketItem == null) {
+            return;
+        }
+
+        Permissions bucketItemPermissions = 
createPermissionsForBucketId(bucketItem.getBucketIdentifier(), 
knownPermissions);
+        bucketItem.setPermissions(bucketItemPermissions);
+
+    }
+
+    private Permissions createPermissionsForBucketId(String bucketId, final 
Permissions knownPermissions) {
+
+        Authorizable bucketResource = 
authorizableLookup.getBucketAuthorizable(bucketId);
+
+        Permissions permissions = knownPermissions == null
+                ? 
authorizationService.getPermissionsForResource(bucketResource)
+                : 
authorizationService.getPermissionsForResource(bucketResource, 
knownPermissions);
+
+        return permissions;
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
 
b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
index 350c170..85b40b7 100644
--- 
a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
+++ 
b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
@@ -25,6 +25,7 @@ import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import static 
org.apache.nifi.registry.web.api.IntegrationTestUtils.assertBucketsEqual;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -59,19 +60,19 @@ public class BucketsIT extends UnsecuredITBase {
                 "\"name\":\"Bucket 1\"," +
                 "\"createdTimestamp\":1505091060000," +
                 "\"description\":\"This is test bucket 1\"," +
-                "\"authorizedActions\":[\"read\",\"write\",\"delete\"]," +
+                
"\"permissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," +
                 
"\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/1\"}}," +
                 "{\"identifier\":\"2\"," +
                 "\"name\":\"Bucket 2\"," +
                 "\"createdTimestamp\":1505091120000," +
                 "\"description\":\"This is test bucket 2\"," +
-                "\"authorizedActions\":[\"read\",\"write\",\"delete\"]," +
+                
"\"permissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," +
                 
"\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/2\"}}," +
                 "{\"identifier\":\"3\"," +
                 "\"name\":\"Bucket 3\"," +
                 "\"createdTimestamp\":1505091180000," +
                 "\"description\":\"This is test bucket 3\"," +
-                "\"authorizedActions\":[\"read\",\"write\",\"delete\"]," +
+                
"\"permissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," +
                 
"\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/3\"}}" +
                 "]";
 
@@ -203,7 +204,7 @@ public class BucketsIT extends UnsecuredITBase {
         // Then: the body of the server response matches the bucket that was 
deleted
         //  and: the bucket is no longer accessible (resource not found)
 
-        createdBucket.setAuthorizedActions(null); // authorizedActions will 
not be present in deletedBucket
+        createdBucket.setPermissions(null); // authorizedActions will not be 
present in deletedBucket
         createdBucket.setLink(null); // links will not be present in 
deletedBucket
         assertBucketsEqual(createdBucket, deletedBucket, true);
 
@@ -234,16 +235,4 @@ public class BucketsIT extends UnsecuredITBase {
 
     }
 
-    private static void assertBucketsEqual(Bucket expected, Bucket actual, 
boolean checkServerSetFields) {
-        assertNotNull(actual);
-        assertEquals(expected.getName(), actual.getName());
-        assertEquals(expected.getDescription(), actual.getDescription());
-        if (checkServerSetFields) {
-            assertEquals(expected.getIdentifier(), actual.getIdentifier());
-            assertEquals(expected.getCreatedTimestamp(), 
actual.getCreatedTimestamp());
-            assertEquals(expected.getAuthorizedActions(), 
actual.getAuthorizedActions());
-            assertEquals(expected.getLink(), actual.getLink());
-        }
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/04cf2322/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/FlowsIT.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/FlowsIT.java
 
b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/FlowsIT.java
index 171442a..854c9c1 100644
--- 
a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/FlowsIT.java
+++ 
b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/FlowsIT.java
@@ -17,7 +17,6 @@
 package org.apache.nifi.registry.web.api;
 
 import org.apache.nifi.registry.bucket.BucketItemType;
-import org.apache.nifi.registry.flow.VersionedComponent;
 import org.apache.nifi.registry.flow.VersionedFlow;
 import org.apache.nifi.registry.flow.VersionedFlowSnapshot;
 import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata;
@@ -30,8 +29,10 @@ import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.util.Set;
 
+import static 
org.apache.nifi.registry.web.api.IntegrationTestUtils.assertFlowSnapshotMetadataEqual;
+import static 
org.apache.nifi.registry.web.api.IntegrationTestUtils.assertFlowSnapshotsEqual;
+import static 
org.apache.nifi.registry.web.api.IntegrationTestUtils.assertFlowsEqual;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -73,6 +74,7 @@ public class FlowsIT extends UnsecuredITBase {
                 "\"createdTimestamp\":1505091360000," +
                 "\"modifiedTimestamp\":1505091360000," +
                 "\"type\":\"FLOW\"," +
+                
"\"permissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," +
                 
"\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/1/flows/1\"}}," +
                 "{\"identifier\":\"2\",\"name\":\"Flow 2\"," +
                 "\"description\":\"This is flow 2\"," +
@@ -80,6 +82,7 @@ public class FlowsIT extends UnsecuredITBase {
                 "\"createdTimestamp\":1505091360000," +
                 "\"modifiedTimestamp\":1505091360000," +
                 "\"type\":\"FLOW\"," +
+                
"\"permissions\":{\"canRead\":true,\"canWrite\":true,\"canDelete\":true}," +
                 "\"versionCount\":0," +
                 
"\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/1/flows/2\"}}" +
                 "]";
@@ -387,73 +390,4 @@ public class FlowsIT extends UnsecuredITBase {
 
     }
 
-    private static void assertFlowsEqual(VersionedFlow expected, VersionedFlow 
actual, boolean checkServerSetFields) {
-        assertNotNull(actual);
-        assertEquals(expected.getName(), actual.getName());
-        assertEquals(expected.getDescription(), actual.getDescription());
-        assertEquals(expected.getBucketIdentifier(), 
actual.getBucketIdentifier());
-        if (checkServerSetFields) {
-            assertEquals(expected.getIdentifier(), actual.getIdentifier());
-            assertEquals(expected.getVersionCount(), actual.getVersionCount());
-            assertEquals(expected.getCreatedTimestamp(), 
actual.getCreatedTimestamp());
-            assertEquals(expected.getModifiedTimestamp(), 
actual.getModifiedTimestamp());
-            assertEquals(expected.getType(), actual.getType());
-            assertEquals(expected.getLink(), actual.getLink());
-        }
-    }
-
-    private static void assertFlowSnapshotsEqual(VersionedFlowSnapshot 
expected, VersionedFlowSnapshot actual, boolean checkServerSetFields) {
-
-        assertNotNull(actual);
-
-        if (expected.getSnapshotMetadata() != null) {
-            assertFlowSnapshotMetadataEqual(expected.getSnapshotMetadata(), 
actual.getSnapshotMetadata(), checkServerSetFields);
-        }
-
-        if (expected.getFlowContents() != null) {
-            assertVersionedProcessGroupsEqual(expected.getFlowContents(), 
actual.getFlowContents());
-        }
-
-    }
-
-    private static void assertFlowSnapshotMetadataEqual(
-            VersionedFlowSnapshotMetadata expected, 
VersionedFlowSnapshotMetadata actual, boolean checkServerSetFields) {
-
-        assertNotNull(actual);
-        assertEquals(expected.getBucketIdentifier(), 
actual.getBucketIdentifier());
-        assertEquals(expected.getFlowIdentifier(), actual.getFlowIdentifier());
-        assertEquals(expected.getVersion(), actual.getVersion());
-        assertEquals(expected.getComments(), actual.getComments());
-        if (checkServerSetFields) {
-            assertEquals(expected.getTimestamp(), actual.getTimestamp());
-        }
-    }
-
-    private static void 
assertVersionedProcessGroupsEqual(VersionedProcessGroup expected, 
VersionedProcessGroup actual) {
-        assertNotNull(actual);
-
-        assertEquals(((VersionedComponent)expected), 
((VersionedComponent)actual));
-
-        // Poor man's set equality assertion as we are only checking the base 
type and not doing a recursive check
-        // TODO, this would be a stronger assertion by replacing this with a 
true VersionedProcessGroup.equals() method that does a deep equality check
-        assertSetsEqual(expected.getProcessGroups(), 
actual.getProcessGroups());
-        assertSetsEqual(expected.getRemoteProcessGroups(), 
actual.getRemoteProcessGroups());
-        assertSetsEqual(expected.getProcessors(), actual.getProcessors());
-        assertSetsEqual(expected.getInputPorts(), actual.getInputPorts());
-        assertSetsEqual(expected.getOutputPorts(), actual.getOutputPorts());
-        assertSetsEqual(expected.getConnections(), actual.getConnections());
-        assertSetsEqual(expected.getLabels(), actual.getLabels());
-        assertSetsEqual(expected.getFunnels(), actual.getFunnels());
-        assertSetsEqual(expected.getControllerServices(), 
actual.getControllerServices());
-    }
-
-
-    private static void assertSetsEqual(Set<? extends VersionedComponent> 
expected, Set<? extends VersionedComponent> actual) {
-        if (expected != null) {
-            assertNotNull(actual);
-            assertEquals(expected.size(), actual.size());
-            assertTrue(actual.containsAll(expected));
-        }
-    }
-
 }

Reply via email to