Added RBAC for REST APIs.

- admin role required for POST, PUT, DELETE & PATCH
- viewer role required for all other requests
- cleaned up all web.xml files for consistency and correctness

Change-Id: I33bad5cec0fb0f4285eed84173025b0a107b5aec
diff --git a/apps/acl/src/main/webapp/WEB-INF/web.xml b/apps/acl/src/main/webapp/WEB-INF/web.xml
index 27d9cc7..68b2485 100644
--- a/apps/acl/src/main/webapp/WEB-INF/web.xml
+++ b/apps/acl/src/main/webapp/WEB-INF/web.xml
@@ -31,11 +31,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/castor/src/main/webapp/WEB-INF/web.xml b/apps/castor/src/main/webapp/WEB-INF/web.xml
index 1c8762e..8ce51f7 100644
--- a/apps/castor/src/main/webapp/WEB-INF/web.xml
+++ b/apps/castor/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/cfm/nbi/src/main/webapp/WEB-INF/web.xml b/apps/cfm/nbi/src/main/webapp/WEB-INF/web.xml
index b4fb8f0..f8355c7 100644
--- a/apps/cfm/nbi/src/main/webapp/WEB-INF/web.xml
+++ b/apps/cfm/nbi/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/cord-support/src/main/webapp/WEB-INF/web.xml b/apps/cord-support/src/main/webapp/WEB-INF/web.xml
index caf7a5d..c204451 100644
--- a/apps/cord-support/src/main/webapp/WEB-INF/web.xml
+++ b/apps/cord-support/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/cpman/app/src/main/webapp/WEB-INF/web.xml b/apps/cpman/app/src/main/webapp/WEB-INF/web.xml
index dceaf96..74e321e 100644
--- a/apps/cpman/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/cpman/app/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml b/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml
index 30bd186..257119e 100644
--- a/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/faultmanagement/fmweb/src/main/webapp/WEB-INF/web.xml b/apps/faultmanagement/fmweb/src/main/webapp/WEB-INF/web.xml
index 9430499..6a172d0 100644
--- a/apps/faultmanagement/fmweb/src/main/webapp/WEB-INF/web.xml
+++ b/apps/faultmanagement/fmweb/src/main/webapp/WEB-INF/web.xml
@@ -20,6 +20,27 @@
          id="ONOS" version="2.5">
     <display-name>FM2 REST API v1.0</display-name>
 
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
diff --git a/apps/imr/api/src/main/webapp/WEB-INF/web.xml b/apps/imr/api/src/main/webapp/WEB-INF/web.xml
index ce093c0..2288b7f 100644
--- a/apps/imr/api/src/main/webapp/WEB-INF/web.xml
+++ b/apps/imr/api/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/kafka-integration/app/src/main/webapp/WEB-INF/web.xml b/apps/kafka-integration/app/src/main/webapp/WEB-INF/web.xml
index 3ad1602..d30a300 100644
--- a/apps/kafka-integration/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/kafka-integration/app/src/main/webapp/WEB-INF/web.xml
@@ -20,6 +20,27 @@
          id="ONOS" version="2.5">
     <display-name>Event Exporter REST API</display-name>
 
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
diff --git a/apps/mappingmanagement/web/src/main/webapp/WEB-INF/web.xml b/apps/mappingmanagement/web/src/main/webapp/WEB-INF/web.xml
index 8fe0170..800f523 100644
--- a/apps/mappingmanagement/web/src/main/webapp/WEB-INF/web.xml
+++ b/apps/mappingmanagement/web/src/main/webapp/WEB-INF/web.xml
@@ -27,11 +27,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/mcast/web/src/main/webapp/WEB-INF/web.xml b/apps/mcast/web/src/main/webapp/WEB-INF/web.xml
index d1f8718..b382fb6 100644
--- a/apps/mcast/web/src/main/webapp/WEB-INF/web.xml
+++ b/apps/mcast/web/src/main/webapp/WEB-INF/web.xml
@@ -27,11 +27,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/mfwd/src/main/webapp/WEB-INF/web.xml b/apps/mfwd/src/main/webapp/WEB-INF/web.xml
index 9757ff4..19afe5e 100644
--- a/apps/mfwd/src/main/webapp/WEB-INF/web.xml
+++ b/apps/mfwd/src/main/webapp/WEB-INF/web.xml
@@ -20,6 +20,27 @@
          id="ONOS" version="2.5">
     <display-name>ONOS APP MFWD</display-name>
 
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
diff --git a/apps/ofagent/src/main/webapp/WEB-INF/web.xml b/apps/ofagent/src/main/webapp/WEB-INF/web.xml
index cc3d463..b71cf1d 100644
--- a/apps/ofagent/src/main/webapp/WEB-INF/web.xml
+++ b/apps/ofagent/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/openstacknetworking/app/src/main/webapp/WEB-INF/web.xml b/apps/openstacknetworking/app/src/main/webapp/WEB-INF/web.xml
index 9194183..017ef9c 100644
--- a/apps/openstacknetworking/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/openstacknetworking/app/src/main/webapp/WEB-INF/web.xml
@@ -27,11 +27,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/openstacknetworkingui/src/main/webapp/WEB-INF/web.xml b/apps/openstacknetworkingui/src/main/webapp/WEB-INF/web.xml
index 616ad86..d5d4006 100644
--- a/apps/openstacknetworkingui/src/main/webapp/WEB-INF/web.xml
+++ b/apps/openstacknetworkingui/src/main/webapp/WEB-INF/web.xml
@@ -20,6 +20,27 @@
          id="ONOS" version="2.5">
     <display-name>SONA GUI REST API v1.0</display-name>
 
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
diff --git a/apps/openstacknode/app/src/main/webapp/WEB-INF/web.xml b/apps/openstacknode/app/src/main/webapp/WEB-INF/web.xml
index e1f7ceb..ed670dd 100644
--- a/apps/openstacknode/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/openstacknode/app/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/openstacktelemetry/app/src/main/webapp/WEB-INF/web.xml b/apps/openstacktelemetry/app/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..1181c43
--- /dev/null
+++ b/apps/openstacktelemetry/app/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2018-present Open Networking Foundation
+  ~
+  ~ Licensed 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.
+  -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         id="ONOS" version="2.5">
+    <display-name>Openstack Telemetry REST API v1.0</display-name>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
+    <servlet>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>javax.ws.rs.Application</param-name>
+            <param-value>org.onosproject.openstacktelemetry.web.OpenstackTelemetryWebApplication</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>
diff --git a/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml b/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..8b44537
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2018-present Open Networking Foundation
+  ~
+  ~ Licensed 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.
+  -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         id="ONOS" version="2.5">
+    <display-name>Openstack vTap REST API v1.0</display-name>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
+    <servlet>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>javax.ws.rs.Application</param-name>
+            <param-value>org.onosproject.openstackvtap.web.OpenstackVtapWebApplication</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>
diff --git a/apps/optical-rest/src/main/webapp/WEB-INF/web.xml b/apps/optical-rest/src/main/webapp/WEB-INF/web.xml
index 1437d86..a55f02b 100644
--- a/apps/optical-rest/src/main/webapp/WEB-INF/web.xml
+++ b/apps/optical-rest/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/pce/pcerest/pom.xml b/apps/pce/pcerest/pom.xml
index 199cdab..498de18 100644
--- a/apps/pce/pcerest/pom.xml
+++ b/apps/pce/pcerest/pom.xml
@@ -96,7 +96,18 @@
             <artifactId>onos-apps-pce-app</artifactId>
             <version>${project.version}</version>
         </dependency>
-
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+            <classifier>tests</classifier>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/apps/pce/pcerest/src/main/resources/WEB-INF/web.xml b/apps/pce/pcerest/src/main/resources/WEB-INF/web.xml
index ae129fc..388044a 100644
--- a/apps/pce/pcerest/src/main/resources/WEB-INF/web.xml
+++ b/apps/pce/pcerest/src/main/resources/WEB-INF/web.xml
@@ -20,6 +20,27 @@
          id="ONOS" version="2.5">
     <display-name>PCE REST API v1.0</display-name>
 
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
diff --git a/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PceResourceTest.java b/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PceResourceTest.java
index 1f69801..a24c874 100644
--- a/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PceResourceTest.java
+++ b/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PceResourceTest.java
@@ -18,6 +18,7 @@
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 import org.glassfish.jersey.test.TestProperties;
+import org.onlab.rest.AuthorizationFilter;
 
 /**
  * Base class for pce rest api tests.  Performs common configuration operations.
@@ -29,6 +30,7 @@
      */
     public PceResourceTest() {
         super(ResourceConfig.forApplicationClass(PceWebApplication.class));
+        AuthorizationFilter.disableForTests();
         set(TestProperties.CONTAINER_PORT, 0);
     }
 }
diff --git a/apps/powermanagement/src/main/webapp/WEB-INF/web.xml b/apps/powermanagement/src/main/webapp/WEB-INF/web.xml
index f3440ee..7a6e3be 100644
--- a/apps/powermanagement/src/main/webapp/WEB-INF/web.xml
+++ b/apps/powermanagement/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/route-service/app/src/main/webapp/WEB-INF/web.xml b/apps/route-service/app/src/main/webapp/WEB-INF/web.xml
index 6b1d27a..1c3d2b0 100644
--- a/apps/route-service/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/route-service/app/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/segmentrouting/web/src/main/webapp/WEB-INF/web.xml b/apps/segmentrouting/web/src/main/webapp/WEB-INF/web.xml
index 73154e3..1362728 100644
--- a/apps/segmentrouting/web/src/main/webapp/WEB-INF/web.xml
+++ b/apps/segmentrouting/web/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/simplefabric/src/main/webapp/WEB-INF/web.xml b/apps/simplefabric/src/main/webapp/WEB-INF/web.xml
index a0e0004..e136671 100644
--- a/apps/simplefabric/src/main/webapp/WEB-INF/web.xml
+++ b/apps/simplefabric/src/main/webapp/WEB-INF/web.xml
@@ -27,11 +27,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/t3/web/src/main/webapp/WEB-INF/web.xml b/apps/t3/web/src/main/webapp/WEB-INF/web.xml
index d99a6ae..9bed969 100644
--- a/apps/t3/web/src/main/webapp/WEB-INF/web.xml
+++ b/apps/t3/web/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/apps/test/demo/src/main/webapp/WEB-INF/web.xml b/apps/test/demo/src/main/webapp/WEB-INF/web.xml
index acc738e..04701ab 100644
--- a/apps/test/demo/src/main/webapp/WEB-INF/web.xml
+++ b/apps/test/demo/src/main/webapp/WEB-INF/web.xml
@@ -20,6 +20,27 @@
          id="ONOS" version="2.5">
     <display-name>ONOS DEMO APP API v1.0</display-name>
 
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
diff --git a/apps/virtualbng/src/main/webapp/WEB-INF/web.xml b/apps/virtualbng/src/main/webapp/WEB-INF/web.xml
index b66d9bf..d395d3d 100644
--- a/apps/virtualbng/src/main/webapp/WEB-INF/web.xml
+++ b/apps/virtualbng/src/main/webapp/WEB-INF/web.xml
@@ -20,6 +20,27 @@
          id="ONOS" version="2.5">
     <display-name>ONOS Virtual BNG APP REST API</display-name>
 
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
diff --git a/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml b/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml
index f83ad87..8c368d9 100644
--- a/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml
+++ b/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml
@@ -20,7 +20,6 @@
          id="ONOS" version="2.5">
     <display-name>VTNRSC REST API v1.0</display-name>
 
-    <!-- TODO: this should be uncommented
     <security-constraint>
         <web-resource-collection>
             <web-resource-name>Secured</web-resource-name>
@@ -28,18 +27,19 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
         <auth-method>BASIC</auth-method>
         <realm-name>karaf</realm-name>
     </login-config>
-    -->
 
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
diff --git a/apps/yang/web/src/main/webapp/WEB-INF/web.xml b/apps/yang/web/src/main/webapp/WEB-INF/web.xml
index 90f85fd..063aa5c 100644
--- a/apps/yang/web/src/main/webapp/WEB-INF/web.xml
+++ b/apps/yang/web/src/main/webapp/WEB-INF/web.xml
@@ -15,19 +15,38 @@
   ~ limitations under the License.
   -->
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
          id="ONOS" version="2.5">
-    <display-name>YANG LIVE COMPILER REST API v1.0</display-name>
+    <display-name>YANG Live Compiler REST API v1.0</display-name>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
 
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
-        <servlet-class>org.glassfish.jersey.servlet.ServletContainer
-        </servlet-class>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
         <init-param>
             <param-name>javax.ws.rs.Application</param-name>
-            <param-value>org.onosproject.yang.web.YangWebApplication
-            </param-value>
+            <param-value>org.onosproject.yang.web.YangWebApplication</param-value>
         </init-param>
         <init-param>
             <param-name>jersey.config.server.provider.classnames</param-name>
diff --git a/tools/package/archetypes/rest/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml b/tools/package/archetypes/rest/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml
index 015f85e..f2b06c7 100644
--- a/tools/package/archetypes/rest/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml
+++ b/tools/package/archetypes/rest/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml
@@ -28,11 +28,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/tools/package/runtime/bin/onos-compile-yang b/tools/package/runtime/bin/onos-compile-yang
index 22044b5..943716d 100755
--- a/tools/package/runtime/bin/onos-compile-yang
+++ b/tools/package/runtime/bin/onos-compile-yang
@@ -1,5 +1,4 @@
 #!/bin/bash
-
 #
 # Copyright 2015-present Open Networking Foundation
 #
@@ -44,4 +43,4 @@
 
 file=$(basename $yang)
 modelId="$(echo $file | sed -E 's/(.zip|.jar|.yang)$//g')"
-curl $URL?modelId=$modelId -F"file=@$yang"
+$curl $URL?modelId=$modelId -F"file=@$yang"
diff --git a/utils/rest/src/main/java/org/onlab/rest/AbstractWebApplication.java b/utils/rest/src/main/java/org/onlab/rest/AbstractWebApplication.java
index f744929..41839c7 100644
--- a/utils/rest/src/main/java/org/onlab/rest/AbstractWebApplication.java
+++ b/utils/rest/src/main/java/org/onlab/rest/AbstractWebApplication.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.ImmutableSet;
 import org.onlab.rest.exceptions.BadRequestMapper;
 import org.onlab.rest.exceptions.EntityNotFoundMapper;
+import org.onlab.rest.exceptions.ForbiddenMapper;
 import org.onlab.rest.exceptions.IllegalArgumentExceptionMapper;
 import org.onlab.rest.exceptions.IllegalStateExceptionMapper;
 import org.onlab.rest.exceptions.NotFoundMapper;
@@ -43,7 +44,9 @@
      */
     protected Set<Class<?>> getClasses(Class<?>... classes) {
         ImmutableSet.Builder<Class<?>> builder = ImmutableSet.builder();
-        builder.add(ServiceNotFoundMapper.class,
+        builder.add(AuthorizationFilter.class,
+                    ForbiddenMapper.class,
+                    ServiceNotFoundMapper.class,
                     EntityNotFoundMapper.class,
                     NotFoundMapper.class,
                     ServerErrorMapper.class,
diff --git a/utils/rest/src/main/java/org/onlab/rest/AuthorizationFilter.java b/utils/rest/src/main/java/org/onlab/rest/AuthorizationFilter.java
new file mode 100644
index 0000000..6bf8a2f
--- /dev/null
+++ b/utils/rest/src/main/java/org/onlab/rest/AuthorizationFilter.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed 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.onlab.rest;
+
+import com.google.common.collect.ImmutableSet;
+
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * Filter that performs authorization checks on all incoming REST API requests.
+ * Methods with modify semantics require 'admin' role; all others require 'viewer' role.
+ */
+public class AuthorizationFilter implements ContainerRequestFilter {
+
+    private static final String ADMIN = "admin";
+    private static final String VIEWER = "viewer";
+
+    private static final String FORBIDDEN_MSG =
+            "User has insufficient privilege for this request";
+
+    private static final Set<String> PRIVILEGED_METHODS =
+            ImmutableSet.of("POST", "PUT", "DELETE", "PATCH");
+
+    private static boolean disableForTests = false;
+
+    @Override
+    public void filter(ContainerRequestContext requestContext) throws IOException {
+        if (disableForTests) {
+            return;
+        }
+        if ((PRIVILEGED_METHODS.contains(requestContext.getMethod()) &&
+                !requestContext.getSecurityContext().isUserInRole(ADMIN)) ||
+                !requestContext.getSecurityContext().isUserInRole(VIEWER)) {
+            throw new ForbiddenException(FORBIDDEN_MSG);
+        }
+    }
+
+    public static void disableForTests() {
+        disableForTests = true;
+    }
+}
diff --git a/utils/rest/src/main/java/org/onlab/rest/exceptions/ForbiddenMapper.java b/utils/rest/src/main/java/org/onlab/rest/exceptions/ForbiddenMapper.java
new file mode 100644
index 0000000..63c8960
--- /dev/null
+++ b/utils/rest/src/main/java/org/onlab/rest/exceptions/ForbiddenMapper.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed 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.onlab.rest.exceptions;
+
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+/**
+ * Mapper for service not found exceptions to the NOT_FOUND response code.
+ */
+@Provider
+public class ForbiddenMapper extends AbstractMapper<ForbiddenException> {
+    @Override
+    protected Response.Status responseStatus() {
+        return Response.Status.FORBIDDEN;
+    }
+}
diff --git a/web/api/src/main/webapp/WEB-INF/web.xml b/web/api/src/main/webapp/WEB-INF/web.xml
index 381868e..324d46d 100644
--- a/web/api/src/main/webapp/WEB-INF/web.xml
+++ b/web/api/src/main/webapp/WEB-INF/web.xml
@@ -29,11 +29,13 @@
         </web-resource-collection>
         <auth-constraint>
             <role-name>admin</role-name>
+            <role-name>viewer</role-name>
         </auth-constraint>
     </security-constraint>
 
     <security-role>
         <role-name>admin</role-name>
+        <role-name>viewer</role-name>
     </security-role>
 
     <login-config>
diff --git a/web/api/src/test/java/org/onosproject/rest/resources/ResourceTest.java b/web/api/src/test/java/org/onosproject/rest/resources/ResourceTest.java
index 24036f6..9f809f3 100644
--- a/web/api/src/test/java/org/onosproject/rest/resources/ResourceTest.java
+++ b/web/api/src/test/java/org/onosproject/rest/resources/ResourceTest.java
@@ -23,6 +23,7 @@
 import org.glassfish.jersey.test.spi.TestContainerFactory;
 import org.onlab.junit.TestUtils;
 import org.onlab.osgi.ServiceDirectory;
+import org.onlab.rest.AuthorizationFilter;
 import org.onlab.rest.BaseResource;
 
 /**
@@ -49,6 +50,7 @@
 
     private void configureProperties() {
         set(TestProperties.CONTAINER_PORT, 0);
+        AuthorizationFilter.disableForTests();
     }
 
     /**