Merge "Log all configuration(add/modify/delete) changes to a new log file audit.log...
authorGiovanni Meo <gmeo@cisco.com>
Wed, 14 Aug 2013 12:58:00 +0000 (12:58 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 14 Aug 2013 12:58:00 +0000 (12:58 +0000)
12 files changed:
opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml
opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/utils/NorthboundUtils.java
opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthbound.java
opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java
opendaylight/northbound/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/northbound/StaticRoutingNorthbound.java
opendaylight/northbound/subnets/src/main/java/org/opendaylight/controller/subnets/northbound/SubnetsNorthboundJAXRS.java
opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthbound.java
opendaylight/northbound/topology/src/main/java/org/opendaylight/controller/topology/northbound/TopologyNorthboundJAXRS.java
opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/Devices.java
opendaylight/web/flows/src/main/java/org/opendaylight/controller/flows/web/Flows.java
opendaylight/web/root/src/main/java/org/opendaylight/controller/web/DaylightWebAdmin.java
opendaylight/web/root/src/main/java/org/opendaylight/controller/web/DaylightWebUtil.java

index 08dabdeedbd8ea99bebe3f647a4bfdadbed649fc..de0a3bcd19e990c0287338d0b5e3b1fbe8696c1b 100644 (file)
@@ -1,4 +1,4 @@
-<configuration scan="true">
+ <configuration scan="true">
 
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
     <encoder>
       <maxHistory>1</maxHistory>
     </rollingPolicy>
 
+    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+      <maxFileSize>10MB</maxFileSize>
+    </triggeringPolicy>
+
     <encoder>
       <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{35} - %msg%n</pattern>
     </encoder>
   </appender>
-
+  <appender name="audit-file" class="ch.qos.logback.core.FileAppender">
+        <file>logs/audit.log</file>
+        <append>true</append>
+        <encoder>
+            <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} %msg %n</pattern>
+        </encoder>
+  </appender>
   <root level="error">
     <appender-ref ref="STDOUT" />
     <appender-ref ref="opendaylight.log" />
   </root>
 
   <!--  Base log level  -->
-  <logger name="org.opendaylight" level="INFO"/>
+  <logger name="org.opendaylight.controller" level="INFO"/>
 
   <!-- OSGi logging bridge -->
   <logger name="org.opendaylight.controller.logging.bridge" level="WARN"/>
@@ -55,4 +65,8 @@
   <logger name="org.opendaylight.controller.usermanager" level="INFO"/>
   <!-- Web modules -->
   <logger name="org.opendaylight.controller.web" level="INFO"/>
-</configuration>
+  <!-- additivity=false ensures analytics data only goes to the analytics log -->
+  <logger name="audit" level="INFO" additivity="false">
+       <appender-ref ref="audit-file"/>
+  </logger>
+</configuration>
\ No newline at end of file
index f98189319becc8ccae7557a7028378f38843b72e..9f47e0c9718f542f49d6bea3079045c482359230 100644 (file)
@@ -13,6 +13,8 @@ import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
 import org.opendaylight.controller.usermanager.IUserManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class NorthboundUtils {
 
@@ -37,6 +39,10 @@ public class NorthboundUtils {
         }
     };
 
+    private static final String AUDIT = "audit";
+
+    private static final Logger logger = LoggerFactory.getLogger(AUDIT);
+
     // Suppress default constructor for noninstantiability
     private NorthboundUtils() {
     }
@@ -114,4 +120,20 @@ public class NorthboundUtils {
         return true;
     }
 
+    public static void auditlog(String moduleName, String user, String action, String resource,
+            String containerName) {
+        String auditMsg = "";
+        String mode = "REST";
+        if (containerName != null) {
+            auditMsg = "Mode: " + mode + " User " + user + " "  + action + " " + moduleName + " " + resource + " in container "
+                    + containerName;
+        } else {
+            auditMsg = "Mode: " + mode + " User " + user + " "  + action + " " + moduleName + " " + resource;
+        }
+        logger.info(auditMsg);
+    }
+
+    public static void auditlog(String moduleName, String user, String action, String resource) {
+        auditlog(moduleName, user, action, resource, null);
+    }
 }
index d3cbc4aceed0ad88a887d3a870a7d184b35a85df..6bccc2d2e9ff25bde94925be51f4555f409c5e98 100644 (file)
@@ -322,7 +322,9 @@ public class FlowProgrammerNorthbound {
         }
 
         Status status = frm.addStaticFlow(flowConfig.getValue());
+
         if (status.isSuccess()) {
+            NorthboundUtils.auditlog("Flow", username, "added", name, containerName);
             return Response.status(Response.Status.CREATED).build();
         }
         throw new InternalServerErrorException(status.getDescription());
@@ -385,6 +387,7 @@ public class FlowProgrammerNorthbound {
 
         Status status = frm.removeStaticFlow(name, node);
         if (status.isSuccess()) {
+            NorthboundUtils.auditlog("Flow", username, "removed", name, containerName);
             return Response.ok().build();
         }
         throw new InternalServerErrorException(status.getDescription());
@@ -446,6 +449,7 @@ public class FlowProgrammerNorthbound {
 
         Status status = frm.toggleStaticFlowStatus(staticFlow);
         if (status.isSuccess()) {
+            NorthboundUtils.auditlog("Flow", username, "toggled", name, containerName);
             return Response.ok().build();
         }
         throw new InternalServerErrorException(status.getDescription());
index 642c5ccbaa9db016aad4e68c99eff7087081cdd3..285967522caa4d99c85515f4a491eafec66f23b8 100644 (file)
@@ -310,6 +310,7 @@ public class HostTrackerNorthbound {
         Status status = hostTracker.addStaticHost(networkAddress,
                 dataLayerAddress, nc, vlan);
         if (status.isSuccess()) {
+            NorthboundUtils.auditlog("Static Host", username, "added", networkAddress, containerName);
             return Response.status(Response.Status.CREATED).build();
         } else if (status.getCode().equals(StatusCode.BADREQUEST)) {
             throw new UnsupportedMediaTypeException(status.getDescription());
@@ -364,6 +365,7 @@ public class HostTrackerNorthbound {
 
         Status status = hostTracker.removeStaticHost(networkAddress);
         if (status.isSuccess()) {
+            NorthboundUtils.auditlog("Static Host", username, "removed", networkAddress, containerName);
             return Response.ok().build();
         }
         throw new InternalServerErrorException(status.getDescription());
index b85f5641c73ea9af99fd3b201909220367c8240b..3deb8dfa7b59766fab862b6151e3b2f00e4fc6d3 100644 (file)
@@ -58,8 +58,7 @@ import org.opendaylight.controller.sal.utils.Status;
 @Path("/")
 public class StaticRoutingNorthbound {
 
-
-        private String username;
+    private String username;
 
     @Context
     public void setSecurityContext(SecurityContext context) {
@@ -197,6 +196,7 @@ public class StaticRoutingNorthbound {
                 sRoute.getPrefix(), sRoute.getNextHop());
         Status response = staticRouting.addStaticRoute(cfgObject);
         if (response.isSuccess()) {
+            NorthboundUtils.auditlog("Static Route", username, "added", name, containerName);
             return Response.status(Response.Status.CREATED).build();
         }
         throw new ResourceConflictException(response.getDescription());
@@ -241,6 +241,7 @@ public class StaticRoutingNorthbound {
 
         Status status = staticRouting.removeStaticRoute(name);
         if (status.isSuccess()) {
+            NorthboundUtils.auditlog("Static Route", username, "removed", name, containerName);
             return Response.ok().build();
         }
         throw new ResourceNotFoundException(status.getDescription());
index 17780fc70db079034f7111c47cf420368f82edd7..8c555f26738536c95eed13580d609fd240e9032c 100644 (file)
@@ -160,6 +160,7 @@ public class SubnetsNorthboundJAXRS {
         SubnetConfig cfgObject = new SubnetConfig(subnetName, subnet, new HashSet<String>(0));
         Status status = switchManager.addSubnet(cfgObject);
         if (status.isSuccess()) {
+            NorthboundUtils.auditlog("Subnet Gateway", username, "added", subnetName, containerName);
             return Response.status(Response.Status.CREATED).build();
         }
         throw new InternalServerErrorException(status.getDescription());
@@ -198,6 +199,7 @@ public class SubnetsNorthboundJAXRS {
         }
         Status status = switchManager.removeSubnet(subnetName);
         if (status.isSuccess()) {
+            NorthboundUtils.auditlog("Subnet Gateway", username, "removed", subnetName, containerName);
             return Response.status(Response.Status.OK).build();
         }
         throw new InternalServerErrorException(status.getDescription());
@@ -274,6 +276,9 @@ public class SubnetsNorthboundJAXRS {
             for (String s : newPorts) {
                 Status st = switchManager.addPortsToSubnet(name, s);
                 successful = successful && st.isSuccess();
+                if(successful){
+                    NorthboundUtils.auditlog("Subnet Gateway", username, "added", s +" to "+name, containerName);
+                }
             }
         }
 
@@ -393,6 +398,9 @@ public class SubnetsNorthboundJAXRS {
                 for (String port : ports) {
                     st = switchManager.addPortsToSubnet(name, port);
                     successful = successful && st.isSuccess();
+                    if(successful){
+                        NorthboundUtils.auditlog("Subnet Gateway", username, "added",  st +" to "+name, containerName);
+                    }
                 }
             } else if (action.equals("delete")) {
                 // delete existing ports
@@ -400,6 +408,9 @@ public class SubnetsNorthboundJAXRS {
                 for (String port : ports) {
                     st = switchManager.removePortsFromSubnet(name, port);
                     successful = successful && st.isSuccess();
+                    if(successful){
+                        NorthboundUtils.auditlog("Subnet Gateway", username, "removed",  st +" from "+name, containerName);
+                    }
                 }
             } else {
                 return Response.status(Response.Status.BAD_REQUEST).build();
index d6d9be9e9fbc7cc5baa43f9376019e6d9f7ce1e2..e67d1b75686934b48fb15cb409bf0cdf5cd3d123 100644 (file)
@@ -303,6 +303,9 @@ public class SwitchNorthbound {
                 nodeProperties.remove(propertyName.toLowerCase());
                 SwitchConfig newSwitchConfig = new SwitchConfig(node.toString(), nodeProperties);
                 status = switchManager.updateNodeConfig(newSwitchConfig);
+                if(status.isSuccess()){
+                    NorthboundUtils.auditlog("Static Route", username, "updated", nodeId, containerName);
+                }
             }
         }
         return NorthboundUtils.getResponse(status);
@@ -519,6 +522,7 @@ public class SwitchNorthbound {
                 .fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
         Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
         if (ret.isSuccess()) {
+            NorthboundUtils.auditlog("Node Connector Property", username, "removed", nc + " from " + nodeConnectorId, containerName);
             return Response.ok().build();
         }
         throw new ResourceNotFoundException(ret.getDescription());
index 323e2d2211deaa916ce5b81257bde2074592aa65..fb4e8229ff48fd87dd8e6195ee272d497bfbd095 100644 (file)
@@ -195,6 +195,7 @@ public class TopologyNorthboundJAXRS {
 
         Status status = topologyManager.addUserLink(userLinkConfig.getValue());
         if (status.isSuccess()) {
+            NorthboundUtils.auditlog("User Link", username, "added", userLinkConfig.getValue().getName(), containerName);
             return Response.status(Response.Status.CREATED).build();
         }
         throw new InternalServerErrorException(status.getDescription());
@@ -236,6 +237,7 @@ public class TopologyNorthboundJAXRS {
 
         Status ret = topologyManager.deleteUserLink(name);
         if (ret.isSuccess()) {
+            NorthboundUtils.auditlog("User Link", username, "removed", name, containerName);
             return Response.ok().build();
         }
         throw new ResourceNotFoundException(ret.getDescription());
index f92e92ec17ea6a2a9ffc515f495855aaa2aac36e..15ad9e9887d8eb2aba1250bc278a48f7441db00a 100644 (file)
@@ -256,6 +256,7 @@ public class Devices implements IDaylightWeb {
             } else {
                 resultBean.setStatus(true);
                 resultBean.setMessage("Updated node information successfully");
+                DaylightWebUtil.auditlog("Node", userName, "updated", nodeId + " to "+ nodeName, containerName);
             }
         } catch (Exception e) {
             resultBean.setStatus(false);
@@ -338,6 +339,7 @@ public class Devices implements IDaylightWeb {
             if (addStaticRouteResult.isSuccess()) {
                 result.setStatus(true);
                 result.setMessage("Static Route saved successfully");
+                DaylightWebUtil.auditlog("Static Route", userName, "added", routeName, containerName);
             } else {
                 result.setStatus(false);
                 result.setMessage(addStaticRouteResult.getDescription());
@@ -381,6 +383,7 @@ public class Devices implements IDaylightWeb {
                     resultBean.setMessage(result.getDescription());
                     break;
                 }
+                DaylightWebUtil.auditlog("Static Route", userName, "removed", route, containerName);
             }
         } catch (Exception e) {
             resultBean.setStatus(false);
@@ -451,6 +454,7 @@ public class Devices implements IDaylightWeb {
             if (result.isSuccess()) {
                 resultBean.setStatus(true);
                 resultBean.setMessage("Added gateway address successfully");
+                DaylightWebUtil.auditlog("Subnet Gateway", userName, "added", gatewayName, containerName);
             } else {
                 resultBean.setStatus(false);
                 resultBean.setMessage(result.getDescription());
@@ -491,6 +495,7 @@ public class Devices implements IDaylightWeb {
                     resultBean.setMessage(result.getDescription());
                     break;
                 }
+                DaylightWebUtil.auditlog("Subnet Gateway", userName, "removed", subnet, containerName);
             }
         } catch (Exception e) {
             resultBean.setStatus(false);
@@ -526,6 +531,7 @@ public class Devices implements IDaylightWeb {
                 resultBean.setStatus(true);
                 resultBean
                         .setMessage("Added ports to subnet gateway address successfully");
+                DaylightWebUtil.auditlog("Ports to Subnet Gateway", userName, "added",nodeId+"/"+ ports, containerName);
             } else {
                 resultBean.setStatus(false);
                 resultBean.setMessage(result.getDescription());
@@ -564,6 +570,7 @@ public class Devices implements IDaylightWeb {
                 resultBean.setStatus(true);
                 resultBean
                         .setMessage("Deleted port from subnet gateway address successfully");
+                DaylightWebUtil.auditlog("Ports from Subnet Gateway", userName, "removed", nodePort, containerName);
             } else {
                 resultBean.setStatus(false);
                 resultBean.setMessage(result.getDescription());
@@ -695,6 +702,7 @@ public class Devices implements IDaylightWeb {
             if (result.isSuccess()) {
                 resultBean.setStatus(true);
                 resultBean.setMessage("SPAN Port added successfully");
+                DaylightWebUtil.auditlog("SPAN Port", userName, "added", cfgObject.getNodeId(), containerName);
             } else {
                 resultBean.setStatus(false);
                 resultBean.setMessage(result.getDescription());
@@ -740,6 +748,7 @@ public class Devices implements IDaylightWeb {
                         resultBean.setMessage(result.getDescription());
                         break;
                     }
+                    DaylightWebUtil.auditlog("SPAN Port", userName, "removed", cfgObject.getNodeId(), containerName);
                 }
             }
         } catch (Exception e) {
index 4396c957bf86f96f37c8784967bc4b605f2196a7..9444360eecb7d7ae4a6e084a4fde8512c7b5ed71 100644 (file)
@@ -47,6 +47,7 @@ import com.google.gson.Gson;
 public class Flows implements IDaylightWeb {
     private static final UserLevel AUTH_LEVEL = UserLevel.CONTAINERUSER;
     private static final String WEB_NAME = "Flows";
+
     private static final String WEB_ID = "flows";
     private static final short WEB_ORDER = 2;
 
@@ -237,6 +238,7 @@ public class Flows implements IDaylightWeb {
         Status result = new Status(StatusCode.BADREQUEST, "Invalid request");
         if (action.equals("add")) {
             result = frm.addStaticFlow(flow);
+            DaylightWebUtil.auditlog("Flow", userName, "added", flow.getName(), containerName);
         }
 
         return (result.isSuccess()) ? StatusCode.SUCCESS.toString() : result
@@ -270,8 +272,14 @@ public class Flows implements IDaylightWeb {
         }
         if (action.equals("remove")) {
             result = frm.removeStaticFlow(name, node);
+            if(result.isSuccess()) {
+                DaylightWebUtil.auditlog("Flow", userName, "removed", name, containerName);
+            }
         } else if (action.equals("toggle")) {
             result = frm.toggleStaticFlowStatus(name, node);
+            if(result.isSuccess()) {
+                DaylightWebUtil.auditlog("Flow", userName, "toggled", name, containerName);
+            }
         } else {
             result = new Status(StatusCode.BADREQUEST, "Unknown action");
         }
index ba2075ddb6a50c198e4d3fbb4d38369391c4fa13..524cb62b3a2175d24596f4b5727a5d7a57310005 100644 (file)
@@ -30,6 +30,9 @@ import com.google.gson.Gson;
 @Controller
 @RequestMapping("/admin")
 public class DaylightWebAdmin {
+
+
+
     @RequestMapping("/users")
     @ResponseBody
     public List<UserConfig> getUsers() {
@@ -69,7 +72,11 @@ public class DaylightWebAdmin {
 
         Status result = (action.equals("add")) ? userManager
                 .addLocalUser(config) : userManager.removeLocalUser(config);
-
+        if(result.getCode().equals(StatusCode.SUCCESS)) {
+            String userAction=(action.equals("add")) ? "added":"removed";
+            DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), userAction, config.getUser());
+            return "Success";
+        }
         return result.getDescription();
     }
 
@@ -93,7 +100,12 @@ public class DaylightWebAdmin {
             return "Operation not permitted";
         }
 
-        return userManager.removeLocalUser(userName).getDescription();
+        Status result = userManager.removeLocalUser(userName);
+        if(result.getCode().equals(StatusCode.SUCCESS)) {
+            DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", userName);
+            return "Success";
+        }
+        return result.getDescription();
     }
 
     @RequestMapping(value = "/users/password/{username}", method = RequestMethod.POST)
@@ -115,7 +127,9 @@ public class DaylightWebAdmin {
         }
 
         Status status = userManager.changeLocalUserPassword(username, currentPassword, newPassword);
-
+        if(status.isSuccess()){
+            DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "changed password for", username);
+        }
         return status;
     }
 
index ab2abe9c9ed136e32d15d5c3f992dde5cd4d9b8e..3add0e6a40b22d0745421d7f0d4db46a82babbfa 100644 (file)
@@ -5,9 +5,14 @@ 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.usermanager.IUserManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class DaylightWebUtil {
 
+    private static final String AUDIT = "audit";
+    private static final Logger logger = LoggerFactory.getLogger(AUDIT);
+
     /**
      * Returns the access privilege the user has on the specified container
      *
@@ -52,4 +57,21 @@ public class DaylightWebUtil {
 
         return Privilege.NONE;
     }
+
+    public static void auditlog(String moduleName, String user, String action, String resource,
+            String containerName) {
+        String auditMsg = "";
+        String mode = "WEB";
+        if (containerName != null) {
+            auditMsg = "Mode: " + mode + " User " + user + " "  + action + " " + moduleName + " " + resource + " in container "
+                    + containerName;
+        } else {
+            auditMsg = "Mode: " + mode + " User " + user + " "  + action + " " + moduleName + " " + resource;
+        }
+        logger.info(auditMsg);
+    }
+
+    public static void auditlog(String moduleName, String user, String action, String resource) {
+        auditlog(moduleName, user, action, resource, null);
+    }
 }
\ No newline at end of file