You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by tb...@apache.org on 2014/07/29 14:04:31 UTC

[1/2] AMBARI-6627 - Views : Admin - Add custom permissions

Repository: ambari
Updated Branches:
  refs/heads/trunk 85362043f -> 11336361f


http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-views/examples/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-views/examples/pom.xml b/ambari-views/examples/pom.xml
index 0951f19..4e93c35 100644
--- a/ambari-views/examples/pom.xml
+++ b/ambari-views/examples/pom.xml
@@ -29,6 +29,7 @@
     <module>phone-list-view</module>
     <module>calculator-view</module>
     <module>weather-view</module>
+    <module>restricted-view</module>
   </modules>
   <build>
     <pluginManagement>

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-views/examples/restricted-view/docs/index.md
----------------------------------------------------------------------
diff --git a/ambari-views/examples/restricted-view/docs/index.md b/ambari-views/examples/restricted-view/docs/index.md
new file mode 100644
index 0000000..78aced4
--- /dev/null
+++ b/ambari-views/examples/restricted-view/docs/index.md
@@ -0,0 +1,261 @@
+<!---
+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](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.
+-->
+
+Restricted View Example
+========
+Description
+-----
+The Restricted view is another simple view example.  Like the HelloWorld view example, it demonstrates the basics of how to write and deploy a view in Ambari but also includes a couple of simple resources and a custom view permission.  The Restricted resources use JAX-RS annotations to define the actions that can be performed on the resources.
+
+Package
+-----
+
+All views are packaged as a view archive.  The view archive contains the configuration file and various optional components of the view.
+
+#####view.xml
+
+The view.xml file is the only required file for a view archive.  The view.xml is the configuration that describes the view and view instances for Ambari.
+
+      <view>
+        <name>RESTRICTED</name>
+        <label>The Restricted View</label>
+        <version>1.0.0</version>
+        <resource>
+          <name>restricted</name>
+          <service-class>org.apache.ambari.view.restricted.RestrictedResource</service-class>
+        </resource>
+        <resource>
+          <name>unrestricted</name>
+          <service-class>org.apache.ambari.view.restricted.UnrestrictedResource</service-class>
+        </resource>
+        <permission>
+          <name>RESTRICTED</name>
+          <description>
+            Access permission for a restricted view resource.
+          </description>
+        </permission>
+        <instance>
+          <name>INSTANCE_1</name>
+        </instance>
+      </view>
+
+The configuration in this case defines a view named RESTRICTED that has a single instance.  The view also defines a resource named 'unrestricted' and a resource name 'restricted'.
+
+
+
+#####UnrestrictedResource.java
+
+The UnrestrictedResource class defines a simple resource for the view.  It uses JAX-RS annotations to define the actions that can be performed on the resource.
+
+    @GET
+    @Produces({"text/html"})
+    public Response getUnrestricted() throws IOException{
+      return Response.ok("<b>You have accessed an unrestricted resource.</b>").type("text/html").build();
+    }
+
+The getUnrestricted method will service requests to **'INSTANCE_1/resources/unrestricted'** for INSTANCE_1 of the RESTRICTED view.  
+
+For example ...
+
+     http://<server>:8080/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1/resources/unrestricted
+
+#####RestrictedResource.java
+
+The RestrictedResource class defines a simple resource for the view.  It uses JAX-RS annotations to define the actions that can be performed on the resource.
+
+    @GET
+    @Produces({"text/html"})
+    public Response getRestricted() throws IOException{
+  
+      String userName = context.getUsername();
+  
+      try {
+        context.hasPermission(userName, "RESTRICTED");
+      } catch (org.apache.ambari.view.SecurityException e) {
+        return Response.status(401).build();
+      }
+  
+      return Response.ok("<b>You have accessed a restricted resource.</b>").type("text/html").build();
+    }
+
+The getRestricted method will service requests to **'INSTANCE_1/resources/restricted'** for INSTANCE_1 of the RESTRICTED view.  
+
+For example ...
+
+     http://<server>:8080/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1/resources/restricted
+
+Build
+-----
+
+The view can be built as a maven project.
+
+    cd ambari-views/examples/restricted-view
+    mvn clean package
+
+The build will produce the view archive.
+
+    ambari-views/examples/restricted-view/target/restricted-view-1.0.0.jar
+
+
+Deploy
+-----
+To deploy a view we simply place the view archive in the views folder of the ambari-server machine.  By default the views folder is located at ...
+
+    /var/lib/ambari-server/resources/views
+
+To deploy the Restricted view simply copy the restricted-view jar to the ambari-server views folder and restart the ambari server.
+
+Use
+-----
+
+After deploying a view you should see it as a view resource in the Ambari REST API.  If we request all views, we should see the RESTRICTED view.
+
+      {
+        "href" : "http://<server>:8080/api/v1/views",
+        "items" : [
+          {
+            "href" : "http://<server>:8080/api/v1/views/RESTRICTED",
+            "ViewInfo" : {
+              "view_name" : "RESTRICTED"
+            }
+          },
+          {
+            "href" : "http://<server>:8080/api/v1/views/HELLO_SERVLET",
+            "ViewInfo" : {
+              "view_name" : "HELLO_SERVLET"
+            }
+          },
+          {
+            "href" : "http://<server>:8080/api/v1/views/HELLO_WORLD",
+            "ViewInfo" : {
+              "view_name" : "HELLO_WORLD"
+            }
+          }
+        ]
+      }
+
+
+If we want to see the details about a specific view, we can ask for it by name.  This shows us that the RESTRICTED view has a single instance named INSTANCE_1.  Note the RESTRICTED permission sub-resource.
+
+    {
+      "href" : "http://<server>/api/v1/views/RESTRICTED/versions/1.0.0/",
+      "ViewVersionInfo" : {
+        "archive" : "/var/lib/ambari-server/resources/views/work/RESTRICTED{1.0.0}",
+        "label" : "The Restricted View",
+        "masker_class" : null,
+        "parameters" : [ ],
+        "version" : "1.0.0",
+        "view_name" : "RESTRICTED"
+      },
+      "permissions" : [
+        {
+          "href" : "http://<server>/api/v1/views/RESTRICTED/versions/1.0.0/permissions/7",
+          "PermissionInfo" : {
+            "permission_id" : 7,
+            "version" : "1.0.0",
+            "view_name" : "RESTRICTED"
+          }
+        }
+      ],
+      "instances" : [
+        {
+          "href" : "http://<server>/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1",
+          "ViewInstanceInfo" : {
+            "instance_name" : "INSTANCE_1",
+            "version" : "1.0.0",
+            "view_name" : "RESTRICTED"
+          }
+        }
+      ]    
+    }
+
+To see a specific instance of a view, we can ask for it by name.  Here we can see the attributes of the view instance.  We can also see that this view has two resources named 'restricted' and 'unrestricted'.  Note that there are no privileges granted on the view instance.
+
+    {
+      "href" : "http://<server>/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1/",
+      "ViewInstanceInfo" : {
+        "context_path" : "/views/RESTRICTED/1.0.0/INSTANCE_1",
+        "description" : null,
+        "icon64_path" : null,
+        "icon_path" : null,
+        "instance_name" : "INSTANCE_1",
+        "label" : "The Restricted View",
+        "version" : "1.0.0",
+        "view_name" : "RESTRICTED",
+        "visible" : true,
+        "instance_data" : { },
+        "properties" : { }
+      },
+      "resources" : [
+        {
+          "href" : "http://<server>/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1/resources/restricted",
+          "instance_name" : "INSTANCE_1",
+          "name" : "restricted",
+          "version" : "1.0.0",
+          "view_name" : "RESTRICTED"
+        },
+        {
+          "href" : "http://<server>/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1/resources/unrestricted",
+          "instance_name" : "INSTANCE_1",
+          "name" : "unrestricted",
+          "version" : "1.0.0",
+          "view_name" : "RESTRICTED"
+        }
+      ],
+      "privileges" : [
+      ]
+    }
+    
+We can access the view's unrestricted resource through the resource's href.
+
+    http://<server>:8080/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1/resources/unrestricted/
+    
+    You have accessed an unrestricted resource.
+
+
+If we try to access the view's restricted resource through the resource's href it should return a 401 Unauthorized response.
+
+    http://<server>:8080/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1/resources/unrestricted/
+    
+    401 Unauthorized
+
+To grant privileges to access the restricted resource we can create a privilege sub-resource for the view instance.  The following API will grant RESTICTED permission to the user 'bob' for the view instance 'INSTANCE_1' of the 'RESTRICTED' view. 
+
+    POST http://<server>/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1
+    
+    [
+      {
+        "PrivilegeInfo" : {
+          "permission_name" : "RESTRICTED",
+          "principal_name" : "bob",
+          "principal_type" : "USER"
+        }
+      }
+    ]
+
+We should now see a privilege sub resource for the view instance and the user 'bob' should be able to access the restricted resource.
+
+    {
+      "href" : "http://<server>/api/v1/views/RESTRICTED/versions/1.0.0/instances/INSTANCE_1/privileges/5",
+      "PrivilegeInfo" : {
+        "instance_name" : "INSTANCE_1",
+        "permission_name" : "RESTRICTED",
+        "principal_name" : "bob",
+        "principal_type" : "USER",
+        "privilege_id" : 5,
+        "version" : "1.0.0",
+        "view_name" : "RESTRICTED"
+      }
+    }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-views/examples/restricted-view/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-views/examples/restricted-view/pom.xml b/ambari-views/examples/restricted-view/pom.xml
new file mode 100644
index 0000000..3574f73
--- /dev/null
+++ b/ambari-views/examples/restricted-view/pom.xml
@@ -0,0 +1,89 @@
+<!--
+   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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.apache.ambari</groupId>
+    <artifactId>ambari-view-examples</artifactId>
+    <version>1.0.0</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>restricted-view</artifactId>
+  <packaging>jar</packaging>
+  <name>Ambari Restricted View</name>
+  <url>http://maven.apache.org</url>
+  <properties>
+    <ambari.version>1.3.0-SNAPSHOT</ambari.version>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.8.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <version>3.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ambari</groupId>
+      <artifactId>ambari-views</artifactId>
+      <version>${ambari.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-server</artifactId>
+      <version>1.8</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.inject</groupId>
+      <artifactId>javax.inject</artifactId>
+      <version>1</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>2.12</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>rpm-maven-plugin</artifactId>
+        <version>2.0.1</version>
+        <executions>
+          <execution>
+            <phase>none</phase>
+            <goals>
+              <goal>rpm</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-views/examples/restricted-view/src/main/java/org/apache/ambari/view/restricted/RestrictedResource.java
----------------------------------------------------------------------
diff --git a/ambari-views/examples/restricted-view/src/main/java/org/apache/ambari/view/restricted/RestrictedResource.java b/ambari-views/examples/restricted-view/src/main/java/org/apache/ambari/view/restricted/RestrictedResource.java
new file mode 100644
index 0000000..88d22ee
--- /dev/null
+++ b/ambari-views/examples/restricted-view/src/main/java/org/apache/ambari/view/restricted/RestrictedResource.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.view.restricted;
+
+import org.apache.ambari.view.ViewContext;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+/**
+ * The restricted resource.
+ */
+public class RestrictedResource {
+  /**
+   * The view context.
+   */
+  @Inject
+  ViewContext context;
+
+  /**
+   * Handles: GET /restricted.
+   *
+   * @return the response
+   */
+  @GET
+  @Produces({"text/html"})
+  public Response getRestricted() throws IOException{
+
+    String userName = context.getUsername();
+
+    try {
+      context.hasPermission(userName, "RESTRICTED");
+    } catch (org.apache.ambari.view.SecurityException e) {
+      return Response.status(401).build();
+    }
+
+    return Response.ok("<b>You have accessed a restricted resource.</b>").type("text/html").build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-views/examples/restricted-view/src/main/java/org/apache/ambari/view/restricted/UnrestrictedResource.java
----------------------------------------------------------------------
diff --git a/ambari-views/examples/restricted-view/src/main/java/org/apache/ambari/view/restricted/UnrestrictedResource.java b/ambari-views/examples/restricted-view/src/main/java/org/apache/ambari/view/restricted/UnrestrictedResource.java
new file mode 100644
index 0000000..f058b8c
--- /dev/null
+++ b/ambari-views/examples/restricted-view/src/main/java/org/apache/ambari/view/restricted/UnrestrictedResource.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.view.restricted;
+
+
+import org.apache.ambari.view.ViewContext;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+/**
+ * The unrestricted resource.
+ */
+public class UnrestrictedResource {
+  /**
+   * The view context.
+   */
+  @Inject
+  ViewContext context;
+
+  /**
+   * Handles: GET /unrestricted.
+   *
+   * @return the response
+   */
+  @GET
+  @Produces({"text/html"})
+  public Response getUnrestricted() throws IOException{
+    return Response.ok("<b>You have accessed an unrestricted resource.</b>").type("text/html").build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-views/examples/restricted-view/src/main/resources/view.xml
----------------------------------------------------------------------
diff --git a/ambari-views/examples/restricted-view/src/main/resources/view.xml b/ambari-views/examples/restricted-view/src/main/resources/view.xml
new file mode 100644
index 0000000..8719987
--- /dev/null
+++ b/ambari-views/examples/restricted-view/src/main/resources/view.xml
@@ -0,0 +1,38 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<view>
+  <name>RESTRICTED</name>
+  <label>The Restricted View</label>
+  <version>1.0.0</version>
+  <resource>
+    <name>restricted</name>
+    <service-class>org.apache.ambari.view.restricted.RestrictedResource</service-class>
+  </resource>
+  <resource>
+    <name>unrestricted</name>
+    <service-class>org.apache.ambari.view.restricted.UnrestrictedResource</service-class>
+  </resource>
+  <permission>
+    <name>RESTRICTED</name>
+    <description>
+      Access permission for a restricted view resource.
+    </description>
+  </permission>
+  <instance>
+    <name>INSTANCE_1</name>
+  </instance>
+</view>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-views/src/main/java/org/apache/ambari/view/SecurityException.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/SecurityException.java b/ambari-views/src/main/java/org/apache/ambari/view/SecurityException.java
new file mode 100644
index 0000000..9b97ade
--- /dev/null
+++ b/ambari-views/src/main/java/org/apache/ambari/view/SecurityException.java
@@ -0,0 +1,44 @@
+/**
+ * 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.ambari.view;
+
+/**
+ * Indicates that a view security exception occurred.
+ */
+public class SecurityException extends Exception {
+  /**
+   * Constructor.
+   *
+   * @param msg        message
+   */
+  public SecurityException(String msg) {
+    super(msg);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param msg        message
+   * @param throwable  root exception
+   */
+  public SecurityException(String msg, Throwable throwable) {
+    super(msg, throwable);
+  }
+}
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java b/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
index c83e8eb..37e91a2 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
@@ -41,6 +41,18 @@ public interface ViewContext {
   public String getUsername();
 
   /**
+   * Determine whether or not the access specified by the given permission name
+   * is permitted for the given user.
+   *
+   * @param userName        the user name
+   * @param permissionName  the permission name
+   *
+   * @throws SecurityException if the access specified by the given permission name
+   *         is not permitted
+   */
+  public void hasPermission(String userName, String permissionName) throws SecurityException;
+
+  /**
    * Get the view name.
    *
    * @return the view name


[2/2] git commit: AMBARI-6627 - Views : Admin - Add custom permissions

Posted by tb...@apache.org.
AMBARI-6627 - Views : Admin - Add custom permissions


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/11336361
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/11336361
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/11336361

Branch: refs/heads/trunk
Commit: 11336361fa4b0e180961f29b95802bb51090c196
Parents: 8536204
Author: tbeerbower <tb...@hortonworks.com>
Authored: Sun Jul 27 09:33:45 2014 -0400
Committer: tbeerbower <tb...@hortonworks.com>
Committed: Tue Jul 29 08:01:54 2014 -0400

----------------------------------------------------------------------
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 .../ViewPermissionResourceDefinition.java       |  58 +++++
 .../ViewVersionResourceDefinition.java          |   7 +-
 .../api/services/ViewPermissionService.java     | 185 +++++++++++++
 .../server/api/services/ViewVersionService.java |  13 +
 .../ambari/server/controller/AmbariServer.java  |   7 +-
 .../internal/DefaultProviderModule.java         |   2 +
 .../internal/PrivilegeResourceProvider.java     |  23 +-
 .../ViewPermissionResourceProvider.java         | 178 +++++++++++++
 .../ambari/server/controller/spi/Resource.java  |   4 +-
 .../apache/ambari/server/orm/dao/MemberDAO.java |   9 +-
 .../ambari/server/orm/dao/PermissionDAO.java    |  20 +-
 .../ambari/server/orm/dao/PrivilegeDAO.java     |  25 +-
 .../server/orm/entities/PermissionEntity.java   |  15 +-
 .../server/orm/entities/ResourceTypeEntity.java |  21 ++
 .../ambari/server/orm/entities/ViewEntity.java  |  47 ++++
 .../ambari/server/view/ViewContextImpl.java     |  43 ++-
 .../apache/ambari/server/view/ViewRegistry.java | 172 +++++++++---
 .../view/configuration/PermissionConfig.java    |  39 +++
 .../server/view/configuration/ViewConfig.java   |  15 ++
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   1 +
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   1 +
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   1 +
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |   1 +
 .../ViewPermissionResourceDefinitionTest.java   |  49 ++++
 .../ViewVersionResourceDefinitionTest.java      |   7 +-
 .../api/services/ViewPermissionServiceTest.java | 100 +++++++
 .../ambari/server/view/ViewRegistryTest.java    |  70 +++--
 .../configuration/PermissionConfigTest.java     |  69 +++++
 ambari-views/examples/pom.xml                   |   1 +
 .../examples/restricted-view/docs/index.md      | 261 +++++++++++++++++++
 ambari-views/examples/restricted-view/pom.xml   |  89 +++++++
 .../view/restricted/RestrictedResource.java     |  57 ++++
 .../view/restricted/UnrestrictedResource.java   |  49 ++++
 .../restricted-view/src/main/resources/view.xml |  38 +++
 .../apache/ambari/view/SecurityException.java   |  44 ++++
 .../org/apache/ambari/view/ViewContext.java     |  12 +
 37 files changed, 1638 insertions(+), 99 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index 892ac22..5399404 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -254,6 +254,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new PrivilegeResourceDefinition(Resource.Type.ViewPrivilege);
         break;
 
+      case ViewPermission:
+        resourceDefinition = new ViewPermissionResourceDefinition();
+        break;
+
       default:
         throw new IllegalArgumentException("Unsupported resource type: " + type);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewPermissionResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewPermissionResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewPermissionResourceDefinition.java
new file mode 100644
index 0000000..1ff360d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewPermissionResourceDefinition.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.Collections;
+import java.util.Set;
+
+
+/**
+ * Permission resource definition.
+ */
+public class ViewPermissionResourceDefinition extends BaseResourceDefinition {
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a permission resource definition.
+   */
+  public ViewPermissionResourceDefinition() {
+    super(Resource.Type.ViewPermission);
+  }
+
+
+  // ----- ResourceDefinition ------------------------------------------------
+
+  @Override
+  public String getPluralName() {
+    return "permissions";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "permission";
+  }
+
+  @Override
+  public Set<SubResourceDefinition> getSubResourceDefinitions() {
+    return Collections.emptySet();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinition.java
index e67a50b..be21d1b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinition.java
@@ -20,7 +20,7 @@ package org.apache.ambari.server.api.resources;
 
 import org.apache.ambari.server.controller.spi.Resource;
 
-import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
 
 
@@ -53,6 +53,9 @@ public class ViewVersionResourceDefinition extends BaseResourceDefinition {
 
   @Override
   public Set<SubResourceDefinition> getSubResourceDefinitions() {
-    return Collections.singleton(new SubResourceDefinition(Resource.Type.ViewInstance));
+    Set<SubResourceDefinition> subResourceDefinitions = new HashSet<SubResourceDefinition>();
+    subResourceDefinitions.add(new SubResourceDefinition(Resource.Type.ViewInstance));
+    subResourceDefinitions.add(new SubResourceDefinition(Resource.Type.ViewPermission));
+    return subResourceDefinitions;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
new file mode 100644
index 0000000..711e85b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
@@ -0,0 +1,185 @@
+/**
+ * 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.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Service responsible for custom view permission resource requests.
+ */
+public class ViewPermissionService extends BaseService {
+
+  /**
+   * Parent view name.
+   */
+  private final String viewName;
+
+  /**
+   * The view version.
+   */
+  private final String version;
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view permission service.
+   *
+   * @param viewName  the view id
+   * @param version   the version
+   */
+  public ViewPermissionService(String viewName, String version) {
+    this.viewName = viewName;
+    this.version  = version;
+  }
+
+
+  // ----- ViewPermissionService -----------------------------------------------
+
+  /**
+   * Handles: GET /permissions/{permissionID}
+   * Get a specific permission.
+   *
+   * @param headers        http headers
+   * @param ui             uri info
+   * @param permissionId   permission id
+   *
+   * @return permission instance representation
+   */
+  @GET
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response getPermission(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, null, ui, Request.Type.GET, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+  /**
+   * Handles: GET  /permissions
+   * Get all permissions.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   *
+   * @return permission collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  public Response getPermissions(@Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, null, ui, Request.Type.GET, createPermissionResource(
+        viewName, version, null));
+  }
+
+  /**
+   * Handles: POST /permissions/{permissionID}
+   * Create a specific permission.
+   *
+   * @param headers    http headers
+   * @param ui         uri info
+   * @param permissionId   permission id
+   *
+   * @return information regarding the created permission
+   */
+  @POST
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response createPermission(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                   @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+  /**
+   * Handles: PUT /permissions/{permissionID}
+   * Update a specific permission.
+   *
+   * @param headers   http headers
+   * @param ui        uri info
+   * @param permissionId  permission id
+   *
+   * @return information regarding the updated permission
+   */
+  @PUT
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response updatePermission(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                   @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+  /**
+   * Handles: DELETE /permissions/{permissionID}
+   * Delete a specific permission.
+   *
+   * @param headers   http headers
+   * @param ui        uri info
+   * @param permissionId  permission id
+   *
+   * @return information regarding the deleted permission
+   */
+  @DELETE
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response deletePermission(@Context HttpHeaders headers, @Context UriInfo ui,
+                                   @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Create a permission resource.
+   *
+   * @param permissionId permission name
+   *
+   * @return a permission resource instance
+   */
+  protected ResourceInstance createPermissionResource(String viewName, String viewVersion, String permissionId) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewVersion, viewVersion);
+    mapIds.put(Resource.Type.ViewPermission, permissionId);
+
+    return createResource(Resource.Type.ViewPermission, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
index 0dac300..8152ae6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
@@ -166,6 +166,19 @@ public class ViewVersionService extends BaseService {
     return new ViewInstanceService(viewName, version);
   }
 
+  /**
+   * Get the permissions sub-resource
+   *
+   * @param version  the version
+   *
+   * @return the permission service
+   */
+  @Path("{version}/permissions")
+  public ViewPermissionService getPermissionHandler(@PathParam("version") String version) {
+
+    return new ViewPermissionService(viewName, version);
+  }
+
 
   // ----- helper methods ----------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 6803a01..eb34a77 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -53,12 +53,14 @@ import org.apache.ambari.server.controller.internal.PrivilegeResourceProvider;
 import org.apache.ambari.server.controller.internal.RecommendationResourceProvider;
 import org.apache.ambari.server.controller.internal.StackDefinedPropertyProvider;
 import org.apache.ambari.server.controller.internal.StackDependencyResourceProvider;
+import org.apache.ambari.server.controller.internal.ViewPermissionResourceProvider;
 import org.apache.ambari.server.controller.nagios.NagiosPropertyProvider;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.PersistenceType;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.dao.BlueprintDAO;
 import org.apache.ambari.server.orm.dao.GroupDAO;
+import org.apache.ambari.server.orm.dao.MemberDAO;
 import org.apache.ambari.server.orm.dao.MetainfoDAO;
 import org.apache.ambari.server.orm.dao.PermissionDAO;
 import org.apache.ambari.server.orm.dao.PrincipalDAO;
@@ -541,11 +543,14 @@ public class AmbariServer {
     ClusterResourceProvider.init(injector.getInstance(BlueprintDAO.class), ambariMetaInfo);
     AlertDefinitionResourceProvider.init(injector.getInstance(AlertDefinitionDAO.class));
     PermissionResourceProvider.init(injector.getInstance(PermissionDAO.class));
+    ViewPermissionResourceProvider.init(injector.getInstance(PermissionDAO.class));
     PrivilegeResourceProvider.init(injector.getInstance(PrivilegeDAO.class), injector.getInstance(UserDAO.class),
         injector.getInstance(GroupDAO.class), injector.getInstance(PrincipalDAO.class),
         injector.getInstance(PermissionDAO.class), injector.getInstance(ResourceDAO.class));
     ViewRegistry.init(injector.getInstance(ViewDAO.class), injector.getInstance(ViewInstanceDAO.class),
-        injector.getInstance(ResourceDAO.class), injector.getInstance(ResourceTypeDAO.class));
+        injector.getInstance(ResourceDAO.class), injector.getInstance(ResourceTypeDAO.class),
+        injector.getInstance(UserDAO.class), injector.getInstance(MemberDAO.class),
+        injector.getInstance(PrivilegeDAO.class));
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
index 1d20075..88e4296 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
@@ -75,6 +75,8 @@ public class DefaultProviderModule extends AbstractProviderModule {
         return new AmbariPrivilegeResourceProvider();
       case ViewPrivilege:
         return new ViewPrivilegeResourceProvider();
+      case ViewPermission:
+        return new ViewPermissionResourceProvider();
       default:
         return AbstractControllerResourceProvider.getResourceProvider(type, propertyIds,
             keyPropertyIds, managementController);

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java
index c7476e5..d04345b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java
@@ -40,6 +40,7 @@ import org.apache.ambari.server.orm.entities.GroupEntity;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.orm.entities.ResourceEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 
 import java.util.Collections;
@@ -303,22 +304,26 @@ public abstract class PrivilegeResourceProvider<T> extends AbstractResourceProvi
    * @return the new privilege entity
    */
   protected PrivilegeEntity toEntity(Map<String, Object> properties, Long resourceId) {
-    PrivilegeEntity entity = new PrivilegeEntity();
+    PrivilegeEntity entity         = new PrivilegeEntity();
+    String          permissionName = (String) properties.get(PERMISSION_NAME_PROPERTY_ID);
+    ResourceEntity  resourceEntity = resourceDAO.findById(resourceId);
 
-    String permissionName = (String) properties.get(PERMISSION_NAME_PROPERTY_ID);
-
-    entity.setPermission(permissionDAO.findPermissionByName(permissionName));
-    entity.setResource(resourceDAO.findById(resourceId));
+    entity.setResource(resourceEntity);
+    entity.setPermission(permissionDAO.findPermissionByNameAndType(permissionName, resourceEntity.getResourceType()));
 
     String principalName = (String) properties.get(PRINCIPAL_NAME_PROPERTY_ID);
     String principalType = (String) properties.get(PRINCIPAL_TYPE_PROPERTY_ID);
 
     if (PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE_NAME.equalsIgnoreCase(principalType)) {
       GroupEntity groupEntity = groupDAO.findGroupByName(principalName);
-      entity.setPrincipal(principalDAO.findById(groupEntity.getPrincipal().getId()));
+      if (groupEntity != null) {
+        entity.setPrincipal(principalDAO.findById(groupEntity.getPrincipal().getId()));
+      }
     } else if (PrincipalTypeEntity.USER_PRINCIPAL_TYPE_NAME.equalsIgnoreCase(principalType)) {
       UserEntity userEntity = userDAO.findLocalUserByName(principalName);
-      entity.setPrincipal(principalDAO.findById(userEntity.getPrincipal().getId()));
+      if (userEntity != null) {
+        entity.setPrincipal(principalDAO.findById(userEntity.getPrincipal().getId()));
+      }
     }
     return entity;
   }
@@ -335,6 +340,10 @@ public abstract class PrivilegeResourceProvider<T> extends AbstractResourceProvi
 
         PrivilegeEntity entity = toEntity(properties, resourceId);
 
+        if (entity.getPrincipal() == null) {
+          throw new AmbariException("Can't find principal " + properties.get(PRINCIPAL_TYPE_PROPERTY_ID) +
+              " " + properties.get(PRINCIPAL_NAME_PROPERTY_ID) + " for privilege.");
+        }
         if (privilegeDAO.exists(entity)) {
             throw new DuplicateResourceException("The privilege already exists.");
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewPermissionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewPermissionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewPermissionResourceProvider.java
new file mode 100644
index 0000000..547692d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewPermissionResourceProvider.java
@@ -0,0 +1,178 @@
+/**
+ * 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.ambari.server.controller.internal;
+
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.orm.dao.PermissionDAO;
+import org.apache.ambari.server.orm.entities.PermissionEntity;
+import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
+import org.apache.ambari.server.orm.entities.ViewEntity;
+import org.apache.ambari.server.view.ViewRegistry;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource provider for custom view permissions.
+ */
+public class ViewPermissionResourceProvider extends AbstractResourceProvider {
+
+  /**
+   * Data access object used to obtain permission entities.
+   */
+  protected static PermissionDAO permissionDAO;
+
+  /**
+   * Permission property id constants.
+   */
+  public static final String VIEW_NAME_PROPERTY_ID       = "PermissionInfo/view_name";
+  public static final String VIEW_VERSION_PROPERTY_ID    = "PermissionInfo/version";
+  public static final String PERMISSION_ID_PROPERTY_ID   = "PermissionInfo/permission_id";
+  public static final String PERMISSION_NAME_PROPERTY_ID = "PermissionInfo/permission_name";
+  public static final String RESOURCE_NAME_PROPERTY_ID   = "PermissionInfo/resource_name";
+
+
+  /**
+   * The key property ids for a permission resource.
+   */
+  private static Map<Resource.Type, String> keyPropertyIds = new HashMap<Resource.Type, String>();
+  static {
+    keyPropertyIds.put(Resource.Type.View, VIEW_NAME_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.ViewVersion, VIEW_VERSION_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.ViewPermission, PERMISSION_ID_PROPERTY_ID);
+  }
+
+  /**
+   * The property ids for a permission resource.
+   */
+  private static Set<String> propertyIds = new HashSet<String>();
+  static {
+    propertyIds.add(VIEW_NAME_PROPERTY_ID);
+    propertyIds.add(VIEW_VERSION_PROPERTY_ID);
+    propertyIds.add(PERMISSION_ID_PROPERTY_ID);
+    propertyIds.add(PERMISSION_NAME_PROPERTY_ID);
+    propertyIds.add(RESOURCE_NAME_PROPERTY_ID);
+  }
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a permission resource provider.
+   */
+  public ViewPermissionResourceProvider() {
+    super(propertyIds, keyPropertyIds);
+  }
+
+
+  // ----- PermissionResourceProvider ----------------------------------------
+
+  /**
+   * Static initialization.
+   *
+   * @param dao  permission data access object
+   */
+  public static void init(PermissionDAO dao) {
+    permissionDAO = dao;
+  }
+
+
+  // ----- ResourceProvider --------------------------------------------------
+
+  @Override
+  public RequestStatus createResources(Request request)
+      throws SystemException, UnsupportedPropertyException,
+      ResourceAlreadyExistsException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Not supported.");
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    ViewRegistry  viewRegistry = ViewRegistry.getInstance();
+    Set<Resource> resources    = new HashSet<Resource>();
+    Set<String>   requestedIds = getRequestPropertyIds(request, predicate);
+
+    for(PermissionEntity permissionEntity : permissionDAO.findAll()){
+      ResourceTypeEntity resourceType = permissionEntity.getResourceType();
+
+      ViewEntity viewEntity = viewRegistry.getDefinition(resourceType);
+
+      if (viewEntity != null) {
+        resources.add(toResource(permissionEntity, resourceType, viewEntity, requestedIds));
+      }
+    }
+
+    return resources;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Not supported.");
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Not supported.");
+  }
+
+  @Override
+  public Map<Resource.Type, String> getKeyPropertyIds() {
+    return keyPropertyIds;
+  }
+
+
+  // ----- AbstractResourceProvider ------------------------------------------
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return new HashSet<String>(keyPropertyIds.values());
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  // convert the given permission entity to a resource
+  private Resource toResource(PermissionEntity entity, ResourceTypeEntity resourceType,
+                              ViewEntity viewEntity, Set<String> requestedIds) {
+
+    Resource resource = new ResourceImpl(Resource.Type.ViewPermission);
+
+    setResourceProperty(resource, VIEW_NAME_PROPERTY_ID, viewEntity.getCommonName(), requestedIds);
+    setResourceProperty(resource, VIEW_VERSION_PROPERTY_ID, viewEntity.getVersion(), requestedIds);
+
+    setResourceProperty(resource, PERMISSION_ID_PROPERTY_ID, entity.getId(), requestedIds);
+    setResourceProperty(resource, PERMISSION_NAME_PROPERTY_ID, entity.getPermissionName(), requestedIds);
+    setResourceProperty(resource, RESOURCE_NAME_PROPERTY_ID, resourceType.getName(), requestedIds);
+
+    return resource;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 50519cc..c6cc95b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -115,7 +115,8 @@ public interface Resource {
     AlertDefinition,
     AmbariPrivilege,
     ClusterPrivilege,
-    ViewPrivilege;
+    ViewPrivilege,
+    ViewPermission;
 
     /**
      * Get the {@link Type} that corresponds to this InternalType.
@@ -192,6 +193,7 @@ public interface Resource {
     public static final Type AmbariPrivilege = InternalType.AmbariPrivilege.getType();
     public static final Type ClusterPrivilege = InternalType.ClusterPrivilege.getType();
     public static final Type ViewPrivilege = InternalType.ViewPrivilege.getType();
+    public static final Type ViewPermission = InternalType.ViewPermission.getType();
 
     /**
      * The type name.

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java
index b4e015d..5788b81 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/MemberDAO.java
@@ -29,6 +29,7 @@ import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.orm.entities.UserEntity;
 
 @Singleton
 public class MemberDAO {
@@ -44,7 +45,13 @@ public class MemberDAO {
 
   @RequiresSession
   public List<MemberEntity> findAll() {
-    final TypedQuery<MemberEntity> query = entityManagerProvider.get().createQuery("SELECT member FROM MemberEntity member", MemberEntity.class);
+    final TypedQuery<MemberEntity> query = entityManagerProvider.get().createQuery("SELECT m FROM MemberEntity m", MemberEntity.class);
+    return daoUtils.selectList(query);
+  }
+
+  public List<MemberEntity> findAllMembersByUser(UserEntity userEntity) {
+    TypedQuery<MemberEntity> query = entityManagerProvider.get().createQuery("SELECT m FROM MemberEntity m WHERE m.user = :userEntity", MemberEntity.class);
+    query.setParameter("userEntity", userEntity);
     return daoUtils.selectList(query);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PermissionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PermissionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PermissionDAO.java
index c00b47a..0ab5af8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PermissionDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PermissionDAO.java
@@ -22,9 +22,9 @@ import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import org.apache.ambari.server.orm.entities.PermissionEntity;
+import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
 
 import javax.persistence.EntityManager;
-import javax.persistence.NoResultException;
 import javax.persistence.TypedQuery;
 import java.util.List;
 
@@ -58,24 +58,22 @@ public class PermissionDAO {
    * @return all entities or an empty List
    */
   public List<PermissionEntity> findAll() {
-    TypedQuery<PermissionEntity> query = entityManagerProvider.get().createQuery("SELECT resource FROM PermissionEntity resource", PermissionEntity.class);
+    TypedQuery<PermissionEntity> query = entityManagerProvider.get().createQuery("SELECT p FROM PermissionEntity p", PermissionEntity.class);
     return daoUtils.selectList(query);
   }
 
   /**
-   * Find a permission entity by name.
+   * Find a permission entity by name and type.
    *
-   * @param name  the permission name
+   * @param name         the permission name
+   * @param resourceType the resource type
    *
    * @return  a matching permission entity or null
    */
-  public PermissionEntity findPermissionByName(String name) {
-    final TypedQuery<PermissionEntity> query = entityManagerProvider.get().createNamedQuery("permissionByName", PermissionEntity.class);
+  public PermissionEntity findPermissionByNameAndType(String name, ResourceTypeEntity resourceType) {
+    TypedQuery<PermissionEntity> query = entityManagerProvider.get().createQuery("SELECT p FROM PermissionEntity p WHERE p.permissionName=:permissionname AND p.resourceType=:resourcetype", PermissionEntity.class);
     query.setParameter("permissionname", name);
-    try {
-      return query.getSingleResult();
-    } catch (NoResultException e) {
-      return null;
-    }
+    query.setParameter("resourcetype", resourceType);
+    return daoUtils.selectSingle(query);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrivilegeDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrivilegeDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrivilegeDAO.java
index de18031..7fed17b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrivilegeDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrivilegeDAO.java
@@ -22,7 +22,10 @@ import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.orm.entities.PermissionEntity;
+import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.orm.entities.ResourceEntity;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
@@ -63,19 +66,33 @@ public class PrivilegeDAO {
   }
 
   /**
-   * Determine whether or not the given privilege entity already exists.
+   * Determine whether or not the given privilege entity exists.
    *
    * @param entity  the privilege entity
    *
    * @return true if the given privilege entity already exists
    */
   public boolean exists(PrivilegeEntity entity) {
+    return exists(entity.getPrincipal(), entity.getResource(), entity.getPermission());
+  }
+
+  /**
+   * Determine whether or not the privilege entity exists defined by the given principal, resource and
+   * permission exists.
+   *
+   * @param principalEntity   the principal entity
+   * @param resourceEntity    the resource entity
+   * @param permissionEntity  the permission entity
+   *
+   * @return true if the privilege entity already exists
+   */
+  public boolean exists(PrincipalEntity principalEntity, ResourceEntity resourceEntity, PermissionEntity permissionEntity) {
     TypedQuery<PrivilegeEntity> query = entityManagerProvider.get().createQuery(
         "SELECT privilege FROM PrivilegeEntity privilege WHERE privilege.principal = :principal AND privilege.resource = :resource AND privilege.permission = :permission", PrivilegeEntity.class);
 
-    query.setParameter("principal", entity.getPrincipal());
-    query.setParameter("resource", entity.getResource());
-    query.setParameter("permission", entity.getPermission());
+    query.setParameter("principal", principalEntity);
+    query.setParameter("resource", resourceEntity);
+    query.setParameter("permission", permissionEntity);
 
     List<PrivilegeEntity> privilegeEntities = daoUtils.selectList(query);
     return !(privilegeEntities == null || privilegeEntities.isEmpty());

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PermissionEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PermissionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PermissionEntity.java
index a770f1d..8889bde 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PermissionEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PermissionEntity.java
@@ -43,10 +43,6 @@ import javax.persistence.TableGenerator;
     , initialValue = 5
     , allocationSize = 1
 )
-
-@NamedQueries({
-    @NamedQuery(name = "permissionByName", query = "SELECT permission_entity FROM PermissionEntity permission_entity where permission_entity.permissionName=:permissionname")
-})
 public class PermissionEntity {
 
   /**
@@ -137,17 +133,14 @@ public class PermissionEntity {
 
     PermissionEntity that = (PermissionEntity) o;
 
-    if (!id.equals(that.id)) return false;
-    if (permissionName != null ? !permissionName.equals(that.permissionName) : that.permissionName != null)
-      return false;
-    if (resourceType != null ? !resourceType.equals(that.resourceType) : that.resourceType != null) return false;
-
-    return true;
+    return !(id != null ? !id.equals(that.id) : that.id != null) &&
+        !(permissionName != null ? !permissionName.equals(that.permissionName) : that.permissionName != null) &&
+        !(resourceType != null ? !resourceType.equals(that.resourceType) : that.resourceType != null);
   }
 
   @Override
   public int hashCode() {
-    int result = id.hashCode();
+    int result = id != null ? id.hashCode() : 0;
     result = 31 * result + (permissionName != null ? permissionName.hashCode() : 0);
     result = 31 * result + (resourceType != null ? resourceType.hashCode() : 0);
     return result;

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ResourceTypeEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ResourceTypeEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ResourceTypeEntity.java
index 9842a6a..1fdb737 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ResourceTypeEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ResourceTypeEntity.java
@@ -99,5 +99,26 @@ public class ResourceTypeEntity {
   public void setName(String name) {
     this.name = name;
   }
+
+
+  // ----- Object overrides --------------------------------------------------
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ResourceTypeEntity that = (ResourceTypeEntity) o;
+
+    return !(id != null ? !id.equals(that.id) : that.id != null) && !(name != null ?
+        !name.equals(that.name) : that.name != null);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = id != null ? id.hashCode() : 0;
+    result = 31 * result + (name != null ? name.hashCode() : 0);
+    return result;
+  }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
index 59d87aa..da6e2d2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
@@ -121,6 +121,18 @@ public class ViewEntity implements ViewDefinition {
   @OneToMany(cascade = CascadeType.ALL, mappedBy = "view")
   private Collection<ViewInstanceEntity> instances = new HashSet<ViewInstanceEntity>();
 
+  /**
+   * The list of view permissions.
+   */
+  @OneToMany(cascade = CascadeType.ALL)
+  @JoinColumns({
+      @JoinColumn(name = "resource_type_id", referencedColumnName = "resource_type_id", nullable = false),
+  })
+  private Collection<PermissionEntity> permissions = new HashSet<PermissionEntity>();
+
+  /**
+   * The resource type.
+   */
   @ManyToOne
   @JoinColumns({
       @JoinColumn(name = "resource_type_id", referencedColumnName = "resource_type_id", nullable = false),
@@ -352,6 +364,41 @@ public class ViewEntity implements ViewDefinition {
   }
 
   /**
+   * Get the view custom permissions.
+   *
+   * @return the view permissions
+   */
+  public Collection<PermissionEntity> getPermissions() {
+    return permissions;
+  }
+
+  /**
+   * Set the custom view permissions.
+   *
+   * @param permissions  the permissions
+   */
+  public void setPermissions(Collection<PermissionEntity> permissions) {
+    this.permissions = permissions;
+  }
+
+  /**
+   * Get the permission entity for the given permission name.
+   *
+   * @param permissionName  the permission name
+   *
+   * @return the matching permission entity or null
+   */
+  public PermissionEntity getPermission(String permissionName) {
+
+    for (PermissionEntity permissionEntity : permissions) {
+      if (permissionEntity.getPermissionName().equals(permissionName)) {
+        return permissionEntity;
+      }
+    }
+    return null;
+  }
+
+  /**
    * Get the view resources.
    *
    * @return the view resources

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
index 6426575..d36ad6e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
@@ -21,13 +21,19 @@ package org.apache.ambari.server.view;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
+import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.ViewEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.server.view.configuration.ParameterConfig;
+import org.apache.ambari.server.view.configuration.ViewConfig;
 import org.apache.ambari.server.view.events.EventImpl;
 import org.apache.ambari.server.view.persistence.DataStoreImpl;
 import org.apache.ambari.server.view.persistence.DataStoreModule;
 import org.apache.ambari.view.DataStore;
+import org.apache.ambari.view.MaskException;
+import org.apache.ambari.view.Masker;
 import org.apache.ambari.view.ResourceProvider;
+import org.apache.ambari.view.SecurityException;
 import org.apache.ambari.view.URLStreamProvider;
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewController;
@@ -35,6 +41,9 @@ import org.apache.ambari.view.ViewDefinition;
 import org.apache.ambari.view.ViewInstanceDefinition;
 import org.apache.ambari.view.events.Event;
 import org.apache.ambari.view.events.Listener;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.Velocity;
 import org.apache.velocity.exception.ParseErrorException;
@@ -51,14 +60,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import org.apache.ambari.server.view.configuration.ParameterConfig;
-import org.apache.ambari.server.view.configuration.ViewConfig;
-import org.apache.ambari.view.MaskException;
-import org.apache.ambari.view.Masker;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
 /**
  * View context implementation.
  */
@@ -239,6 +240,32 @@ public class ViewContextImpl implements ViewContext, ViewController {
   }
 
   @Override
+  public void hasPermission(String userName, String permissionName) throws org.apache.ambari.view.SecurityException {
+
+    if (userName == null || userName.length() == 0) {
+      throw new SecurityException("No user name specified.");
+    }
+
+    if (permissionName == null || permissionName.length() == 0) {
+      throw new SecurityException("No permission name specified.");
+    }
+
+    if (viewInstanceEntity == null) {
+      throw new SecurityException("There is no instance associated with the view context");
+    }
+
+    PermissionEntity permissionEntity = viewEntity.getPermission(permissionName);
+
+    if (permissionEntity == null) {
+      throw new SecurityException("The permission " + permissionName + " is not defined for " + viewEntity.getName());
+    }
+
+    if (!viewRegistry.hasPermission(permissionEntity, viewInstanceEntity.getResource(), userName)) {
+      throw new SecurityException("The user " + userName + " has not been granted permission " + permissionName);
+    }
+  }
+
+  @Override
   public URLStreamProvider getURLStreamProvider() {
     return streamProvider;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
index 4859836..7b7d9a4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -29,12 +29,19 @@ import org.apache.ambari.server.api.services.ViewExternalSubResourceService;
 import org.apache.ambari.server.api.services.ViewSubResourceService;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.orm.dao.MemberDAO;
+import org.apache.ambari.server.orm.dao.PrivilegeDAO;
 import org.apache.ambari.server.orm.dao.ResourceDAO;
 import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
+import org.apache.ambari.server.orm.dao.UserDAO;
 import org.apache.ambari.server.orm.dao.ViewDAO;
 import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
+import org.apache.ambari.server.orm.entities.GroupEntity;
+import org.apache.ambari.server.orm.entities.MemberEntity;
+import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.ResourceEntity;
 import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.orm.entities.ViewEntity;
 import org.apache.ambari.server.orm.entities.ViewEntityEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceDataEntity;
@@ -44,6 +51,7 @@ import org.apache.ambari.server.orm.entities.ViewResourceEntity;
 import org.apache.ambari.server.view.configuration.EntityConfig;
 import org.apache.ambari.server.view.configuration.InstanceConfig;
 import org.apache.ambari.server.view.configuration.ParameterConfig;
+import org.apache.ambari.server.view.configuration.PermissionConfig;
 import org.apache.ambari.server.view.configuration.PersistenceConfig;
 import org.apache.ambari.server.view.configuration.PropertyConfig;
 import org.apache.ambari.server.view.configuration.ResourceConfig;
@@ -164,6 +172,21 @@ public class ViewRegistry {
    */
   private static ResourceTypeDAO resourceTypeDAO;
 
+  /**
+   * User data access object.
+   */
+  private static UserDAO userDAO;
+
+  /**
+   * Group member data access object.
+   */
+  private static MemberDAO memberDAO;
+
+  /**
+   * Privilege data access object.
+   */
+  private static PrivilegeDAO privilegeDAO;
+
 
   // ----- Constructors ------------------------------------------------------
 
@@ -198,6 +221,23 @@ public class ViewRegistry {
   }
 
   /**
+   * Get the view definition for the given resource type.
+   *
+   * @param resourceTypeEntity  the resource type
+   *
+   * @return the view definition for the given resource type or null
+   */
+  public ViewEntity getDefinition(ResourceTypeEntity resourceTypeEntity) {
+
+    for (ViewEntity viewEntity : viewDefinitions.values()) {
+      if (viewEntity.getResourceType().equals(resourceTypeEntity)) {
+        return viewEntity;
+      }
+    }
+    return null;
+  }
+
+  /**
    * Add a view definition to the registry.
    *
    * @param definition  the definition
@@ -605,6 +645,43 @@ public class ViewRegistry {
     listeners.add(listener);
   }
 
+  /**
+   * Determine whether or not the access specified by the given permission
+   * is permitted for the given user on the view instance identified by
+   * the given resource.
+   *
+   * @param permissionEntity  the permission entity
+   * @param resourceEntity    the resource entity
+   * @param userName          the user name
+   *
+   * @return true if the access specified by the given permission
+   *         is permitted for the given user.
+   */
+  public boolean hasPermission(PermissionEntity permissionEntity, ResourceEntity resourceEntity, String userName) {
+
+    UserEntity userEntity = userDAO.findLocalUserByName(userName);
+
+    if (userEntity == null) {
+      return false;
+    }
+
+    if (privilegeDAO.exists(userEntity.getPrincipal(), resourceEntity, permissionEntity)) {
+      return true;
+    }
+
+    List<MemberEntity> memberEntities = memberDAO.findAllMembersByUser(userEntity);
+
+    for (MemberEntity memberEntity : memberEntities) {
+
+      GroupEntity groupEntity = memberEntity.getGroup();
+
+      if (privilegeDAO.exists(groupEntity.getPrincipal(), resourceEntity, permissionEntity)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
 
   // ----- helper methods ----------------------------------------------------
 
@@ -700,6 +777,24 @@ public class ViewRegistry {
       }
       viewDefinition.setResources(resources);
     }
+
+    ResourceTypeEntity resourceTypeEntity = new ResourceTypeEntity();
+    resourceTypeEntity.setName(viewDefinition.getName());
+
+    viewDefinition.setResourceType(resourceTypeEntity);
+
+    List<PermissionConfig> permissionConfigurations = viewConfig.getPermissions();
+
+    Collection<PermissionEntity> permissions = new HashSet<PermissionEntity>();
+    for (PermissionConfig permissionConfiguration : permissionConfigurations) {
+      PermissionEntity permissionEntity =  new PermissionEntity();
+
+      permissionEntity.setPermissionName(permissionConfiguration.getName());
+      permissionEntity.setResourceType(resourceTypeEntity);
+      permissions.add(permissionEntity);
+    }
+    viewDefinition.setPermissions(permissions);
+
     View view = null;
     if (viewConfig.getView() != null) {
       view = getView(viewConfig.getViewClass(cl), new ViewContextImpl(viewDefinition, this));
@@ -774,6 +869,10 @@ public class ViewRegistry {
 
     setPersistenceEntities(viewInstanceDefinition);
 
+    ResourceEntity resourceEntity = new ResourceEntity();
+    resourceEntity.setResourceType(viewDefinition.getResourceType());
+    viewInstanceDefinition.setResource(resourceEntity);
+
     viewDefinition.addInstanceDefinition(viewInstanceDefinition);
   }
 
@@ -885,35 +984,8 @@ public class ViewRegistry {
       if (LOG.isDebugEnabled()) {
         LOG.debug("Creating View " + viewName + ".");
       }
-      // get or create an admin resource type to represent this view
-      ResourceTypeEntity resourceTypeEntity = resourceTypeDAO.findByName(viewName);
-      if (resourceTypeEntity == null) {
-        resourceTypeEntity = new ResourceTypeEntity();
-        resourceTypeEntity.setName(view.getName());
-        resourceTypeDAO.create(resourceTypeEntity);
-      }
-
-      view.setResourceType(resourceTypeEntity);
-
-      for( ViewInstanceEntity instance : view.getInstances()) {
-
-        // create an admin resource to represent this view instance
-        ResourceEntity resourceEntity = new ResourceEntity();
-        resourceEntity.setResourceType(resourceTypeEntity);
-        resourceDAO.create(resourceEntity);
-
-        instance.setResource(resourceEntity);
-      }
       // ... merge it
-      viewDAO.merge(view);
-
-      persistedView = viewDAO.findByName(viewName);
-      if (persistedView == null) {
-        String message = "View  " + persistedView.getViewName() + " can not be found.";
-
-        LOG.error(message);
-        throw new IllegalStateException(message);
-      }
+      persistedView = viewDAO.merge(view);
     }
 
     Map<String, ViewInstanceEntity> instanceEntityMap = new HashMap<String, ViewInstanceEntity>();
@@ -921,6 +993,9 @@ public class ViewRegistry {
       instanceEntityMap.put(instance.getName(), instance);
     }
 
+    view.setResourceType(persistedView.getResourceType());
+    view.setPermissions(persistedView.getPermissions());
+
     // make sure that each instance of the view in the db is reflected in the given view
     for (ViewInstanceEntity persistedInstance : persistedView.getInstances()){
       String instanceName = persistedInstance.getName();
@@ -947,9 +1022,7 @@ public class ViewRegistry {
       instance.setProperties(persistedInstance.getProperties());
       instance.setEntities(persistedInstance.getEntities());
 
-      if (instance.getResource() == null) {
-        instance.setResource(persistedInstance.getResource());
-      }
+      instance.setResource(persistedInstance.getResource());
     }
 
     // these instances appear in the archive but have been deleted
@@ -1078,12 +1151,20 @@ public class ViewRegistry {
    * @param instanceDAO      view instance data access object
    * @param resourceDAO      resource data access object
    * @param resourceTypeDAO  resource type data access object
+   * @param userDAO          user data access object
+   * @param memberDAO        group member data access object
+   * @param privilegeDAO     the privilege data access object
    */
-  public static void init(ViewDAO viewDAO, ViewInstanceDAO instanceDAO, ResourceDAO resourceDAO, ResourceTypeDAO resourceTypeDAO) {
+  public static void init(ViewDAO viewDAO, ViewInstanceDAO instanceDAO, ResourceDAO resourceDAO,
+                          ResourceTypeDAO resourceTypeDAO, UserDAO userDAO, MemberDAO memberDAO,
+                          PrivilegeDAO privilegeDAO) {
     setViewDAO(viewDAO);
     setInstanceDAO(instanceDAO);
     setResourceDAO(resourceDAO);
     setResourceTypeDAO(resourceTypeDAO);
+    setUserDAO(userDAO);
+    setMemberDAO(memberDAO);
+    setPrivilegeDAO(privilegeDAO);
   }
 
   /**
@@ -1122,6 +1203,33 @@ public class ViewRegistry {
     ViewRegistry.resourceTypeDAO = resourceTypeDAO;
   }
 
+  /**
+   * Set the user DAO.
+   *
+   * @param userDAO  the user DAO
+   */
+  protected static void setUserDAO(UserDAO userDAO) {
+    ViewRegistry.userDAO = userDAO;
+  }
+
+  /**
+   * Set the group member DAO.
+   *
+   * @param memberDAO  the group member DAO
+   */
+  protected static void setMemberDAO(MemberDAO memberDAO) {
+    ViewRegistry.memberDAO = memberDAO;
+  }
+
+  /**
+   * Set the privilege DAO.
+   *
+   * @param privilegeDAO  the privilege DAO
+   */
+  protected static void setPrivilegeDAO(PrivilegeDAO privilegeDAO) {
+    ViewRegistry.privilegeDAO = privilegeDAO;
+  }
+
 
   // ----- inner class : ViewRegistryHelper ----------------------------------
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/PermissionConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/PermissionConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/PermissionConfig.java
new file mode 100644
index 0000000..07d1b53
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/PermissionConfig.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.ambari.server.view.configuration;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+/**
+ * View custom permission configuration.
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class PermissionConfig {
+  private String name;
+  private String description;
+
+  public String getName() {
+    return name;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
index e084918..ddca446 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
@@ -109,6 +109,12 @@ public class ViewConfig {
   private PersistenceConfig persistence;
 
   /**
+   * The list of view parameters.
+   */
+  @XmlElement(name="permission")
+  private List<PermissionConfig> permissions;
+
+  /**
    * Get the unique name.
    *
    * @return the view name
@@ -241,4 +247,13 @@ public class ViewConfig {
   public PersistenceConfig getPersistence() {
     return persistence;
   }
+
+  /**
+   * Get the list of custom permissions defined for the view.
+   *
+   * @return the list of custom permissions
+   */
+  public List<PermissionConfig> getPermissions() {
+    return permissions == null ? Collections.<PermissionConfig>emptyList() : permissions;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index f3cac2e..cf51a49 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -129,6 +129,7 @@ ALTER TABLE viewentity ADD CONSTRAINT FK_viewentity_view_name FOREIGN KEY (view_
 ALTER TABLE adminresource ADD CONSTRAINT FK_resource_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);
 ALTER TABLE adminprincipal ADD CONSTRAINT FK_principal_principal_type_id FOREIGN KEY (principal_type_id) REFERENCES adminprincipaltype(principal_type_id);
 ALTER TABLE adminpermission ADD CONSTRAINT FK_permission_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);
+ALTER TABLE adminpermission ADD CONSTRAINT UQ_permission_name_resource_type_id UNIQUE (permission_name, resource_type_id);
 ALTER TABLE adminprivilege ADD CONSTRAINT FK_privilege_permission_id FOREIGN KEY (permission_id) REFERENCES adminpermission(permission_id);
 ALTER TABLE adminprivilege ADD CONSTRAINT FK_privilege_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id);
 ALTER TABLE viewmain ADD CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index 2328ffc..c05affd 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -119,6 +119,7 @@ ALTER TABLE viewentity ADD CONSTRAINT FK_viewentity_view_name FOREIGN KEY (view_
 ALTER TABLE adminresource ADD CONSTRAINT FK_resource_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);
 ALTER TABLE adminprincipal ADD CONSTRAINT FK_principal_principal_type_id FOREIGN KEY (principal_type_id) REFERENCES adminprincipaltype(principal_type_id);
 ALTER TABLE adminpermission ADD CONSTRAINT FK_permission_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);
+ALTER TABLE adminpermission ADD CONSTRAINT UQ_permission_name_resource_type_id UNIQUE (permission_name, resource_type_id);
 ALTER TABLE adminprivilege ADD CONSTRAINT FK_privilege_permission_id FOREIGN KEY (permission_id) REFERENCES adminpermission(permission_id);
 ALTER TABLE adminprivilege ADD CONSTRAINT FK_privilege_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id);
 ALTER TABLE viewmain ADD CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 43addca..82335e3 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -152,6 +152,7 @@ ALTER TABLE viewentity ADD CONSTRAINT FK_viewentity_view_name FOREIGN KEY (view_
 ALTER TABLE adminresource ADD CONSTRAINT FK_resource_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);
 ALTER TABLE adminprincipal ADD CONSTRAINT FK_principal_principal_type_id FOREIGN KEY (principal_type_id) REFERENCES adminprincipaltype(principal_type_id);
 ALTER TABLE adminpermission ADD CONSTRAINT FK_permission_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);
+ALTER TABLE adminpermission ADD CONSTRAINT UQ_permission_name_resource_type_id UNIQUE (permission_name, resource_type_id);
 ALTER TABLE adminprivilege ADD CONSTRAINT FK_privilege_permission_id FOREIGN KEY (permission_id) REFERENCES adminpermission(permission_id);
 ALTER TABLE adminprivilege ADD CONSTRAINT FK_privilege_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id);
 ALTER TABLE viewmain ADD CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index 2fc99be..b5fcd94 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -215,6 +215,7 @@ ALTER TABLE ambari.viewentity ADD CONSTRAINT FK_viewentity_view_name FOREIGN KEY
 ALTER TABLE ambari.adminresource ADD CONSTRAINT FK_resource_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);
 ALTER TABLE ambari.adminprincipal ADD CONSTRAINT FK_principal_principal_type_id FOREIGN KEY (principal_type_id) REFERENCES adminprincipaltype(principal_type_id);
 ALTER TABLE ambari.adminpermission ADD CONSTRAINT FK_permission_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);
+ALTER TABLE ambari.adminpermission ADD CONSTRAINT UQ_permission_name_resource_type_id UNIQUE (permission_name, resource_type_id);
 ALTER TABLE ambari.adminprivilege ADD CONSTRAINT FK_privilege_permission_id FOREIGN KEY (permission_id) REFERENCES adminpermission(permission_id);
 ALTER TABLE ambari.adminprivilege ADD CONSTRAINT FK_privilege_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id);
 ALTER TABLE viewmain ADD CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id);

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewPermissionResourceDefinitionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewPermissionResourceDefinitionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewPermissionResourceDefinitionTest.java
new file mode 100644
index 0000000..fbb20f2
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewPermissionResourceDefinitionTest.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Set;
+
+/**
+ * ViewPermissionResourceDefinition tests.
+ */
+public class ViewPermissionResourceDefinitionTest {
+  @Test
+  public void testGetPluralName() throws Exception {
+    ViewPermissionResourceDefinition ViewPermissionResourceDefinition = new ViewPermissionResourceDefinition();
+    Assert.assertEquals("permissions", ViewPermissionResourceDefinition.getPluralName());
+  }
+
+  @Test
+  public void testGetSingularName() throws Exception {
+    ViewPermissionResourceDefinition ViewPermissionResourceDefinition = new ViewPermissionResourceDefinition();
+    Assert.assertEquals("permission", ViewPermissionResourceDefinition.getSingularName());
+  }
+
+  @Test
+  public void testGetSubResourceDefinitions() throws Exception {
+    ViewPermissionResourceDefinition ViewPermissionResourceDefinition = new ViewPermissionResourceDefinition();
+    Set<SubResourceDefinition> subResourceDefinitions = ViewPermissionResourceDefinition.getSubResourceDefinitions ();
+
+    Assert.assertTrue(subResourceDefinitions.isEmpty());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinitionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinitionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinitionTest.java
index 32c13b3..d83c902 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinitionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewVersionResourceDefinitionTest.java
@@ -44,8 +44,11 @@ public class ViewVersionResourceDefinitionTest {
     ViewVersionResourceDefinition viewVersionResourceDefinition = new ViewVersionResourceDefinition();
     Set<SubResourceDefinition> subResourceDefinitions = viewVersionResourceDefinition.getSubResourceDefinitions ();
 
-    Assert.assertEquals(1, subResourceDefinitions.size());
+    Assert.assertEquals(2, subResourceDefinitions.size());
 
-    Assert.assertEquals("ViewInstance", subResourceDefinitions.iterator().next().getType().name());
+    for (SubResourceDefinition subResourceDefinition : subResourceDefinitions) {
+      String name = subResourceDefinition.getType().name();
+      Assert.assertTrue(name.equals("ViewInstance") || name.equals("ViewPermission"));
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewPermissionServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewPermissionServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewPermissionServiceTest.java
new file mode 100644
index 0000000..f841be9
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewPermissionServiceTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
+import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for ViewPermissionService.
+ */
+public class ViewPermissionServiceTest extends BaseServiceTest {
+
+
+  public List<ServiceTestInvocation> getTestInvocations() throws Exception {
+    List<ServiceTestInvocation> listInvocations = new ArrayList<ServiceTestInvocation>();
+
+    //getPermission
+    ViewPermissionService permissionService = new TestViewPermissionService("MY_VIEW", "1.0", "permissionName");
+    Method m = permissionService.getClass().getMethod("getPermission", HttpHeaders.class, UriInfo.class, String.class);
+    Object[] args = new Object[] {getHttpHeaders(), getUriInfo(), "permissionName"};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.GET, permissionService, m, args, null));
+
+    //getPermissions
+    permissionService = new TestViewPermissionService("MY_VIEW", "1.0",null);
+    m = permissionService.getClass().getMethod("getPermissions", HttpHeaders.class, UriInfo.class);
+    args = new Object[] {getHttpHeaders(), getUriInfo()};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.GET, permissionService, m, args, null));
+
+    //createPermission
+    permissionService = new TestViewPermissionService("MY_VIEW", "1.0","permissionName");
+    m = permissionService.getClass().getMethod("createPermission", String.class, HttpHeaders.class, UriInfo.class, String.class);
+    args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "permissionName"};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.POST, permissionService, m, args, "body"));
+
+    //deletePermission
+    permissionService = new TestViewPermissionService("MY_VIEW", "1.0","permissionName");
+    m = permissionService.getClass().getMethod("deletePermission", HttpHeaders.class, UriInfo.class, String.class);
+    args = new Object[] {getHttpHeaders(), getUriInfo(), "permissionName"};
+    listInvocations.add(new ServiceTestInvocation(Request.Type.DELETE, permissionService, m, args, null));
+
+    return listInvocations;
+  }
+
+
+  private class TestViewPermissionService extends ViewPermissionService {
+    private String permissionId;
+
+    private TestViewPermissionService(String viewName, String version, String permissionId) {
+
+      super(viewName, version);
+      this.permissionId = permissionId;
+    }
+
+    @Override
+    protected ResourceInstance createPermissionResource(String viewName, String viewVersion, String permissionId) {
+      assertEquals(this.permissionId, permissionId);
+      return getTestResource();
+    }
+
+    @Override
+    RequestFactory getRequestFactory() {
+      return getTestRequestFactory();
+    }
+
+    @Override
+    protected RequestBodyParser getBodyParser() {
+      return getTestBodyParser();
+    }
+
+    @Override
+    protected ResultSerializer getResultSerializer() {
+      return getTestResultSerializer();
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
index 5bd5c38..fbe1c90 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
@@ -22,8 +22,11 @@ import org.apache.ambari.server.api.resources.SubResourceDefinition;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.orm.dao.MemberDAO;
+import org.apache.ambari.server.orm.dao.PrivilegeDAO;
 import org.apache.ambari.server.orm.dao.ResourceDAO;
 import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
+import org.apache.ambari.server.orm.dao.UserDAO;
 import org.apache.ambari.server.orm.dao.ViewDAO;
 import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
 import org.apache.ambari.server.orm.entities.ResourceEntity;
@@ -175,12 +178,22 @@ public class ViewRegistryTest {
     ViewRegistry.setViewDAO(vDAO);
 
     ViewEntity viewDefinition = ViewEntityTest.getViewEntity();
+    viewDefinition.setResourceType(resourceTypeEntity);
 
-    viewDefinition.setInstances(ViewInstanceEntityTest.getViewInstanceEntities(viewDefinition));
+    Set<ViewInstanceEntity> viewInstanceEntities = ViewInstanceEntityTest.getViewInstanceEntities(viewDefinition);
+    viewDefinition.setInstances(viewInstanceEntities);
 
     Map<File, ViewConfig> viewConfigs =
         Collections.singletonMap(viewArchive, viewDefinition.getConfiguration());
 
+    long resourceId = 99L;
+    for (ViewInstanceEntity viewInstanceEntity : viewInstanceEntities) {
+      ResourceEntity resourceEntity = new ResourceEntity();
+      resourceEntity.setId(resourceId);
+      resourceEntity.setResourceType(resourceTypeEntity);
+      viewInstanceEntity.setResource(resourceEntity);
+    }
+
     Map<String, File> files = new HashMap<String, File>();
 
     files.put("/var/lib/ambari-server/resources/views/work", extractedArchiveDir);
@@ -242,17 +255,10 @@ public class ViewRegistryTest {
     Capture<ViewEntity> captureViewEntity = new Capture<ViewEntity>();
 
     expect(vDAO.findByName("MY_VIEW{1.0.0}")).andReturn(null);
-    expect(vDAO.merge(capture(captureViewEntity))).andReturn(null);
-    expect(vDAO.findByName("MY_VIEW{1.0.0}")).andReturn(viewDefinition);
+    expect(vDAO.merge(capture(captureViewEntity))).andReturn(viewDefinition);
 
     expect(vDAO.findAll()).andReturn(Collections.<ViewEntity>emptyList());
 
-    expect(rtDAO.findByName("MY_VIEW{1.0.0}")).andReturn(resourceTypeEntity);
-
-    Capture<ResourceEntity> resourceEntityCapture = new Capture<ResourceEntity>();
-    rDAO.create(capture(resourceEntityCapture));
-    rDAO.create(capture(resourceEntityCapture));
-
     // replay mocks
     replay(configuration, viewDir, extractedArchiveDir, viewArchive, archiveDir, entryFile, classesDir,
         libDir, fileEntry, viewJarFile, enumeration, jarEntry, is, fos, vDAO, rtDAO, rDAO);
@@ -305,10 +311,22 @@ public class ViewRegistryTest {
     ViewRegistry.setViewDAO(vDAO);
 
     ViewEntity viewDefinition = ViewEntityTest.getViewEntity();
+    viewDefinition.setResourceType(resourceTypeEntity);
+
+    Set<ViewInstanceEntity> viewInstanceEntities = ViewInstanceEntityTest.getViewInstanceEntities(viewDefinition);
+    viewDefinition.setInstances(viewInstanceEntities);
 
     Map<File, ViewConfig> viewConfigs =
         Collections.singletonMap(viewArchive, viewDefinition.getConfiguration());
 
+    long resourceId = 99L;
+    for (ViewInstanceEntity viewInstanceEntity : viewInstanceEntities) {
+      ResourceEntity resourceEntity = new ResourceEntity();
+      resourceEntity.setId(resourceId);
+      resourceEntity.setResourceType(resourceTypeEntity);
+      viewInstanceEntity.setResource(resourceEntity);
+    }
+
     Map<String, File> files = new HashMap<String, File>();
 
     files.put("/var/lib/ambari-server/resources/views/work", extractedArchiveDir);
@@ -374,11 +392,7 @@ public class ViewRegistryTest {
 
     expect(vDAO.findAll()).andReturn(Collections.<ViewEntity>emptyList());
 
-    expect(rtDAO.findByName("MY_VIEW{1.0.0}")).andReturn(resourceTypeEntity);
-
     Capture<ResourceEntity> resourceEntityCapture = new Capture<ResourceEntity>();
-    rDAO.create(capture(resourceEntityCapture));
-    rDAO.create(capture(resourceEntityCapture));
 
     // replay mocks
     replay(configuration, viewDir, extractedArchiveDir, viewArchive, archiveDir, entryFile, classesDir,
@@ -511,8 +525,11 @@ public class ViewRegistryTest {
     ViewInstanceDAO viewInstanceDAO = createNiceMock(ViewInstanceDAO.class);
     ResourceDAO resourceDAO = createNiceMock(ResourceDAO.class);
     ResourceTypeDAO resourceTypeDAO = createNiceMock(ResourceTypeDAO.class);
+    UserDAO userDAO = createNiceMock(UserDAO.class);
+    MemberDAO memberDAO = createNiceMock(MemberDAO.class);
+    PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
 
-    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO);
+    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO, userDAO, memberDAO, privilegeDAO);
 
     ViewRegistry registry = ViewRegistry.getInstance();
 
@@ -549,8 +566,11 @@ public class ViewRegistryTest {
     ViewInstanceDAO viewInstanceDAO = createNiceMock(ViewInstanceDAO.class);
     ResourceDAO resourceDAO = createNiceMock(ResourceDAO.class);
     ResourceTypeDAO resourceTypeDAO = createNiceMock(ResourceTypeDAO.class);
+    UserDAO userDAO = createNiceMock(UserDAO.class);
+    MemberDAO memberDAO = createNiceMock(MemberDAO.class);
+    PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
 
-    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO);
+    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO, userDAO, memberDAO, privilegeDAO);
 
     ViewRegistry registry = ViewRegistry.getInstance();
 
@@ -582,8 +602,11 @@ public class ViewRegistryTest {
     ViewInstanceDAO viewInstanceDAO = createNiceMock(ViewInstanceDAO.class);
     ResourceDAO resourceDAO = createNiceMock(ResourceDAO.class);
     ResourceTypeDAO resourceTypeDAO = createNiceMock(ResourceTypeDAO.class);
+    UserDAO userDAO = createNiceMock(UserDAO.class);
+    MemberDAO memberDAO = createNiceMock(MemberDAO.class);
+    PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
 
-    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO);
+    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO, userDAO, memberDAO, privilegeDAO);
 
     ViewRegistry registry = ViewRegistry.getInstance();
 
@@ -616,8 +639,11 @@ public class ViewRegistryTest {
     ViewInstanceDAO viewInstanceDAO = createNiceMock(ViewInstanceDAO.class);
     ResourceDAO resourceDAO = createNiceMock(ResourceDAO.class);
     ResourceTypeDAO resourceTypeDAO = createNiceMock(ResourceTypeDAO.class);
+    UserDAO userDAO = createNiceMock(UserDAO.class);
+    MemberDAO memberDAO = createNiceMock(MemberDAO.class);
+    PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
 
-    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO);
+    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO, userDAO, memberDAO, privilegeDAO);
 
     ViewRegistry registry = ViewRegistry.getInstance();
 
@@ -658,8 +684,11 @@ public class ViewRegistryTest {
     ViewInstanceDAO viewInstanceDAO = createNiceMock(ViewInstanceDAO.class);
     ResourceDAO resourceDAO = createNiceMock(ResourceDAO.class);
     ResourceTypeDAO resourceTypeDAO = createNiceMock(ResourceTypeDAO.class);
+    UserDAO userDAO = createNiceMock(UserDAO.class);
+    MemberDAO memberDAO = createNiceMock(MemberDAO.class);
+    PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
 
-    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO);
+    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO, userDAO, memberDAO, privilegeDAO);
 
     ViewRegistry registry = ViewRegistry.getInstance();
 
@@ -698,8 +727,11 @@ public class ViewRegistryTest {
     ViewInstanceDAO viewInstanceDAO = createNiceMock(ViewInstanceDAO.class);
     ResourceDAO resourceDAO = createNiceMock(ResourceDAO.class);
     ResourceTypeDAO resourceTypeDAO = createNiceMock(ResourceTypeDAO.class);
+    UserDAO userDAO = createNiceMock(UserDAO.class);
+    MemberDAO memberDAO = createNiceMock(MemberDAO.class);
+    PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
 
-    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO);
+    ViewRegistry.init(viewDAO, viewInstanceDAO, resourceDAO, resourceTypeDAO, userDAO, memberDAO, privilegeDAO);
 
     ViewRegistry registry = ViewRegistry.getInstance();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/11336361/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/PermissionConfigTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/PermissionConfigTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/PermissionConfigTest.java
new file mode 100644
index 0000000..2600f17
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/PermissionConfigTest.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view.configuration;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.xml.bind.JAXBException;
+import java.util.List;
+
+/**
+ * EntityConfig tests.
+ */
+public class PermissionConfigTest {
+
+  private final static String xml = "<view>\n" +
+      "    <name>MY_VIEW</name>\n" +
+      "    <label>My View!</label>\n" +
+      "    <version>1.0.0</version>\n" +
+      "    <instance>\n" +
+      "        <name>INSTANCE1</name>\n" +
+      "    </instance>\n" +
+      "  <permission>\n" +
+      "    <name>RESTRICTED</name>\n" +
+      "    <description>Access permission for a restricted view resource.</description>\n" +
+      "  </permission>" +
+      "</view>";
+
+
+  @Test
+  public void testGetName() throws Exception {
+    List<PermissionConfig> permissions = getPremissionConfig();
+
+    Assert.assertEquals(1, permissions.size());
+
+    Assert.assertEquals("RESTRICTED", permissions.get(0).getName());
+  }
+
+  @Test
+  public void testGetDescription() throws Exception {
+    List<PermissionConfig> permissions = getPremissionConfig();
+
+    Assert.assertEquals(1, permissions.size());
+
+    Assert.assertEquals("Access permission for a restricted view resource.", permissions.get(0).getDescription());
+  }
+
+  public static List<PermissionConfig> getPremissionConfig() throws JAXBException {
+    ViewConfig config = ViewConfigTest.getConfig(xml);
+
+    return config.getPermissions();
+  }
+}