Merge "Fixed deserialization of IdentityRefs in Restconf URI."
[controller.git] / opendaylight / web / root / src / main / java / org / opendaylight / controller / web / DaylightWebAdmin.java
index ba2075ddb6a50c198e4d3fbb4d38369391c4fa13..4c8a6b8439f2b18482a848605e1f5e234a27f8cd 100644 (file)
@@ -8,14 +8,25 @@
 
 package org.opendaylight.controller.web;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.connectionmanager.IConnectionManager;
 import org.opendaylight.controller.sal.authorization.UserLevel;
+import org.opendaylight.controller.sal.core.Description;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
 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.switchmanager.ISwitchManager;
 import org.opendaylight.controller.usermanager.IUserManager;
 import org.opendaylight.controller.usermanager.UserConfig;
 import org.springframework.stereotype.Controller;
@@ -30,18 +41,124 @@ import com.google.gson.Gson;
 @Controller
 @RequestMapping("/admin")
 public class DaylightWebAdmin {
-    @RequestMapping("/users")
+    Gson gson = new Gson();
+
+    /**
+     * Returns list of clustered controllers. Highlights "this" controller and
+     * if controller is coordinator
+     *
+     * @return List<ClusterBean>
+     */
+    @RequestMapping("/cluster")
+    @ResponseBody
+    public String getClusteredControllers() {
+        IClusterGlobalServices clusterServices = (IClusterGlobalServices) ServiceHelper.getGlobalInstance(
+                IClusterGlobalServices.class, this);
+        if (clusterServices == null) {
+            return null;
+        }
+        IConnectionManager connectionManager = (IConnectionManager) ServiceHelper.getGlobalInstance(
+                IConnectionManager.class, this);
+        if (connectionManager == null) {
+            return null;
+        }
+
+        List<ClusterNodeBean> clusterNodes = new ArrayList<ClusterNodeBean>();
+
+        List<InetAddress> controllers = clusterServices.getClusteredControllers();
+        for (InetAddress controller : controllers) {
+            ClusterNodeBean.Builder clusterBeanBuilder = new ClusterNodeBean.Builder(controller);
+
+            // get number of connected nodes
+            Set<Node> connectedNodes = connectionManager.getNodes(controller);
+            int numNodes = connectedNodes == null ? 0 : connectedNodes.size();
+            clusterBeanBuilder.nodesConnected(numNodes);
+
+            // determine if this is the executing controller
+            if (controller.equals(clusterServices.getMyAddress())) {
+                clusterBeanBuilder.highlightMe();
+            }
+
+            // determine whether this is coordinator
+            if (clusterServices.getCoordinatorAddress().equals(controller)) {
+                clusterBeanBuilder.iAmCoordinator();
+            }
+            clusterNodes.add(clusterBeanBuilder.build());
+        }
+
+        return gson.toJson(clusterNodes);
+    }
+
+    /**
+     * Return nodes connected to controller {controller}
+     *
+     * @param controller
+     *            - byte[] of the address of the controller
+     * @return List<NodeBean>
+     */
+    @RequestMapping("/cluster/controller/{controller}")
+    @ResponseBody
+    public String getNodesConnectedToController(@PathVariable("controller") String controller) {
+        IClusterGlobalServices clusterServices = (IClusterGlobalServices) ServiceHelper.getGlobalInstance(
+                IClusterGlobalServices.class, this);
+        if (clusterServices == null) {
+            return null;
+        }
+        IConnectionManager connectionManager = (IConnectionManager) ServiceHelper.getGlobalInstance(
+                IConnectionManager.class, this);
+        if (connectionManager == null) {
+            return null;
+        }
+        ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class,
+                GlobalConstants.DEFAULT.toString(), this);
+        if (switchManager == null) {
+            return null;
+        }
+
+        byte[] address = gson.fromJson(controller, byte[].class);
+        InetAddress controllerAddress = null;
+        try {
+            controllerAddress = InetAddress.getByAddress(address);
+        } catch (UnknownHostException e) {
+            return null;
+        }
+
+        List<NodeBean> result = new ArrayList<NodeBean>();
+
+        Set<Node> nodes = connectionManager.getNodes(controllerAddress);
+        if (nodes == null) {
+            return gson.toJson(result);
+        }
+        for (Node node : nodes) {
+            Description description = (Description) switchManager.getNodeProp(node, Description.propertyName);
+            NodeBean nodeBean;
+            if (description == null || description.getValue().equals("None")) {
+                nodeBean = new NodeBean(node);
+            } else {
+                nodeBean = new NodeBean(node, description.getValue());
+            }
+            result.add(nodeBean);
+        }
+
+        return gson.toJson(result);
+    }
+
+    @RequestMapping(value = "/users", method = RequestMethod.GET)
     @ResponseBody
-    public List<UserConfig> getUsers() {
-        IUserManager userManager = (IUserManager) ServiceHelper
-                .getGlobalInstance(IUserManager.class, this);
+    public List<UserBean> getUsers() {
+        IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
         if (userManager == null) {
             return null;
         }
 
-        List<UserConfig> userConfList = userManager.getLocalUserList();
+        List<UserBean> result = new ArrayList<UserBean>();
+        List<UserConfig> configs = userManager.getLocalUserList();
+        for (UserConfig config : configs) {
+            UserBean bean = new UserBean(config);
+            result.add(bean);
+        }
 
-        return userConfList;
+        return result;
     }
 
     /*
@@ -49,73 +166,169 @@ public class DaylightWebAdmin {
      */
     @RequestMapping(value = "/users", method = RequestMethod.POST)
     @ResponseBody
-    public String saveLocalUserConfig(
-            @RequestParam(required = true) String json,
-            @RequestParam(required = true) String action,
-            HttpServletRequest request) {
+    public Status saveLocalUserConfig(@RequestParam(required = true) String json,
+            @RequestParam(required = true) String action, HttpServletRequest request) {
 
-        IUserManager userManager = (IUserManager) ServiceHelper
-                .getGlobalInstance(IUserManager.class, this);
+        IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
         if (userManager == null) {
-            return "Internal Error";
+            return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
         }
 
         if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
-            return "Operation not permitted";
+            return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
         }
 
         Gson gson = new Gson();
-        UserConfig config = gson.fromJson(json, UserConfig.class);
+        UserConfig plainConfig = gson.fromJson(json, UserConfig.class);
+        // Recreate using the proper constructor which will hash the password
+        UserConfig config = new UserConfig(plainConfig.getUser(), plainConfig.getPassword(), plainConfig.getRoles());
+
+        Status result = (action.equals("add")) ? userManager.addLocalUser(config) : userManager.removeLocalUser(config);
+        if (result.isSuccess()) {
+            if (action.equals("add")) {
+                DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "added", config.getUser()
+                        + " as " + config.getRoles().toString());
+            } else {
+                DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", config.getUser());
+            }
+        }
+        return result;
+    }
+
+    @RequestMapping(value = "/user/modify", method = RequestMethod.POST)
+    @ResponseBody
+    public Status modifyUser(@RequestParam(required = true) String json,
+            @RequestParam(required = true) String action, HttpServletRequest request) {
+
+        IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
+        if (userManager == null) {
+            return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
+        }
+
+        if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
+            return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
+        }
+
+        UserConfig newConfig = gson.fromJson(json, UserConfig.class);
+        List<UserConfig> currentUserConfig = userManager.getLocalUserList();
+        String password = null;
+        String user = newConfig.getUser();
+        for (UserConfig userConfig : currentUserConfig) {
+            if(userConfig.getUser().equals(user)){
+                password = userConfig.getPassword();
+                break;
+            }
+        }
+        if (password == null) {
+            String msg = String.format("User %s not found in configuration database", user);
+            return new Status(StatusCode.NOTFOUND, msg);
+        }
 
-        Status result = (action.equals("add")) ? userManager
-                .addLocalUser(config) : userManager.removeLocalUser(config);
+        //While modifying a user role, the password is not provided from GUI for any user.
+        //The password is stored in hash mode, hence it cannot be retrieved and added to UserConfig object
+        //The hashed password is injected below to the json string containing username and new roles before
+        //converting to UserConfig object.
+        json = json.replace("\"roles\"", "\"password\":\""+ password + "\",\"roles\"");
+        Gson gson = new Gson();
+        newConfig = gson.fromJson(json, UserConfig.class);
 
-        return result.getDescription();
+        Status result = userManager.modifyLocalUser(newConfig);
+        if (result.isSuccess()) {
+            DaylightWebUtil.auditlog("Roles of", request.getUserPrincipal().getName(), "updated", newConfig.getUser()
+                    + " to " + newConfig.getRoles().toString());
+        }
+        return result;
     }
 
+
     @RequestMapping(value = "/users/{username}", method = RequestMethod.POST)
     @ResponseBody
-    public String removeLocalUser(@PathVariable("username") String userName,
-            HttpServletRequest request) {
+    public Status removeLocalUser(@PathVariable("username") String userName, HttpServletRequest request) {
 
-        String username = request.getUserPrincipal().getName();
-        if (username.equals(userName)) {
-            return "Invalid Request: User cannot delete itself";
+        String loggedInUser = request.getUserPrincipal().getName();
+        if (loggedInUser.equals(userName)) {
+            String msg = "Invalid Request: User cannot delete itself";
+            return new Status(StatusCode.NOTALLOWED, msg);
         }
 
-        IUserManager userManager = (IUserManager) ServiceHelper
-                .getGlobalInstance(IUserManager.class, this);
+        IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
         if (userManager == null) {
-            return "Internal Error";
+            return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
         }
 
         if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
-            return "Operation not permitted";
+            return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
         }
 
-        return userManager.removeLocalUser(userName).getDescription();
+        Status status = userManager.removeLocalUser(userName);
+        if (status.isSuccess()) {
+            DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", userName);
+            return status;
+        }
+        return status;
     }
 
     @RequestMapping(value = "/users/password/{username}", method = RequestMethod.POST)
     @ResponseBody
-    public Status changePassword(@PathVariable("username") String username, HttpServletRequest request,
-            @RequestParam("currentPassword") String currentPassword, @RequestParam("newPassword") String newPassword) {
-        IUserManager userManager = (IUserManager) ServiceHelper
-                .getGlobalInstance(IUserManager.class, this);
+    public Status changePassword(
+            @PathVariable("username") String username, HttpServletRequest request,
+            @RequestParam(value = "currentPassword", required=false) String currentPassword,
+            @RequestParam("newPassword") String newPassword) {
+        IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
         if (userManager == null) {
-            return new Status(StatusCode.GONE, "User Manager not found");
+            return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
         }
 
-        if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
-            return new Status(StatusCode.FORBIDDEN, "Operation not permitted");
-        }
+        Status status;
+        String requestingUser = request.getUserPrincipal().getName();
 
-        if (newPassword.isEmpty()) {
-            return new Status(StatusCode.BADREQUEST, "Empty passwords not allowed");
-        }
+        //changing own password
+        if (requestingUser.equals(username) ) {
+            status = userManager.changeLocalUserPassword(username, currentPassword, newPassword);
+            //enforce the user to re-login with new password
+            if (status.isSuccess() && !newPassword.equals(currentPassword)) {
+                userManager.userLogout(username);
+                HttpSession session = request.getSession(false);
+                if ( session != null) {
+                    session.invalidate();
+                }
+            }
+
+        //admin level user resetting other's password
+        } else if (authorize(userManager, UserLevel.NETWORKADMIN, request)) {
+
+            //Since User Manager doesn't have an unprotected password change API,
+            //we re-create the user with the new password (and current roles).
+            List<String> roles = userManager.getUserRoles(username);
+            UserConfig newConfig = new UserConfig(username, newPassword, roles);
 
-        Status status = userManager.changeLocalUserPassword(username, currentPassword, newPassword);
+            //validate before removing existing config, so we don't remove but fail to add
+            status = newConfig.validate();
+            if (!status.isSuccess()) {
+                return status;
+            }
 
+            userManager.userLogout(username);
+            status = userManager.removeLocalUser(username);
+            if (!status.isSuccess()) {
+                return status;
+            }
+            if (userManager.addLocalUser(newConfig).isSuccess()) {
+                status = new Status(StatusCode.SUCCESS, "Password for user " + username + " reset successfully.");
+            } else {
+                //unexpected
+                status = new Status(StatusCode.INTERNALERROR, "Failed resetting password for user " + username + ". User is now removed.");
+            }
+
+        //unauthorized
+        } else {
+            status = new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
+        }
+
+        if (status.isSuccess()) {
+            DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "changed password for",
+                    username);
+        }
         return status;
     }
 
@@ -124,8 +337,7 @@ public class DaylightWebAdmin {
      *
      * @param level
      */
-    private boolean authorize(IUserManager userManager, UserLevel level,
-            HttpServletRequest request) {
+    private boolean authorize(IUserManager userManager, UserLevel level, HttpServletRequest request) {
         String username = request.getUserPrincipal().getName();
         UserLevel userLevel = userManager.getUserLevel(username);
         return userLevel.toNumber() <= level.toNumber();