Authorization fixes for Northbound bundles 24/324/1
authorSapan Shah <sapshah@cisco.com>
Thu, 9 May 2013 01:20:30 +0000 (18:20 -0700)
committerSapan Shah <sapshah@cisco.com>
Thu, 9 May 2013 01:20:30 +0000 (18:20 -0700)
Signed-off-by: Sapan Shah <sapshah@cisco.com>
16 files changed:
opendaylight/northbound/commons/pom.xml
opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/utils/NorthboundUtils.java [new file with mode: 0644]
opendaylight/northbound/flowprogrammer/pom.xml
opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthbound.java
opendaylight/northbound/hosttracker/pom.xml
opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java
opendaylight/northbound/staticrouting/pom.xml
opendaylight/northbound/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/northbound/StaticRoutingNorthbound.java
opendaylight/northbound/statistics/pom.xml
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthbound.java
opendaylight/northbound/subnets/pom.xml
opendaylight/northbound/subnets/src/main/java/org/opendaylight/controller/subnets/northbound/SubnetsNorthboundJAXRS.java
opendaylight/northbound/switchmanager/pom.xml
opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthbound.java
opendaylight/northbound/topology/pom.xml
opendaylight/northbound/topology/src/main/java/org/opendaylight/controller/topology/northbound/TopologyNorthboundJAXRS.java

index d80d669..3756e3d 100644 (file)
           <instructions>
             <Export-Package>
               org.opendaylight.controller.northbound.commons.exception,
+              org.opendaylight.controller.northbound.commons.utils,
               org.opendaylight.controller.northbound.commons
             </Export-Package>
             <Import-Package>
               javax.ws.rs,
               javax.ws.rs.core,
               org.opendaylight.controller.sal.utils,
+              org.opendaylight.controller.sal.authorization,
+              org.opendaylight.controller.containermanager,
               org.opendaylight.controller.usermanager,
               javax.servlet.http, 
               org.slf4j,                              
diff --git a/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/utils/NorthboundUtils.java b/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/utils/NorthboundUtils.java
new file mode 100644 (file)
index 0000000..7069ff0
--- /dev/null
@@ -0,0 +1,60 @@
+package org.opendaylight.controller.northbound.commons.utils;
+
+import org.opendaylight.controller.containermanager.IContainerAuthorization;
+import org.opendaylight.controller.sal.authorization.Privilege;
+import org.opendaylight.controller.sal.authorization.UserLevel;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.usermanager.IUserManager;
+
+public class NorthboundUtils {
+
+    
+    /**
+     * Returns whether the current user has the required privilege on the
+     * specified container
+     * 
+     * @param userName
+     *            The user name
+     * @param containerName
+     *            The container name
+     * @param required
+     *            Operation to be performed - READ/WRITE
+     * @param bundle
+     *            Class from where the function is invoked           
+     * @return The Status of the request, either Success or Unauthorized
+     */
+    public static boolean isAuthorized(String userName, String containerName,
+            Privilege required,Object bundle) {
+        
+         if (containerName.equals(GlobalConstants.DEFAULT.toString())) {
+            IUserManager auth = (IUserManager) ServiceHelper.getGlobalInstance(
+                    IUserManager.class, bundle);
+            
+            switch (required) {
+            case WRITE:
+                return (auth.getUserLevel(userName).ordinal() <= UserLevel.NETWORKADMIN.ordinal());
+            case READ:
+                return (auth.getUserLevel(userName).ordinal() <= UserLevel.NETWORKOPERATOR.ordinal());                    
+            default:
+                return false;
+            }
+
+        } else {
+            IContainerAuthorization auth = (IContainerAuthorization) ServiceHelper
+                    .getGlobalInstance(IContainerAuthorization.class, bundle);
+
+            if (auth == null) {
+                return false;
+            }
+
+            Privilege current = auth.getResourcePrivilege(userName,
+                    containerName);
+            if (required.ordinal() > current.ordinal()) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+}
index a4ebfa2..e28454f 100644 (file)
               org.opendaylight.controller.switchmanager,
               org.opendaylight.controller.northbound.commons,
               org.opendaylight.controller.northbound.commons.exception,
-              com.sun.jersey.spi.container.servlet,                            
+              org.opendaylight.controller.northbound.commons.utils,
+              org.opendaylight.controller.sal.authorization,
+              org.opendaylight.controller.usermanager,
+                         com.sun.jersey.spi.container.servlet,                            
               javax.ws.rs,
               javax.ws.rs.core,
               javax.xml.bind.annotation,
index ed3abde..99452b4 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -20,8 +19,10 @@ 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.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
 import javax.xml.bind.JAXBElement;
 
 import org.codehaus.enunciate.jaxrs.ResponseCode;
@@ -36,6 +37,9 @@ import org.opendaylight.controller.northbound.commons.exception.NotAcceptableExc
 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
@@ -44,20 +48,34 @@ import org.opendaylight.controller.switchmanager.ISwitchManager;
 
 /**
  * Flow Configuration Northbound API
- *
- * <br><br>
+ * 
+ * <br>
+ * <br>
  * Authentication scheme : <b>HTTP Basic</b><br>
  * Authentication realm : <b>opendaylight</b><br>
  * Transport : <b>HTTP and HTTPS</b><br>
  * <br>
- * HTTPS Authentication is disabled by default. Administrator can enable it in tomcat-server.xml after adding 
- * a proper keystore / SSL certificate from a trusted authority.<br>
- * More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
- *
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ * 
  */
 @Path("/")
 public class FlowProgrammerNorthbound {
 
+    private String username;
+
+    @Context
+    public void setSecurityContext(SecurityContext context) {
+        username = context.getUserPrincipal().getName();
+    }
+
+    protected String getUserName() {
+        return username;
+    }
+
     private IForwardingRulesManager getForwardingRulesManagerService(
             String containerName) {
         IContainerManager containerManager = (IContainerManager) ServiceHelper
@@ -129,38 +147,51 @@ public class FlowProgrammerNorthbound {
 
     /**
      * Returns a list of Flows configured on the given container
-     *
-     * @param containerName Name of the Container. The Container name for the base controller is "default".
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
      * @return List of configured flows configured on a given container
      */
     @Path("/{containerName}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(FlowConfigs.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public FlowConfigs getStaticFlows(
             @PathParam("containerName") String containerName) {
-        List<FlowConfig> flowConfigs = getStaticFlowsInternal(containerName, null);
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+
+        List<FlowConfig> flowConfigs = getStaticFlowsInternal(containerName,
+                null);
         return new FlowConfigs(flowConfigs);
     }
 
     /**
      * Returns a list of Flows configured on a Node in a given container
-     *
-     * @param containerName Name of the Container. The Container name
-     * for the base controller is "default".
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier
      * @return List of configured flows configured on a Node in a container
      */
     @Path("/{containerName}/{nodeType}/{nodeId}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(FlowConfigs.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName or nodeId is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
@@ -168,6 +199,12 @@ public class FlowProgrammerNorthbound {
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId) {
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         Node node = Node.fromString(nodeType, nodeId);
         if (node == null) {
             throw new ResourceNotFoundException(nodeId + " : "
@@ -178,29 +215,38 @@ public class FlowProgrammerNorthbound {
     }
 
     /**
-     * Returns the flow configuration matching a human-readable name and nodeId on a
-     * given Container.
-     *
-     * @param containerName Name of the Container. The Container name
-     * for the base controller is "default".
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier
-     * @param name Human-readable name for the configured flow.
+     * Returns the flow configuration matching a human-readable name and nodeId
+     * on a given Container.
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier
+     * @param name
+     *            Human-readable name for the configured flow.
      * @return Flow configuration matching the name and nodeId on a Container
      */
     @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(FlowConfig.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName or NodeId or Configuration name is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public FlowConfig getStaticFlow(
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
-            @PathParam("nodeId") String nodeId,
-            @PathParam("name") String name) {
+            @PathParam("nodeId") String nodeId, @PathParam("name") String name) {
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
 
         if (frm == null) {
@@ -220,20 +266,25 @@ public class FlowProgrammerNorthbound {
 
     /**
      * Add a flow configuration
-     *
-     * @param containerName Name of the Container. The Container name
-     * for the base controller is "default".
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier
-     * @param name Name of the Static Flow configuration
-     * @param FlowConfig Flow Configuration in JSON or XML format
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier
+     * @param name
+     *            Name of the Static Flow configuration
+     * @param FlowConfig
+     *            Flow Configuration in JSON or XML format
      * @return Response as dictated by the HTTP Response Status code
      */
 
     @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
     @POST
-    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( {
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
             @ResponseCode(code = 201, condition = "Flow Config processed successfully"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
@@ -247,6 +298,12 @@ public class FlowProgrammerNorthbound {
             @PathParam(value = "nodeId") String nodeId,
             @TypeHint(FlowConfig.class) JAXBElement<FlowConfig> flowConfig) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
 
         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
@@ -273,21 +330,25 @@ public class FlowProgrammerNorthbound {
 
     /**
      * Delete a Flow configuration
-     *
+     * 
      * DELETE /flows/{containerName}/{nodeType}/{nodeId}/{name}
-     *
-     * @param containerName Name of the Container. The Container name
-     * for the base controller is "default".
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier
-     * @param name Name of the Static Flow configuration
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier
+     * @param name
+     *            Name of the Static Flow configuration
      * @return Response as dictated by the HTTP Response code
      */
 
     @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
     @DELETE
-    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( {
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
@@ -299,6 +360,12 @@ public class FlowProgrammerNorthbound {
             @PathParam("nodeType") String nodeType,
             @PathParam(value = "nodeId") String nodeId) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
 
         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
@@ -325,19 +392,23 @@ public class FlowProgrammerNorthbound {
 
     /**
      * Toggle a Flow configuration
-     *
-     * @param containerName Name of the Container. The Container name
-     * for the base controller is "default".
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier
-     * @param name Name of the Static Flow configuration
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier
+     * @param name
+     *            Name of the Static Flow configuration
      * @return Response as dictated by the HTTP Response code
      */
 
     @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
     @PUT
-    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( {
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
@@ -349,6 +420,13 @@ public class FlowProgrammerNorthbound {
             @PathParam(value = "nodeId") String nodeId,
             @PathParam(value = "name") String name) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+
         handleDefaultDisabled(containerName);
 
         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
@@ -374,7 +452,7 @@ public class FlowProgrammerNorthbound {
     }
 
     private Node handleNodeAvailability(String containerName, String nodeType,
-                                        String nodeId) {
+            String nodeId) {
 
         Node node = Node.fromString(nodeType, nodeId);
         if (node == null) {
@@ -401,13 +479,13 @@ public class FlowProgrammerNorthbound {
         IContainerManager containerManager = (IContainerManager) ServiceHelper
                 .getGlobalInstance(IContainerManager.class, this);
         if (containerManager == null) {
-            throw new InternalServerErrorException(RestMessages.INTERNALERROR
-                    .toString());
+            throw new InternalServerErrorException(
+                    RestMessages.INTERNALERROR.toString());
         }
         if (containerName.equals(GlobalConstants.DEFAULT.toString())
                 && containerManager.hasNonDefaultContainer()) {
-            throw new NotAcceptableException(RestMessages.DEFAULTDISABLED
-                    .toString());
+            throw new NotAcceptableException(
+                    RestMessages.DEFAULTDISABLED.toString());
         }
     }
 
index 5ddab37..374b984 100644 (file)
               org.opendaylight.controller.sal.utils,
               org.opendaylight.controller.containermanager,
               org.opendaylight.controller.switchmanager,
+              org.opendaylight.controller.usermanager,
               org.apache.commons.logging,
               com.sun.jersey.spi.container.servlet,
               org.opendaylight.controller.northbound.commons,
               org.opendaylight.controller.northbound.commons.exception,
-              javax.ws.rs,
+              org.opendaylight.controller.northbound.commons.utils,
+              org.opendaylight.controller.sal.authorization,
+                         javax.ws.rs,
               javax.ws.rs.core,
               javax.xml.bind.annotation,
               javax.xml.bind,
index 2275ee9..a9f210e 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -11,10 +10,8 @@ package org.opendaylight.controller.hosttracker.northbound;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.security.Principal;
 import java.util.List;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
@@ -24,8 +21,10 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
 
 import org.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
@@ -38,7 +37,9 @@ import org.opendaylight.controller.northbound.commons.exception.InternalServerEr
 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
 import org.opendaylight.controller.northbound.commons.exception.UnsupportedMediaTypeException;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
@@ -47,26 +48,43 @@ import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
 
+import org.opendaylight.controller.sal.authorization.Privilege;
+
 /**
  * Host Tracker Northbound REST APIs.<br>
- * This class provides REST APIs to track host location in a network. Host Location is represented by Host node connector 
- * which is essentially a logical entity that represents a Switch/Port. A host is represented by it's IP-address 
- * and mac-address.
- *
- * <br><br>
+ * This class provides REST APIs to track host location in a network. Host
+ * Location is represented by Host node connector which is essentially a logical
+ * entity that represents a Switch/Port. A host is represented by it's
+ * IP-address and mac-address.
+ * 
+ * <br>
+ * <br>
  * Authentication scheme : <b>HTTP Basic</b><br>
  * Authentication realm : <b>opendaylight</b><br>
  * Transport : <b>HTTP and HTTPS</b><br>
  * <br>
- * HTTPS Authentication is disabled by default. Administrator can enable it in tomcat-server.xml after adding
- * a proper keystore / SSL certificate from a trusted authority.<br>
- * More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
- *
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ * 
  */
 
 @Path("/")
 public class HostTrackerNorthbound {
 
+    private String username;
+
+    @Context
+    public void setSecurityContext(SecurityContext context) {
+        username = context.getUserPrincipal().getName();
+    }
+
+    protected String getUserName() {
+        return username;
+    }
+
     private IfIptoHost getIfIpToHostService(String containerName) {
         IContainerManager containerManager = (IContainerManager) ServiceHelper
                 .getGlobalInstance(IContainerManager.class, this);
@@ -100,21 +118,30 @@ public class HostTrackerNorthbound {
     }
 
     /**
-     * Returns a list of all Hosts : both configured via PUT API and dynamically learnt on the network.
-     *
-     * @param containerName Name of the Container. The Container name for the base controller is "default".
+     * Returns a list of all Hosts : both configured via PUT API and dynamically
+     * learnt on the network.
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
      * @return List of Active Hosts.
      */
     @Path("/{containerName}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(Hosts.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
-    public Hosts getActiveHosts(
-            @PathParam("containerName") String containerName) {
+    public Hosts getActiveHosts(@PathParam("containerName") String containerName) {
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         IfIptoHost hostTracker = getIfIpToHostService(containerName);
         if (hostTracker == null) {
             throw new ServiceUnavailableException("Host Tracker "
@@ -125,21 +152,30 @@ public class HostTrackerNorthbound {
     }
 
     /**
-     * Returns a list of Hosts that are statically configured and are connected to a NodeConnector that is down.
-     *
-     * @param containerName Name of the Container. The Container name for the base controller is "default".
+     * Returns a list of Hosts that are statically configured and are connected
+     * to a NodeConnector that is down.
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
      * @return List of inactive Hosts.
      */
     @Path("/{containerName}/inactive")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(Hosts.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public Hosts getInactiveHosts(
             @PathParam("containerName") String containerName) {
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         IfIptoHost hostTracker = getIfIpToHostService(containerName);
         if (hostTracker == null) {
             throw new ServiceUnavailableException("Host Tracker "
@@ -151,16 +187,19 @@ public class HostTrackerNorthbound {
 
     /**
      * Returns a host that matches the IP Address value passed as parameter.
-     *
-     * @param containerName Name of the Container. The Container name for the base controller is "default".
-     * @param networkAddress IP Address being looked up
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param networkAddress
+     *            IP Address being looked up
      * @return host that matches the IP Address
      */
     @Path("/{containerName}/{networkAddress}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(HostNodeConnector.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 415, condition = "Invalid IP Address passed in networkAddress parameter"),
@@ -168,6 +207,12 @@ public class HostTrackerNorthbound {
     public HostNodeConnector getHostDetails(
             @PathParam("containerName") String containerName,
             @PathParam("networkAddress") String networkAddress) {
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         IfIptoHost hostTracker = getIfIpToHostService(containerName);
         if (hostTracker == null) {
             throw new ServiceUnavailableException("Host Tracker "
@@ -191,22 +236,31 @@ public class HostTrackerNorthbound {
 
     /**
      * Add a Static Host configuration
-     *
-     * @param containerName Name of the Container. The Container name for the base controller is "default".
-     * @param networkAddress Host IP Address
-     * @param dataLayerAddress Host L2 data-layer address.
-     * @param nodeType Node Type as specifid by Node class
-     * @param nodeId Node Identifier as specifid by Node class
-     * @param nodeConnectorType Port Type as specified by NodeConnector class
-     * @param nodeConnectorId Port Identifier as specified by NodeConnector class
-     * @param vlan Vlan number
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param networkAddress
+     *            Host IP Address
+     * @param dataLayerAddress
+     *            Host L2 data-layer address.
+     * @param nodeType
+     *            Node Type as specifid by Node class
+     * @param nodeId
+     *            Node Identifier as specifid by Node class
+     * @param nodeConnectorType
+     *            Port Type as specified by NodeConnector class
+     * @param nodeConnectorId
+     *            Port Identifier as specified by NodeConnector class
+     * @param vlan
+     *            Vlan number
      * @return Response as dictated by the HTTP Response Status code
      */
 
     @Path("/{containerName}/{networkAddress}")
     @POST
-    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( {
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
             @ResponseCode(code = 201, condition = "Flow Config processed successfully"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
@@ -222,6 +276,12 @@ public class HostTrackerNorthbound {
             @QueryParam("nodeConnectorId") String nodeConnectorId,
             @DefaultValue("0") @QueryParam("vlan") String vlan) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
 
         IfIptoHost hostTracker = getIfIpToHostService(containerName);
@@ -232,8 +292,8 @@ public class HostTrackerNorthbound {
 
         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
         if (node == null) {
-            throw new InternalServerErrorException(RestMessages.NONODE.
-                                                   toString());
+            throw new InternalServerErrorException(
+                    RestMessages.NONODE.toString());
         }
 
         try {
@@ -242,15 +302,14 @@ public class HostTrackerNorthbound {
             throw new UnsupportedMediaTypeException(networkAddress + " "
                     + RestMessages.INVALIDADDRESS.toString());
         }
-        NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType, nodeConnectorId,
-                                                          node);
+        NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType,
+                nodeConnectorId, node);
         if (nc == null) {
-            throw new ResourceNotFoundException(nodeConnectorType+"|"+nodeConnectorId + " : "
-                    + RestMessages.NONODE.toString());
+            throw new ResourceNotFoundException(nodeConnectorType + "|"
+                    + nodeConnectorId + " : " + RestMessages.NONODE.toString());
         }
         Status status = hostTracker.addStaticHost(networkAddress,
-                                               dataLayerAddress,
-                                               nc, vlan);
+                dataLayerAddress, nc, vlan);
         if (status.isSuccess()) {
             return Response.status(Response.Status.CREATED).build();
         } else if (status.getCode().equals(StatusCode.BADREQUEST)) {
@@ -261,16 +320,19 @@ public class HostTrackerNorthbound {
 
     /**
      * Delete a Static Host configuration
-     *
-     * @param containerName Name of the Container. The Container name for the base controller is "default".
-     * @param networkAddress   IP Address
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param networkAddress
+     *            IP Address
      * @return Response as dictated by the HTTP Response code.
      */
 
     @Path("/{containerName}/{networkAddress}")
     @DELETE
-    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( {
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
@@ -280,7 +342,13 @@ public class HostTrackerNorthbound {
     public Response deleteFlow(
             @PathParam(value = "containerName") String containerName,
             @PathParam(value = "networkAddress") String networkAddress) {
-
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
         IfIptoHost hostTracker = getIfIpToHostService(containerName);
         if (hostTracker == null) {
@@ -307,18 +375,18 @@ public class HostTrackerNorthbound {
         IContainerManager containerManager = (IContainerManager) ServiceHelper
                 .getGlobalInstance(IContainerManager.class, this);
         if (containerManager == null) {
-            throw new InternalServerErrorException(RestMessages.INTERNALERROR
-                    .toString());
+            throw new InternalServerErrorException(
+                    RestMessages.INTERNALERROR.toString());
         }
         if (containerName.equals(GlobalConstants.DEFAULT.toString())
                 && containerManager.hasNonDefaultContainer()) {
-            throw new ResourceConflictException(RestMessages.DEFAULTDISABLED
-                    .toString());
+            throw new ResourceConflictException(
+                    RestMessages.DEFAULTDISABLED.toString());
         }
     }
 
     private Node handleNodeAvailability(String containerName, String nodeType,
-                                        String nodeId) {
+            String nodeId) {
 
         Node node = Node.fromString(nodeType, nodeId);
         if (node == null) {
@@ -340,4 +408,5 @@ public class HostTrackerNorthbound {
         }
         return node;
     }
+
 }
index f0fd323..3e76e06 100644 (file)
               org.opendaylight.controller.sal.core,
               org.opendaylight.controller.sal.utils,
               org.opendaylight.controller.containermanager,
+              org.opendaylight.controller.usermanager,
               com.sun.jersey.spi.container.servlet,
               org.opendaylight.controller.northbound.commons,
               org.opendaylight.controller.northbound.commons.exception,
-              org.slf4j,              
+              org.opendaylight.controller.northbound.commons.utils,
+              org.opendaylight.controller.sal.authorization,
+                         org.slf4j,              
               javax.ws.rs,
               javax.ws.rs.core,
               javax.xml.bind.annotation,
index f04c902..c48d7ec 100644 (file)
@@ -19,8 +19,10 @@ import javax.ws.rs.POST;
 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.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
 import javax.xml.bind.JAXBElement;
 
 import org.codehaus.enunciate.jaxrs.ResponseCode;
@@ -34,6 +36,9 @@ import org.opendaylight.controller.northbound.commons.exception.InternalServerEr
 import org.opendaylight.controller.northbound.commons.exception.NotAcceptableException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.sal.utils.Status;
@@ -53,6 +58,19 @@ import org.opendaylight.controller.sal.utils.Status;
 @Path("/")
 public class StaticRoutingNorthbound {
 
+
+       private String username;
+       
+    @Context
+    public void setSecurityContext(SecurityContext context) {
+       username = context.getUserPrincipal().getName();
+    }
+    protected String getUserName() {
+        return username;
+    }
+       
+
+       
     private List<StaticRoute> getStaticRoutesInternal(String containerName) {
 
         IForwardingStaticRouting staticRouting = (IForwardingStaticRouting) ServiceHelper
@@ -90,6 +108,13 @@ public class StaticRoutingNorthbound {
             @ResponseCode(code = 404, condition = "The containerName passed was not found") })
     public StaticRoutes getStaticRoutes(
             @PathParam("containerName") String containerName) {
+
+        if(!NorthboundUtils.isAuthorized(getUserName(), containerName, 
+                Privilege.WRITE, this)){
+            throw new 
+                UnauthorizedException("User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         return new StaticRoutes(getStaticRoutesInternal(containerName));
     }
 
@@ -110,6 +135,13 @@ public class StaticRoutingNorthbound {
     public StaticRoute getStaticRoute(
             @PathParam("containerName") String containerName,
             @PathParam("name") String name) {
+
+        if(!NorthboundUtils.isAuthorized(getUserName(), containerName, 
+                Privilege.WRITE, this)){
+            throw new 
+                UnauthorizedException("User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         List<StaticRoute> routes = this.getStaticRoutesInternal(containerName);
         for (StaticRoute route : routes) {
             if (route.getName().equalsIgnoreCase(name)) {
@@ -142,6 +174,13 @@ public class StaticRoutingNorthbound {
             @PathParam(value = "name") String name,
             @TypeHint(StaticRoute.class) JAXBElement<StaticRoute> staticRouteData) {
 
+   
+        if(!NorthboundUtils.isAuthorized(getUserName(), containerName, 
+                Privilege.WRITE, this)){
+            throw new 
+                UnauthorizedException("User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
 
         IForwardingStaticRouting staticRouting = (IForwardingStaticRouting) ServiceHelper
@@ -182,7 +221,13 @@ public class StaticRoutingNorthbound {
     public Response removeStaticRoute(
             @PathParam(value = "containerName") String containerName,
             @PathParam(value = "name") String name) {
-
+        if(!NorthboundUtils.isAuthorized(getUserName(), containerName, 
+                Privilege.WRITE, this)){
+            throw new 
+                UnauthorizedException("User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
 
         IForwardingStaticRouting staticRouting = (IForwardingStaticRouting) ServiceHelper
index 84c4020..326c932 100644 (file)
                          org.opendaylight.controller.sal.utils,
                          org.opendaylight.controller.containermanager,
                          org.opendaylight.controller.statisticsmanager,
+                         org.opendaylight.controller.usermanager,
                          org.opendaylight.controller.switchmanager,
+                         org.opendaylight.controller.sal.authorization,
                          org.apache.commons.logging,
               com.sun.jersey.spi.container.servlet,
               org.opendaylight.controller.northbound.commons,
               org.opendaylight.controller.northbound.commons.exception,
+              org.opendaylight.controller.northbound.commons.utils,
               javax.ws.rs,
               javax.ws.rs.core,
               javax.xml.bind.annotation,
index 651cb2d..5cddc66 100644 (file)
@@ -15,7 +15,9 @@ import javax.ws.rs.GET;
 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.MediaType;
+import javax.ws.rs.core.SecurityContext;
 
 import org.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
@@ -23,10 +25,9 @@ import org.codehaus.enunciate.jaxrs.TypeHint;
 import org.opendaylight.controller.containermanager.IContainerManager;
 
 import org.opendaylight.controller.northbound.commons.RestMessages;
-import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
-import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
-import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
-import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.northbound.commons.exception.*;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
@@ -36,21 +37,36 @@ import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
 
 /**
- * Northbound APIs that returns various Statistics exposed by the Southbound plugins such as Openflow.
+ * Northbound APIs that returns various Statistics exposed by the Southbound
+ * plugins such as Openflow.
  * 
- * <br><br>
+ * <br>
+ * <br>
  * Authentication scheme : <b>HTTP Basic</b><br>
  * Authentication realm : <b>opendaylight</b><br>
  * Transport : <b>HTTP and HTTPS</b><br>
  * <br>
- * HTTPS Authentication is disabled by default. Administrator can enable it in tomcat-server.xml after adding 
- * a proper keystore / SSL certificate from a trusted authority.<br>
- * More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
- *
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ * 
  */
 @Path("/")
 public class StatisticsNorthbound {
 
+    private String username;
+
+    @Context
+    public void setSecurityContext(SecurityContext context) {
+        username = context.getUserPrincipal().getName();
+    }
+
+    protected String getUserName() {
+        return username;
+    }
+
     private IStatisticsManager getStatisticsService(String containerName) {
         IContainerManager containerManager = (IContainerManager) ServiceHelper
                 .getGlobalInstance(IContainerManager.class, this);
@@ -85,21 +101,29 @@ public class StatisticsNorthbound {
 
     /**
      * Returns a list of all Flow Statistics from all the Nodes.
-     *
-     * @param containerName Name of the Container. The Container name for the base controller is "default". 
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
      * @return List of FlowStatistics from all the Nodes
      */
 
     @Path("/{containerName}/flowstats")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(AllFlowStatistics.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public AllFlowStatistics getFlowStatistics(
             @PathParam("containerName") String containerName) {
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         IStatisticsManager statisticsManager = getStatisticsService(containerName);
         if (statisticsManager == null) {
             throw new ServiceUnavailableException("Statistics "
@@ -121,8 +145,7 @@ public class StatisticsNorthbound {
             for (FlowOnNode flowOnSwitch : flows) {
                 flowStats.add(flowOnSwitch);
             }
-            FlowStatistics stat = new FlowStatistics(node,
-                                                     flowStats);
+            FlowStatistics stat = new FlowStatistics(node, flowStats);
             statistics.add(stat);
         }
         return new AllFlowStatistics(statistics);
@@ -130,18 +153,21 @@ public class StatisticsNorthbound {
 
     /**
      * Returns a list of Flow Statistics for a given Node.
-     *
-     * @param containerName Name of the Container. The Container name
-     * for the base controller is "default". 
-     * @param nodeType Node Type as specifid by Node class
-     * @param nodeId Node Identifier
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param nodeType
+     *            Node Type as specifid by Node class
+     * @param nodeId
+     *            Node Identifier
      * @return List of Flow Statistics for a given Node.
      */
     @Path("/{containerName}/flowstats/{nodeType}/{nodeId}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(FlowStatistics.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
@@ -149,7 +175,12 @@ public class StatisticsNorthbound {
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId) {
-
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
 
         IStatisticsManager statisticsManager = getStatisticsService(containerName);
@@ -170,23 +201,33 @@ public class StatisticsNorthbound {
     }
 
     /**
-     * Returns a list of all the Port Statistics across all the NodeConnectors on all the Nodes.
-     *
-     * @param containerName Name of the Container. The Container name for the base controller is "default". 
-     * @return List of all the Port Statistics across all the NodeConnectors on all the Nodes.
+     * Returns a list of all the Port Statistics across all the NodeConnectors
+     * on all the Nodes.
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @return List of all the Port Statistics across all the NodeConnectors on
+     *         all the Nodes.
      */
 
     @Path("/{containerName}/portstats")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(AllPortStatistics.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public AllPortStatistics getPortStatistics(
             @PathParam("containerName") String containerName) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         IStatisticsManager statisticsManager = getStatisticsService(containerName);
         if (statisticsManager == null) {
             throw new ServiceUnavailableException("Statistics "
@@ -211,19 +252,24 @@ public class StatisticsNorthbound {
     }
 
     /**
-     * Returns a list of all the Port Statistics across all the NodeConnectors in a given Node.
-     *
-     * @param containerName Name of the Container. The Container name
-     * for the base controller is "default". 
-     * @param nodeType Node Type as specifid by Node class
-     * @param Node Identifier
-     * @return Returns a list of all the Port Statistics across all the NodeConnectors in a given Node.
+     * Returns a list of all the Port Statistics across all the NodeConnectors
+     * in a given Node.
+     * 
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param nodeType
+     *            Node Type as specifid by Node class
+     * @param Node
+     *            Identifier
+     * @return Returns a list of all the Port Statistics across all the
+     *         NodeConnectors in a given Node.
      */
     @Path("/{containerName}/portstats/{nodeType}/{nodeId}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(PortStatistics.class)
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
@@ -232,6 +278,12 @@ public class StatisticsNorthbound {
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
 
         IStatisticsManager statisticsManager = getStatisticsService(containerName);
@@ -247,28 +299,27 @@ public class StatisticsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
 
-        Node node = handleNodeAvailability(containerName,
-                                           nodeType, nodeId);
-        return new PortStatistics(node, statisticsManager
-                .getNodeConnectorStatistics(node));
+        Node node = handleNodeAvailability(containerName, nodeType, nodeId);
+        return new PortStatistics(node,
+                statisticsManager.getNodeConnectorStatistics(node));
     }
 
     private void handleDefaultDisabled(String containerName) {
         IContainerManager containerManager = (IContainerManager) ServiceHelper
                 .getGlobalInstance(IContainerManager.class, this);
         if (containerManager == null) {
-            throw new InternalServerErrorException(RestMessages.INTERNALERROR
-                    .toString());
+            throw new InternalServerErrorException(
+                    RestMessages.INTERNALERROR.toString());
         }
         if (containerName.equals(GlobalConstants.DEFAULT.toString())
                 && containerManager.hasNonDefaultContainer()) {
-            throw new ResourceConflictException(RestMessages.DEFAULTDISABLED
-                    .toString());
+            throw new ResourceConflictException(
+                    RestMessages.DEFAULTDISABLED.toString());
         }
     }
 
     private Node handleNodeAvailability(String containerName, String nodeType,
-                                        String nodeId) {
+            String nodeId) {
 
         Node node = Node.fromString(nodeType, nodeId);
         if (node == null) {
index 22c9a97..3abb1be 100644 (file)
                          org.opendaylight.controller.switchmanager,
               org.opendaylight.controller.northbound.commons,
               org.opendaylight.controller.northbound.commons.exception,
+              org.opendaylight.controller.northbound.commons.utils,
               com.sun.jersey.spi.container.servlet,
-              javax.ws.rs,
+              org.opendaylight.controller.sal.authorization,
+              org.opendaylight.controller.usermanager,
+                         javax.ws.rs,
               javax.ws.rs.core,
               javax.xml.bind.annotation,
               org.slf4j,
index 1e53362..05bb5b1 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.controller.subnets.northbound;
 
 import java.util.ArrayList;
-import java.util.List;
 
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -17,8 +16,10 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
 
 import org.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
@@ -26,6 +27,9 @@ import org.codehaus.enunciate.jaxrs.TypeHint;
 import org.opendaylight.controller.northbound.commons.RestMessages;
 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
@@ -38,60 +42,86 @@ public class SubnetsNorthboundJAXRS {
     protected static final Logger logger = LoggerFactory
             .getLogger(SubnetsNorthboundJAXRS.class);
 
+    private String username;
+
+    @Context
+    public void setSecurityContext(SecurityContext context) {
+        username = context.getUserPrincipal().getName();
+    }
+
+    protected String getUserName() {
+        return username;
+    }
+
     /**
      * List all the subnets in a given container
-     *
-     * @param containerName container in which we want to query the subnets
-     *
+     * 
+     * @param containerName
+     *            container in which we want to query the subnets
+     * 
      * @return a List of SubnetConfig
      */
     @Path("/{containerName}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( { @ResponseCode(code = 404, condition = "The containerName passed was not found") })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({ @ResponseCode(code = 404, condition = "The containerName passed was not found") })
     @TypeHint(SubnetConfigs.class)
     public SubnetConfigs listSubnets(
             @PathParam("containerName") String containerName) {
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         ISwitchManager switchManager = null;
         switchManager = (ISwitchManager) ServiceHelper.getInstance(
                 ISwitchManager.class, containerName, this);
         if (switchManager == null) {
-            throw new ResourceNotFoundException(RestMessages.NOCONTAINER
-                    .toString());
+            throw new ResourceNotFoundException(
+                    RestMessages.NOCONTAINER.toString());
         }
         return new SubnetConfigs(switchManager.getSubnetsConfigList());
     }
 
     /**
      * List the configuration of a subnet in a given container
-     *
-     * @param containerName container in which we want to query the
-     * subnet
-     * @param subnetName of the subnet being queried
-     *
+     * 
+     * @param containerName
+     *            container in which we want to query the subnet
+     * @param subnetName
+     *            of the subnet being queried
+     * 
      * @return a SubnetConfig
      */
     @Path("/{containerName}/{subnetName}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( {
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
             @ResponseCode(code = 404, condition = "The containerName passed was not found"),
             @ResponseCode(code = 404, condition = "Subnet does not exist") })
     @TypeHint(SubnetConfig.class)
     public SubnetConfig listSubnet(
             @PathParam("containerName") String containerName,
             @PathParam("subnetName") String subnetName) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         ISwitchManager switchManager = null;
         switchManager = (ISwitchManager) ServiceHelper.getInstance(
                 ISwitchManager.class, containerName, this);
         if (switchManager == null) {
-            throw new ResourceNotFoundException(RestMessages.NOCONTAINER
-                    .toString());
+            throw new ResourceNotFoundException(
+                    RestMessages.NOCONTAINER.toString());
         }
         SubnetConfig res = switchManager.getSubnetConfig(subnetName);
         if (res == null) {
-            throw new ResourceNotFoundException(RestMessages.NOSUBNET
-                    .toString());
+            throw new ResourceNotFoundException(
+                    RestMessages.NOSUBNET.toString());
         } else {
             return res;
         }
@@ -99,17 +129,19 @@ public class SubnetsNorthboundJAXRS {
 
     /**
      * Add/Update a subnet to a container
-     *
-     * @param containerName container in which we want to add/update the
-     * subnet
-     * @param subnetName that has to be added
-     * @param subnet pair default gateway IP/mask that identify the
-     * subnet being added modified
-     *
+     * 
+     * @param containerName
+     *            container in which we want to add/update the subnet
+     * @param subnetName
+     *            that has to be added
+     * @param subnet
+     *            pair default gateway IP/mask that identify the subnet being
+     *            added modified
+     * 
      */
     @Path("/{containerName}/{subnetName}")
     @POST
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 404, condition = "The containerName passed was not found"),
             @ResponseCode(code = 404, condition = "Invalid Data passed"),
             @ResponseCode(code = 201, condition = "Subnet added/modified"),
@@ -117,17 +149,27 @@ public class SubnetsNorthboundJAXRS {
     public Response addSubnet(@PathParam("containerName") String containerName,
             @PathParam("subnetName") String subnetName,
             @QueryParam("subnet") String subnet) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         if (subnetName == null) {
-            throw new ResourceNotFoundException(RestMessages.INVALIDDATA.toString());
+            throw new ResourceNotFoundException(
+                    RestMessages.INVALIDDATA.toString());
         }
         if (subnet == null) {
-            throw new ResourceNotFoundException(RestMessages.INVALIDDATA.toString());
+            throw new ResourceNotFoundException(
+                    RestMessages.INVALIDDATA.toString());
         }
         ISwitchManager switchManager = null;
         switchManager = (ISwitchManager) ServiceHelper.getInstance(
                 ISwitchManager.class, containerName, this);
         if (switchManager == null) {
-            throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
+            throw new ResourceNotFoundException(
+                    RestMessages.NOCONTAINER.toString());
         }
 
         SubnetConfig cfgObject = new SubnetConfig(subnetName, subnet,
@@ -141,30 +183,39 @@ public class SubnetsNorthboundJAXRS {
 
     /**
      * Delete a subnet from a container
-     *
-     * @param containerName container in which we want to delete the
-     * subnet by name
-     * @param subnetName of the subnet to be remove.
-     *
+     * 
+     * @param containerName
+     *            container in which we want to delete the subnet by name
+     * @param subnetName
+     *            of the subnet to be remove.
+     * 
      */
     @Path("/{containerName}/{subnetName}")
     @DELETE
-    @StatusCodes( {
+    @StatusCodes({
             @ResponseCode(code = 404, condition = "The containerName passed was not found"),
             @ResponseCode(code = 500, condition = "Removal of subnet failed") })
     public Response removeSubnet(
             @PathParam("containerName") String containerName,
             @PathParam("subnetName") String subnetName) {
         if (subnetName == null) {
-            throw new ResourceNotFoundException(RestMessages.INVALIDDATA
-                    .toString());
+            throw new ResourceNotFoundException(
+                    RestMessages.INVALIDDATA.toString());
         }
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+
         ISwitchManager switchManager = null;
         switchManager = (ISwitchManager) ServiceHelper.getInstance(
                 ISwitchManager.class, containerName, this);
         if (switchManager == null) {
-            throw new ResourceNotFoundException(RestMessages.NOCONTAINER
-                    .toString());
+            throw new ResourceNotFoundException(
+                    RestMessages.NOCONTAINER.toString());
         }
         Status status = switchManager.removeSubnet(subnetName);
         if (status.isSuccess()) {
@@ -173,58 +224,57 @@ public class SubnetsNorthboundJAXRS {
         throw new InternalServerErrorException(status.getDescription());
     }
 
-    /* /\** */
-    /*  * */
-    /*  * Add or remove switch ports to a subnet */
-    /*  * */
-    /*  * POST subnets/green/sw */
-    /*  * */
-    /*  * @param model */
-    /*  * @param containerName */
-    /*  * @param name */
-    /*  * @param subnet: the subnet name name */
-    /*  * @param switchports: datapath ID/port list => xx:xx:xx:xx:xx:xx:xx:xx/a,b,c-m,r-t,y */
-    /*  * @return */
-    /*  *\/ */
-    /* @RequestMapping(value = "/{containerName}/{name}", method = RequestMethod.POST) */
-    /* public View addSwitchports(Map<String, Object> model, */
-    /*         @PathVariable(value = "containerName") String containerName, */
-    /*         @PathVariable(value = "name") String name, */
-    /*         @RequestParam(value = "nodeports") String nodePorts, */
-    /*         @RequestParam(value = "action") String action) { */
-
-    /*     checkDefaultDisabled(containerName); */
-
-    /*     ISwitchManager switchManager = null; */
-    /*     try { */
-    /*         BundleContext bCtx = FrameworkUtil.getBundle(this.getClass()) */
-    /*                 .getBundleContext(); */
-
-    /*         ServiceReference[] services = bCtx.getServiceReferences( */
-    /*                 ISwitchManager.class.getName(), "(containerName=" */
-    /*                         + containerName + ")"); */
-
-    /*         if (services != null) { */
-    /*             switchManager = (ISwitchManager) bCtx.getService(services[0]); */
-    /*             logger.debug("Switch manager reference is:" + switchManager); */
-    /*         } */
-    /*     } catch (Exception e) { */
-    /*         logger.error("Switch Manager reference is NULL"); */
-    /*     } */
-
-    /*     checkContainerExists(switchManager); */
-
-    /*     String ret; */
-    /*     if (action.equals("add")) { */
-    /*         ret = switchManager.addPortsToSubnet(name, nodePorts); */
-    /*     } else if (action.equals("remove")) { */
-    /*         ret = switchManager.removePortsFromSubnet(name, nodePorts); */
-    /*     } else { */
-    /*         throw new UnsupportedMediaTypeException(RestMessages.UNKNOWNACTION */
-    /*                 .toString() */
-    /*                 + ": " + action); */
-    /*     } */
-
-    /*     return returnViewOrThrowConflicEx(model, ret); */
-    /* } */
+    /*
+     * 
+     * Add or remove switch ports to a subnet POST subnets/green/sw
+     * 
+     * @param model
+     * 
+     * @param containerName
+     * 
+     * @param name
+     * 
+     * @param subnet: the subnet name name
+     * 
+     * @param switchports: datapath ID/port list =>
+     * xx:xx:xx:xx:xx:xx:xx:xx/a,b,c-m,r-t,y
+     * 
+     * @return
+     * 
+     * @RequestMapping(value = "/{containerName}/{name}", method =
+     * RequestMethod.POST)
+     * 
+     * public View addSwitchports(Map<String, Object> model,
+     * 
+     * @PathVariable(value = "containerName") String containerName,
+     * 
+     * @PathVariable(value = "name") String name,
+     * 
+     * @RequestParam(value = "nodeports") String nodePorts,
+     * 
+     * @RequestParam(value = "action") String action) {
+     * 
+     * checkDefaultDisabled(containerName); ISwitchManager switchManager = null;
+     * try { BundleContext bCtx = FrameworkUtil.getBundle(this.getClass())
+     * .getBundleContext();
+     * 
+     * ServiceReference[] services = bCtx.getServiceReferences(
+     * ISwitchManager.class.getName(), "(containerName=" + containerName + ")");
+     * 
+     * if (services != null) { switchManager = (ISwitchManager)
+     * bCtx.getService(services[0]); logger.debug("Switch manager reference is:"
+     * + switchManager); } } catch (Exception e) {
+     * logger.error("Switch Manager reference is NULL"); }
+     * 
+     * checkContainerExists(switchManager);
+     * 
+     * String ret; if (action.equals("add")) { ret =
+     * switchManager.addPortsToSubnet(name, nodePorts); } else if
+     * (action.equals("remove")) { ret =
+     * switchManager.removePortsFromSubnet(name, nodePorts); } else { throw new
+     * UnsupportedMediaTypeException(RestMessages.UNKNOWNACTION .toString() +
+     * ": " + action); }
+     * 
+     * return returnViewOrThrowConflicEx(model, ret); }
+     */
 }
index 25757e6..7a97e17 100644 (file)
               org.opendaylight.controller.sal.utils,
               org.opendaylight.controller.containermanager,
               org.opendaylight.controller.switchmanager,
+              org.opendaylight.controller.usermanager,
               org.apache.commons.lang3.tuple,
               org.apache.commons.logging,              
               com.sun.jersey.spi.container.servlet,
               org.opendaylight.controller.northbound.commons,
               org.opendaylight.controller.northbound.commons.exception,
-              javax.ws.rs,
+              org.opendaylight.controller.northbound.commons.utils,
+              org.opendaylight.controller.sal.authorization,
+                         javax.ws.rs,
               javax.ws.rs.core,
               javax.xml.bind.annotation,
               javax.xml.bind,
index c26d4f2..7bdd3f3 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -23,8 +22,11 @@ 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.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+
 import org.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
 import org.codehaus.enunciate.jaxrs.TypeHint;
@@ -34,6 +36,9 @@ import org.opendaylight.controller.northbound.commons.exception.InternalServerEr
 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
 import org.opendaylight.controller.sal.core.MacAddress;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
@@ -52,168 +57,219 @@ import org.opendaylight.controller.switchmanager.ISwitchManager;
 @Path("/")
 public class SwitchNorthbound {
 
-       private ISwitchManager getIfSwitchManagerService(String containerName) {
-               IContainerManager containerManager = (IContainerManager) ServiceHelper
-               .getGlobalInstance(IContainerManager.class, this);
-               if (containerManager == null) {
-                       throw new ServiceUnavailableException("Container "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               boolean found = false;
-               List<String> containerNames = containerManager.getContainerNames();
-               for (String cName : containerNames) {
-                       if (cName.trim().equalsIgnoreCase(containerName.trim())) {
-                               found = true;
-                       }
-               }
-
-               if (found == false) {
-                       throw new ResourceNotFoundException(containerName + " "
-                                       + RestMessages.NOCONTAINER.toString());
-               }
-
-               ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(
-                               ISwitchManager.class, containerName, this);
-
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               return switchManager;
-       }
-
-       /**
-        * 
-        * Retrieve a list of all the nodes and their properties in the network
-        * 
-        * @param containerName The container for which we want to retrieve the list
-        * @return A list of Pair each pair represents a
-        *         {@link org.opendaylight.controller.sal.core.Node} and Set of
-        *         {@link org.opendaylight.controller.sal.core.Property} attached to
-        *         it.
-        */
-       @Path("/{containerName}/nodes")
-       @GET
-       @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-       @TypeHint(Nodes.class)
-       @StatusCodes( {
-               @ResponseCode(code = 200, condition = "Operation successful"),
-               @ResponseCode(code = 404, condition = "The containerName is not found"),
-               @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
-               public Nodes getNodes(
-                               @PathParam("containerName") String containerName) {
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               List<NodeProperties> res = new ArrayList<NodeProperties>();
-               Set<Node> nodes = switchManager.getNodes();
-               if (nodes == null) {
-                       return null;
-               }
-
-               byte[] controllerMac = switchManager.getControllerMAC();
-               for (Node node : nodes) {
-                       Map<String, Property> propMap = switchManager.getNodeProps(node);
-                       if (propMap == null) {
-                               continue;
-                       }
-                       Set<Property> props = new HashSet<Property>(propMap.values());
-                       
-                       byte[] nodeMac = switchManager.getNodeMAC(node);
-                       Property macAddr = new MacAddress(controllerMac, nodeMac);
-                       props.add(macAddr);
-                       
-                       NodeProperties nodeProps = new NodeProperties(node, props);
-                       res.add(nodeProps);
-               }
-
-               return new Nodes(res);
-       }
+    private String username;
+
+    @Context
+    public void setSecurityContext(SecurityContext context) {
+        username = context.getUserPrincipal().getName();
+    }
+
+    protected String getUserName() {
+        return username;
+    }
+
+    private ISwitchManager getIfSwitchManagerService(String containerName) {
+        IContainerManager containerManager = (IContainerManager) ServiceHelper
+                .getGlobalInstance(IContainerManager.class, this);
+        if (containerManager == null) {
+            throw new ServiceUnavailableException("Container "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        boolean found = false;
+        List<String> containerNames = containerManager.getContainerNames();
+        for (String cName : containerNames) {
+            if (cName.trim().equalsIgnoreCase(containerName.trim())) {
+                found = true;
+                break;
+            }
+        }
+
+        if (found == false) {
+            throw new ResourceNotFoundException(containerName + " "
+                    + RestMessages.NOCONTAINER.toString());
+        }
+
+        ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+                .getInstance(ISwitchManager.class, containerName, this);
+
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        return switchManager;
+    }
+
+    /**
+     * 
+     * Retrieve a list of all the nodes and their properties in the network
+     * 
+     * @param containerName
+     *            The container for which we want to retrieve the list
+     * @return A list of Pair each pair represents a
+     *         {@link org.opendaylight.controller.sal.core.Node} and Set of
+     *         {@link org.opendaylight.controller.sal.core.Property} attached to
+     *         it.
+     */
+    @Path("/{containerName}/nodes")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(Nodes.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The containerName is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+    public Nodes getNodes(@PathParam("containerName") String containerName) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+
+        ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        List<NodeProperties> res = new ArrayList<NodeProperties>();
+        Set<Node> nodes = switchManager.getNodes();
+        if (nodes == null) {
+            return null;
+        }
+
+        byte[] controllerMac = switchManager.getControllerMAC();
+        for (Node node : nodes) {
+            Map<String, Property> propMap = switchManager.getNodeProps(node);
+            if (propMap == null) {
+                continue;
+            }
+            Set<Property> props = new HashSet<Property>(propMap.values());
+
+            byte[] nodeMac = switchManager.getNodeMAC(node);
+            Property macAddr = new MacAddress(controllerMac, nodeMac);
+            props.add(macAddr);
+
+            NodeProperties nodeProps = new NodeProperties(node, props);
+            res.add(nodeProps);
+        }
+
+        return new Nodes(res);
+    }
 
     /**
      * Add a Name/Tier property to a node
-     *
-     * @param containerName Name of the Container
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
-     * @param propName Name of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
-     * @param propValue Value of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
+     * 
+     * @param containerName
+     *            Name of the Container
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier as specified by
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @param propName
+     *            Name of the Property specified by
+     *            {@link org.opendaylight.controller.sal.core.Property} and its
+     *            extended classes
+     * @param propValue
+     *            Value of the Property specified by
+     *            {@link org.opendaylight.controller.sal.core.Property} and its
+     *            extended classes
      * @return Response as dictated by the HTTP Response Status code
      */
 
     @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propName}/{propValue}")
     @PUT
-    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(Response.class)
-    @StatusCodes( {
-           @ResponseCode(code = 200, condition = "Operation successful"),
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
-    public Response addNodeProperty(@PathParam("containerName") String containerName,
+    public Response addNodeProperty(
+            @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId,
             @PathParam("propName") String propName,
             @PathParam("propValue") String propValue) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
 
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
+        ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
 
         handleNodeAvailability(containerName, nodeType, nodeId);
-               Node node = Node.fromString(nodeId);
-        
-               Property prop = switchManager.createProperty(propName, propValue);
-               if (prop == null) {
-                       throw new ResourceNotFoundException(
-                                       RestMessages.INVALIDDATA.toString());
-               }
-               
+        Node node = Node.fromString(nodeId);
+
+        Property prop = switchManager.createProperty(propName, propValue);
+        if (prop == null) {
+            throw new ResourceNotFoundException(
+                    RestMessages.INVALIDDATA.toString());
+        }
+
         switchManager.setNodeProp(node, prop);
         return Response.status(Response.Status.CREATED).build();
     }
 
     /**
      * Delete a property of a node
-     *
-     * @param containerName Name of the Container
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
-     * @param propertyName Name of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
+     * 
+     * @param containerName
+     *            Name of the Container
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier as specified by
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @param propertyName
+     *            Name of the Property specified by
+     *            {@link org.opendaylight.controller.sal.core.Property} and its
+     *            extended classes
      * @return Response as dictated by the HTTP Response Status code
      */
 
     @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}")
     @DELETE
-    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( {
-           @ResponseCode(code = 200, condition = "Operation successful"),
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
-    public Response deleteNodeProperty(@PathParam("containerName") String containerName,
+    public Response deleteNodeProperty(
+            @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId,
             @PathParam("propertyName") String propertyName) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         handleDefaultDisabled(containerName);
 
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
+        ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
 
         handleNodeAvailability(containerName, nodeType, nodeId);
-               Node node = Node.fromString(nodeId);
-        
+        Node node = Node.fromString(nodeId);
+
         Status ret = switchManager.removeNodeProp(node, propertyName);
         if (ret.isSuccess()) {
             return Response.ok().build();
@@ -221,80 +277,109 @@ public class SwitchNorthbound {
         throw new ResourceNotFoundException(ret.getDescription());
     }
 
-       /**
-        * 
-        * Retrieve a list of all the node connectors and their properties in a given node
-        * 
-        * @param containerName The container for which we want to retrieve the list
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
-        * @return A List of Pair each pair represents a
-        *         {@link org.opendaylight.controller.sal.core.NodeConnector} and
-        *         its corresponding
-        *         {@link org.opendaylight.controller.sal.core.Property} attached to
-        *         it.
-        */
-       @Path("/{containerName}/node/{nodeType}/{nodeId}")
-       @GET
-       @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-       @TypeHint(NodeConnectors.class)
-       @StatusCodes( {
-               @ResponseCode(code = 200, condition = "Operation successful"),
-               @ResponseCode(code = 404, condition = "The containerName is not found"),
-               @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
-               public NodeConnectors getNodeConnectors(
-                               @PathParam("containerName") String containerName,
-                   @PathParam("nodeType") String nodeType,
-                               @PathParam("nodeId") String nodeId) {
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               handleNodeAvailability(containerName, nodeType,nodeId);
-               Node node = Node.fromString(nodeId);
-
-               List<NodeConnectorProperties> res = new ArrayList<NodeConnectorProperties>();
-               Set<NodeConnector> ncs = switchManager.getNodeConnectors(node);
-               if (ncs == null) {
-                       return null;
-               }
-
-               for (NodeConnector nc : ncs) {
-                       Map<String, Property> propMap = switchManager.getNodeConnectorProps(nc);
-                       if (propMap == null) {
-                               continue;
-                       }
-                       Set<Property> props = new HashSet<Property>(propMap.values());
-                       NodeConnectorProperties ncProps = new NodeConnectorProperties(nc, props);
-                       res.add(ncProps);
-               }
-
-               return new NodeConnectors(res);
-       }
+    /**
+     * 
+     * Retrieve a list of all the node connectors and their properties in a
+     * given node
+     * 
+     * @param containerName
+     *            The container for which we want to retrieve the list
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier as specified by
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return A List of Pair each pair represents a
+     *         {@link org.opendaylight.controller.sal.core.NodeConnector} and
+     *         its corresponding
+     *         {@link org.opendaylight.controller.sal.core.Property} attached to
+     *         it.
+     */
+    @Path("/{containerName}/node/{nodeType}/{nodeId}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(NodeConnectors.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The containerName is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+    public NodeConnectors getNodeConnectors(
+            @PathParam("containerName") String containerName,
+            @PathParam("nodeType") String nodeType,
+            @PathParam("nodeId") String nodeId) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+
+        ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        handleNodeAvailability(containerName, nodeType, nodeId);
+        Node node = Node.fromString(nodeId);
+
+        List<NodeConnectorProperties> res = new ArrayList<NodeConnectorProperties>();
+        Set<NodeConnector> ncs = switchManager.getNodeConnectors(node);
+        if (ncs == null) {
+            return null;
+        }
+
+        for (NodeConnector nc : ncs) {
+            Map<String, Property> propMap = switchManager
+                    .getNodeConnectorProps(nc);
+            if (propMap == null) {
+                continue;
+            }
+            Set<Property> props = new HashSet<Property>(propMap.values());
+            NodeConnectorProperties ncProps = new NodeConnectorProperties(nc,
+                    props);
+            res.add(ncProps);
+        }
+
+        return new NodeConnectors(res);
+    }
 
     /**
      * Add a Name/Bandwidth property to a node connector
-     *
-     * @param containerName Name of the Container 
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
-     * @param nodeConnectorType Type of the node connector being programmed
-     * @param nodeConnectorId NodeConnector Identifier as specified by {@link org.opendaylight.controller.sal.core.NodeConnector}
-     * @param propName Name of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
-     * @param propValue Value of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
+     * 
+     * @param containerName
+     *            Name of the Container
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier as specified by
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @param nodeConnectorType
+     *            Type of the node connector being programmed
+     * @param nodeConnectorId
+     *            NodeConnector Identifier as specified by
+     *            {@link org.opendaylight.controller.sal.core.NodeConnector}
+     * @param propName
+     *            Name of the Property specified by
+     *            {@link org.opendaylight.controller.sal.core.Property} and its
+     *            extended classes
+     * @param propValue
+     *            Value of the Property specified by
+     *            {@link org.opendaylight.controller.sal.core.Property} and its
+     *            extended classes
      * @return Response as dictated by the HTTP Response Status code
      */
 
     @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propName}/{propValue}")
     @PUT
-    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( {
-           @ResponseCode(code = 200, condition = "Operation successful"),
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
-    public Response addNodeConnectorProperty(@PathParam("containerName") String containerName,
+    public Response addNodeConnectorProperty(
+            @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId,
             @PathParam("nodeConnectorType") String nodeConnectorType,
@@ -302,27 +387,36 @@ public class SwitchNorthbound {
             @PathParam("propName") String propName,
             @PathParam("propValue") String propValue) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+
         handleDefaultDisabled(containerName);
 
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               handleNodeAvailability(containerName, nodeType, nodeId);
-               Node node = Node.fromString(nodeId);
-
-               handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
-               NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorId, node);
-        
-               Property prop = switchManager.createProperty(propName, propValue);
-               if (prop == null) {
-                       throw new ResourceNotFoundException(
-                                       RestMessages.INVALIDDATA.toString());
-               }
-               
-               Status ret = switchManager.addNodeConnectorProp(nc, prop);
+        ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        handleNodeAvailability(containerName, nodeType, nodeId);
+        Node node = Node.fromString(nodeId);
+
+        handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
+                nodeConnectorId);
+        NodeConnector nc = NodeConnector
+                .fromStringNoNode(nodeConnectorId, node);
+
+        Property prop = switchManager.createProperty(propName, propValue);
+        if (prop == null) {
+            throw new ResourceNotFoundException(
+                    RestMessages.INVALIDDATA.toString());
+        }
+
+        Status ret = switchManager.addNodeConnectorProp(nc, prop);
         if (ret.isSuccess()) {
             return Response.status(Response.Status.CREATED).build();
         }
@@ -331,44 +425,64 @@ public class SwitchNorthbound {
 
     /**
      * Delete a property of a node connector
-     *
-     * @param containerName Name of the Container
-     * @param nodeType Type of the node being programmed
-     * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
-     * @param nodeConnectorType Type of the node connector being programmed
-     * @param nodeConnectorId NodeConnector Identifier as specified by {@link org.opendaylight.controller.sal.core.NodeConnector}
-     * @param propertyName Name of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
+     * 
+     * @param containerName
+     *            Name of the Container
+     * @param nodeType
+     *            Type of the node being programmed
+     * @param nodeId
+     *            Node Identifier as specified by
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @param nodeConnectorType
+     *            Type of the node connector being programmed
+     * @param nodeConnectorId
+     *            NodeConnector Identifier as specified by
+     *            {@link org.opendaylight.controller.sal.core.NodeConnector}
+     * @param propertyName
+     *            Name of the Property specified by
+     *            {@link org.opendaylight.controller.sal.core.Property} and its
+     *            extended classes
      * @return Response as dictated by the HTTP Response Status code
      */
 
     @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}")
     @DELETE
-    @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @StatusCodes( {
-           @ResponseCode(code = 200, condition = "Operation successful"),
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
-    public Response deleteNodeConnectorProperty(@PathParam("containerName") String containerName,
+    public Response deleteNodeConnectorProperty(
+            @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId,
             @PathParam("nodeConnectorType") String nodeConnectorType,
             @PathParam("nodeConnectorId") String nodeConnectorId,
             @PathParam("propertyName") String propertyName) {
 
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+
         handleDefaultDisabled(containerName);
 
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               handleNodeAvailability(containerName, nodeType, nodeId);
-               Node node = Node.fromString(nodeId);
-               
-               handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
-               NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorId, node);
-        
+        ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        handleNodeAvailability(containerName, nodeType, nodeId);
+        Node node = Node.fromString(nodeId);
+
+        handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
+                nodeConnectorId);
+        NodeConnector nc = NodeConnector
+                .fromStringNoNode(nodeConnectorId, node);
+
         Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
         if (ret.isSuccess()) {
             return Response.ok().build();
@@ -376,174 +490,208 @@ public class SwitchNorthbound {
         throw new ResourceNotFoundException(ret.getDescription());
     }
 
-/*    *//**
+    /*    *//**
      * Retrieve a list of Span ports that were configured previously.
-     *
-     * @param containerName Name of the Container 
-     * @return list of {@link org.opendaylight.controller.switchmanager.SpanConfig} resources
-     *//*
-       @Path("/span-config/{containerName}")
-       @GET
-       @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-       @StatusCodes( {
-               @ResponseCode(code = 200, condition = "Operation successful"),
-               @ResponseCode(code = 404, condition = "The containerName is not found"),
-               @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
-               public List<SpanConfig> getSpanConfigList(@PathParam("containerName") String containerName) {
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               return switchManager.getSpanConfigList();
-       }
-
-    *//**
+     * 
+     * @param containerName
+     *            Name of the Container
+     * @return list of
+     *         {@link org.opendaylight.controller.switchmanager.SpanConfig}
+     *         resources
+     */
+    /*
+     * @Path("/span-config/{containerName}")
+     * 
+     * @GET
+     * 
+     * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+     * 
+     * @StatusCodes( {
+     * 
+     * @ResponseCode(code = 200, condition = "Operation successful"),
+     * 
+     * @ResponseCode(code = 404, condition = "The containerName is not found"),
+     * 
+     * @ResponseCode(code = 503, condition =
+     * "One or more of Controller Services are unavailable") }) public
+     * List<SpanConfig> getSpanConfigList(@PathParam("containerName") String
+     * containerName) { ISwitchManager switchManager = (ISwitchManager)
+     * getIfSwitchManagerService(containerName); if (switchManager == null) {
+     * throw new ServiceUnavailableException("Switch Manager " +
+     * RestMessages.SERVICEUNAVAILABLE.toString()); }
+     * 
+     * return switchManager.getSpanConfigList(); }
+     *//**
      * Add a span configuration
-     *
-     * @param containerName Name of the Container 
-     * @param config {@link org.opendaylight.controller.switchmanager.SpanConfig} in JSON or XML format
+     * 
+     * @param containerName
+     *            Name of the Container
+     * @param config
+     *            {@link org.opendaylight.controller.switchmanager.SpanConfig}
+     *            in JSON or XML format
      * @return Response as dictated by the HTTP Response Status code
-     *//*
-       @Path("/span-config/{containerName}")
-       @PUT
-       @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-       @StatusCodes( {
-               @ResponseCode(code = 200, condition = "Operation successful"),
-               @ResponseCode(code = 404, condition = "The containerName is not found"),
-               @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
-               public Response addSpanConfig(@PathParam("containerName") String containerName,
-                   @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               String ret = switchManager.addSpanConfig(config.getValue());
-        if (ret.equals(ReturnString.SUCCESS.toString())) {
-            return Response.status(Response.Status.CREATED).build();
-        }
-        throw new InternalServerErrorException(ret);
-       }
-
-    *//**
+     */
+    /*
+     * @Path("/span-config/{containerName}")
+     * 
+     * @PUT
+     * 
+     * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+     * 
+     * @StatusCodes( {
+     * 
+     * @ResponseCode(code = 200, condition = "Operation successful"),
+     * 
+     * @ResponseCode(code = 404, condition = "The containerName is not found"),
+     * 
+     * @ResponseCode(code = 503, condition =
+     * "One or more of Controller Services are unavailable") }) public Response
+     * addSpanConfig(@PathParam("containerName") String containerName,
+     * 
+     * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
+     * ISwitchManager switchManager = (ISwitchManager)
+     * getIfSwitchManagerService(containerName); if (switchManager == null) {
+     * throw new ServiceUnavailableException("Switch Manager " +
+     * RestMessages.SERVICEUNAVAILABLE.toString()); }
+     * 
+     * String ret = switchManager.addSpanConfig(config.getValue()); if
+     * (ret.equals(ReturnString.SUCCESS.toString())) { return
+     * Response.status(Response.Status.CREATED).build(); } throw new
+     * InternalServerErrorException(ret); }
+     *//**
      * Delete a span configuration
-     *
-     * @param containerName Name of the Container 
-     * @param config {@link org.opendaylight.controller.switchmanager.SpanConfig} in JSON or XML format
+     * 
+     * @param containerName
+     *            Name of the Container
+     * @param config
+     *            {@link org.opendaylight.controller.switchmanager.SpanConfig}
+     *            in JSON or XML format
      * @return Response as dictated by the HTTP Response Status code
-     *//*
-       @Path("/span-config/{containerName}")
-       @DELETE
-       @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-       @StatusCodes( {
-               @ResponseCode(code = 200, condition = "Operation successful"),
-               @ResponseCode(code = 404, condition = "The containerName is not found"),
-               @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
-               public Response deleteSpanConfig(@PathParam("containerName") String containerName,
-                   @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               String ret = switchManager.removeSpanConfig(config.getValue());
-        if (ret.equals(ReturnString.SUCCESS.toString())) {
-            return Response.ok().build();
-        }
-        throw new ResourceNotFoundException(ret);
-       }
-*/
-    
+     */
+    /*
+     * @Path("/span-config/{containerName}")
+     * 
+     * @DELETE
+     * 
+     * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+     * 
+     * @StatusCodes( {
+     * 
+     * @ResponseCode(code = 200, condition = "Operation successful"),
+     * 
+     * @ResponseCode(code = 404, condition = "The containerName is not found"),
+     * 
+     * @ResponseCode(code = 503, condition =
+     * "One or more of Controller Services are unavailable") }) public Response
+     * deleteSpanConfig(@PathParam("containerName") String containerName,
+     * 
+     * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
+     * ISwitchManager switchManager = (ISwitchManager)
+     * getIfSwitchManagerService(containerName); if (switchManager == null) {
+     * throw new ServiceUnavailableException("Switch Manager " +
+     * RestMessages.SERVICEUNAVAILABLE.toString()); }
+     * 
+     * String ret = switchManager.removeSpanConfig(config.getValue()); if
+     * (ret.equals(ReturnString.SUCCESS.toString())) { return
+     * Response.ok().build(); } throw new ResourceNotFoundException(ret); }
+     */
+
     /**
      * Save the current switch configurations
-     *
-     * @param containerName Name of the Container 
+     * 
+     * @param containerName
+     *            Name of the Container
      * @return Response as dictated by the HTTP Response Status code
      */
-       @Path("/{containerName}/switch-config")
-       @POST
-       @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-       @StatusCodes( {
-               @ResponseCode(code = 200, condition = "Operation successful"),
-               @ResponseCode(code = 404, condition = "The containerName is not found"),
-               @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
-               public Response saveSwitchConfig(@PathParam("containerName") String containerName) {
-               ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
-               if (switchManager == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               Status ret = switchManager.saveSwitchConfig();
+    @Path("/{containerName}/switch-config")
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The containerName is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+    public Response saveSwitchConfig(
+            @PathParam("containerName") String containerName) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+        ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        Status ret = switchManager.saveSwitchConfig();
         if (ret.isSuccess()) {
             return Response.ok().build();
         }
         throw new InternalServerErrorException(ret.getDescription());
-       }
+    }
 
     private void handleDefaultDisabled(String containerName) {
         IContainerManager containerManager = (IContainerManager) ServiceHelper
                 .getGlobalInstance(IContainerManager.class, this);
         if (containerManager == null) {
-            throw new InternalServerErrorException(RestMessages.INTERNALERROR
-                    .toString());
+            throw new InternalServerErrorException(
+                    RestMessages.INTERNALERROR.toString());
         }
         if (containerName.equals(GlobalConstants.DEFAULT.toString())
                 && containerManager.hasNonDefaultContainer()) {
-            throw new ResourceConflictException(RestMessages.DEFAULTDISABLED
-                    .toString());
+            throw new ResourceConflictException(
+                    RestMessages.DEFAULTDISABLED.toString());
         }
     }
 
     private Node handleNodeAvailability(String containerName, String nodeType,
-               String nodeId) {
-
-       Node node = Node.fromString(nodeType, nodeId);
-       if (node == null) {
-               throw new ResourceNotFoundException(nodeId + " : "
-                               + RestMessages.NONODE.toString());
-       }
-
-       ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
-                       ISwitchManager.class, containerName, this);
-
-       if (sm == null) {
-               throw new ServiceUnavailableException("Switch Manager "
-                               + RestMessages.SERVICEUNAVAILABLE.toString());
-       }
-
-       if (!sm.getNodes().contains(node)) {
-               throw new ResourceNotFoundException(node.toString() + " : "
-                               + RestMessages.NONODE.toString());
-       }
-       return node;
+            String nodeId) {
+
+        Node node = Node.fromString(nodeType, nodeId);
+        if (node == null) {
+            throw new ResourceNotFoundException(nodeId + " : "
+                    + RestMessages.NONODE.toString());
+        }
+
+        ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
+                ISwitchManager.class, containerName, this);
+
+        if (sm == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if (!sm.getNodes().contains(node)) {
+            throw new ResourceNotFoundException(node.toString() + " : "
+                    + RestMessages.NONODE.toString());
+        }
+        return node;
+    }
+
+    private void handleNodeConnectorAvailability(String containerName,
+            Node node, String nodeConnectorType, String nodeConnectorId) {
+
+        NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType,
+                nodeConnectorId, node);
+        if (nc == null) {
+            throw new ResourceNotFoundException(nc + " : "
+                    + RestMessages.NORESOURCE.toString());
+        }
+
+        ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
+                ISwitchManager.class, containerName, this);
+
+        if (sm == null) {
+            throw new ServiceUnavailableException("Switch Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if (!sm.getNodeConnectors(node).contains(nc)) {
+            throw new ResourceNotFoundException(nc.toString() + " : "
+                    + RestMessages.NORESOURCE.toString());
+        }
     }
 
-       private void handleNodeConnectorAvailability(String containerName,
-                       Node node, String nodeConnectorType, String nodeConnectorId) {
-
-               NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType,
-                               nodeConnectorId, node);
-               if (nc == null) {
-                       throw new ResourceNotFoundException(nc + " : "
-                                       + RestMessages.NORESOURCE.toString());
-               }
-               
-               ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
-                               ISwitchManager.class, containerName, this);
-
-               if (sm == null) {
-                       throw new ServiceUnavailableException("Switch Manager "
-                                       + RestMessages.SERVICEUNAVAILABLE.toString());
-               }
-
-               if (!sm.getNodeConnectors(node).contains(nc)) {
-                       throw new ResourceNotFoundException(nc.toString() + " : "
-                                       + RestMessages.NORESOURCE.toString());
-               }
-       }
 }
index 0cfa487..b8eebe4 100644 (file)
               org.opendaylight.controller.containermanager,
               org.opendaylight.controller.northbound.commons,
               org.opendaylight.controller.northbound.commons.exception,
+              org.opendaylight.controller.northbound.commons.utils,
               org.opendaylight.controller.sal.core,
               org.opendaylight.controller.sal.packet,
-              org.opendaylight.controller.sal.packet.address,
+              org.opendaylight.controller.sal.authorization,
+                         org.opendaylight.controller.sal.packet.address,
               org.opendaylight.controller.sal.utils,
               org.opendaylight.controller.switchmanager,
+              org.opendaylight.controller.usermanager,
               org.opendaylight.controller.topologymanager,
               com.sun.jersey.spi.container.servlet,
-              javax.ws.rs,
+                         javax.ws.rs,
               javax.ws.rs.core,
               javax.xml.bind,
               javax.xml.bind.annotation,
index 5f1933b..10480bc 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -22,8 +21,10 @@ import javax.ws.rs.POST;
 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.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
 import javax.xml.bind.JAXBElement;
 
 import org.codehaus.enunciate.jaxrs.ResponseCode;
@@ -32,61 +33,82 @@ import org.codehaus.enunciate.jaxrs.TypeHint;
 import org.opendaylight.controller.northbound.commons.RestMessages;
 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
 import org.opendaylight.controller.sal.core.Edge;
 import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.topologymanager.ITopologyManager;
 import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Topology Northbound REST API
  * 
- * <br><br>
+ * <br>
+ * <br>
  * Authentication scheme : <b>HTTP Basic</b><br>
  * Authentication realm : <b>opendaylight</b><br>
  * Transport : <b>HTTP and HTTPS</b><br>
  * <br>
- * HTTPS Authentication is disabled by default. Administrator can enable it in tomcat-server.xml after adding 
- * a proper keystore / SSL certificate from a trusted authority.<br>
- * More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
  */
 
 @Path("/")
 public class TopologyNorthboundJAXRS {
-    private static Logger logger = LoggerFactory
-            .getLogger(TopologyNorthboundJAXRS.class);
+
+    private String username;
+
+    @Context
+    public void setSecurityContext(SecurityContext context) {
+        username = context.getUserPrincipal().getName();
+    }
+
+    protected String getUserName() {
+        return username;
+    }
 
     /**
-     *
+     * 
      * Retrieve the Topology
-     *
-     * @param containerName The container for which we want to retrieve the topology
-     *
-     * @return A List of EdgeProps each EdgeProp represent an Edge of
-     * the grap with the corresponding properties attached to it.
+     * 
+     * @param containerName
+     *            The container for which we want to retrieve the topology
+     * 
+     * @return A List of EdgeProps each EdgeProp represent an Edge of the grap
+     *         with the corresponding properties attached to it.
      */
     @Path("/{containerName}")
     @GET
-    @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(Topology.class)
-    @StatusCodes( { @ResponseCode(code = 404, condition = "The Container Name passed was not found") })
-    public Topology getTopology(
-            @PathParam("containerName") String containerName) {
+    @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name passed was not found") })
+    public Topology getTopology(@PathParam("containerName") String containerName) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
                 .getInstance(ITopologyManager.class, containerName, this);
         if (topologyManager == null) {
-            throw new ResourceNotFoundException(RestMessages.NOCONTAINER
-                    .toString());
+            throw new ResourceNotFoundException(
+                    RestMessages.NOCONTAINER.toString());
         }
 
         Map<Edge, Set<Property>> topo = topologyManager.getEdges();
         if (topo != null) {
             List<EdgeProperties> res = new ArrayList<EdgeProperties>();
             for (Map.Entry<Edge, Set<Property>> entry : topo.entrySet()) {
-                EdgeProperties el = new EdgeProperties(entry.getKey(), entry.getValue());
+                EdgeProperties el = new EdgeProperties(entry.getKey(),
+                        entry.getValue());
                 res.add(el);
             }
             return new Topology(res);
@@ -96,100 +118,127 @@ public class TopologyNorthboundJAXRS {
     }
 
     /**
-    * Retrieve the user configured links 
-    *
-    * @param containerName The container for which we want to retrieve the user links
-    *
-    * @return A List of user configured links
-    */
-   @Path("/{containerName}/userLink")
-   @GET
-   @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-   @TypeHint(TopologyUserLinks.class)
-   @StatusCodes( { @ResponseCode(code = 404, condition = "The Container Name passed was not found") })
-   public TopologyUserLinks getUserLinks(
-           @PathParam("containerName") String containerName) {
-       ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
-               .getInstance(ITopologyManager.class, containerName, this);
-       if (topologyManager == null) {
-           throw new ResourceNotFoundException(RestMessages.NOCONTAINER
-                   .toString());
-       }
-
-       ConcurrentMap<String, TopologyUserLinkConfig> userLinks = topologyManager.getUserLinks();
-       if ((userLinks != null) && (userLinks.values() != null)) {
-          List<TopologyUserLinkConfig> res = new ArrayList<TopologyUserLinkConfig>(userLinks.values());
-           return new TopologyUserLinks(res);
-       }
-
-       return null;
-   }
-   
-   /**
-    * Add an User Link
-    *
-    * @param containerName Name of the Container. The base Container is "default".
-    * @param TopologyUserLinkConfig in JSON or XML format
-    * @return Response as dictated by the HTTP Response Status code
-    */
-
-   @Path("/{containerName}/userLink")
-   @POST
-   @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-   @StatusCodes( {
-           @ResponseCode(code = 201, condition = "User Link added successfully"),
-           @ResponseCode(code = 404, condition = "The Container Name passed was not found"),
-           @ResponseCode(code = 409, condition = "Failed to add User Link due to Conflicting Name"),
-           @ResponseCode(code = 500, condition = "Failed to add User Link. Failure Reason included in HTTP Error response"),
-           @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
-   public Response addUserLink(
-           @PathParam(value = "containerName") String containerName,
-           @TypeHint(TopologyUserLinkConfig.class) JAXBElement<TopologyUserLinkConfig> userLinkConfig) {
-
-               ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
-                               .getInstance(ITopologyManager.class, containerName, this);
-               if (topologyManager == null) {
-                       throw new ResourceNotFoundException(RestMessages.NOCONTAINER
-                                       .toString());
-               }
-
-               Status status = topologyManager.addUserLink(userLinkConfig.getValue());
-               if (status.isSuccess()) {
-                       return Response.status(Response.Status.CREATED).build();
-               }
-               throw new InternalServerErrorException(status.getDescription());
-   }
-
-   /**
-    * Delete an User Link
-    *
-    * @param containerName Name of the Container. The base Container is "default".
-    * @param name Name of the Link Configuration
-    * @return Response as dictated by the HTTP Response Status code
-    */
-
-   @Path("/{containerName}/userLink/{name}")
-   @DELETE
-   @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-   @StatusCodes( {
-              @ResponseCode(code = 200, condition = "Operation successful"),
-           @ResponseCode(code = 404, condition = "The Container Name or Link Configuration Name was not found"),
-           @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
-   public Response deleteUserLink(
-                  @PathParam("containerName") String containerName,
-           @PathParam("name") String name) {
-
-               ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
-                               .getInstance(ITopologyManager.class, containerName, this);
-          if (topologyManager == null) {
-                  throw new ResourceNotFoundException(RestMessages.NOCONTAINER
-                                  .toString());
-          }
-
-       Status ret = topologyManager.deleteUserLink(name);
-       if (ret.isSuccess()) {
-           return Response.ok().build();
-       }
-       throw new ResourceNotFoundException(ret.getDescription());
-   }
+     * Retrieve the user configured links
+     * 
+     * @param containerName
+     *            The container for which we want to retrieve the user links
+     * 
+     * @return A List of user configured links
+     */
+    @Path("/{containerName}/userLink")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(TopologyUserLinks.class)
+    @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name passed was not found") })
+    public TopologyUserLinks getUserLinks(
+            @PathParam("containerName") String containerName) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+        ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
+                .getInstance(ITopologyManager.class, containerName, this);
+        if (topologyManager == null) {
+            throw new ResourceNotFoundException(
+                    RestMessages.NOCONTAINER.toString());
+        }
+
+        ConcurrentMap<String, TopologyUserLinkConfig> userLinks = topologyManager
+                .getUserLinks();
+        if ((userLinks != null) && (userLinks.values() != null)) {
+            List<TopologyUserLinkConfig> res = new ArrayList<TopologyUserLinkConfig>(
+                    userLinks.values());
+            return new TopologyUserLinks(res);
+        }
+
+        return null;
+    }
+
+    /**
+     * Add an User Link
+     * 
+     * @param containerName
+     *            Name of the Container. The base Container is "default".
+     * @param TopologyUserLinkConfig
+     *            in JSON or XML format
+     * @return Response as dictated by the HTTP Response Status code
+     */
+
+    @Path("/{containerName}/userLink")
+    @POST
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "User Link added successfully"),
+            @ResponseCode(code = 404, condition = "The Container Name passed was not found"),
+            @ResponseCode(code = 409, condition = "Failed to add User Link due to Conflicting Name"),
+            @ResponseCode(code = 500, condition = "Failed to add User Link. Failure Reason included in HTTP Error response"),
+            @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
+    public Response addUserLink(
+            @PathParam(value = "containerName") String containerName,
+            @TypeHint(TopologyUserLinkConfig.class) JAXBElement<TopologyUserLinkConfig> userLinkConfig) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+        ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
+                .getInstance(ITopologyManager.class, containerName, this);
+        if (topologyManager == null) {
+            throw new ResourceNotFoundException(
+                    RestMessages.NOCONTAINER.toString());
+        }
+
+        Status status = topologyManager.addUserLink(userLinkConfig.getValue());
+        if (status.isSuccess()) {
+            return Response.status(Response.Status.CREATED).build();
+        }
+        throw new InternalServerErrorException(status.getDescription());
+    }
+
+    /**
+     * Delete an User Link
+     * 
+     * @param containerName
+     *            Name of the Container. The base Container is "default".
+     * @param name
+     *            Name of the Link Configuration
+     * @return Response as dictated by the HTTP Response Status code
+     */
+
+    @Path("/{containerName}/userLink/{name}")
+    @DELETE
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The Container Name or Link Configuration Name was not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
+    public Response deleteUserLink(
+            @PathParam("containerName") String containerName,
+            @PathParam("name") String name) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+        ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
+                .getInstance(ITopologyManager.class, containerName, this);
+        if (topologyManager == null) {
+            throw new ResourceNotFoundException(
+                    RestMessages.NOCONTAINER.toString());
+        }
+
+        Status ret = topologyManager.deleteUserLink(name);
+        if (ret.isSuccess()) {
+            return Response.ok().build();
+        }
+        throw new ResourceNotFoundException(ret.getDescription());
+    }
+
 }