2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.web;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.ArrayList;
14 import java.util.List;
17 import javax.servlet.http.HttpServletRequest;
18 import javax.servlet.http.HttpSession;
20 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
21 import org.opendaylight.controller.connectionmanager.IConnectionManager;
22 import org.opendaylight.controller.sal.authorization.UserLevel;
23 import org.opendaylight.controller.sal.core.Description;
24 import org.opendaylight.controller.sal.core.Node;
25 import org.opendaylight.controller.sal.utils.GlobalConstants;
26 import org.opendaylight.controller.sal.utils.ServiceHelper;
27 import org.opendaylight.controller.sal.utils.Status;
28 import org.opendaylight.controller.sal.utils.StatusCode;
29 import org.opendaylight.controller.switchmanager.ISwitchManager;
30 import org.opendaylight.controller.usermanager.IUserManager;
31 import org.opendaylight.controller.usermanager.UserConfig;
32 import org.springframework.stereotype.Controller;
33 import org.springframework.web.bind.annotation.PathVariable;
34 import org.springframework.web.bind.annotation.RequestMapping;
35 import org.springframework.web.bind.annotation.RequestMethod;
36 import org.springframework.web.bind.annotation.RequestParam;
37 import org.springframework.web.bind.annotation.ResponseBody;
39 import com.google.gson.Gson;
42 @RequestMapping("/admin")
43 public class DaylightWebAdmin {
44 Gson gson = new Gson();
47 * Returns list of clustered controllers. Highlights "this" controller and
48 * if controller is coordinator
50 * @return List<ClusterBean>
52 @RequestMapping("/cluster")
54 public String getClusteredControllers() {
55 IClusterGlobalServices clusterServices = (IClusterGlobalServices) ServiceHelper.getGlobalInstance(
56 IClusterGlobalServices.class, this);
57 if (clusterServices == null) {
60 IConnectionManager connectionManager = (IConnectionManager) ServiceHelper.getGlobalInstance(
61 IConnectionManager.class, this);
62 if (connectionManager == null) {
66 List<ClusterNodeBean> clusterNodes = new ArrayList<ClusterNodeBean>();
68 List<InetAddress> controllers = clusterServices.getClusteredControllers();
69 for (InetAddress controller : controllers) {
70 ClusterNodeBean.Builder clusterBeanBuilder = new ClusterNodeBean.Builder(controller);
72 // get number of connected nodes
73 Set<Node> connectedNodes = connectionManager.getNodes(controller);
74 int numNodes = connectedNodes == null ? 0 : connectedNodes.size();
75 clusterBeanBuilder.nodesConnected(numNodes);
77 // determine if this is the executing controller
78 if (controller.equals(clusterServices.getMyAddress())) {
79 clusterBeanBuilder.highlightMe();
82 // determine whether this is coordinator
83 if (clusterServices.getCoordinatorAddress().equals(controller)) {
84 clusterBeanBuilder.iAmCoordinator();
86 clusterNodes.add(clusterBeanBuilder.build());
89 return gson.toJson(clusterNodes);
93 * Return nodes connected to controller {controller}
96 * - byte[] of the address of the controller
97 * @return List<NodeBean>
99 @RequestMapping("/cluster/controller/{controller}")
101 public String getNodesConnectedToController(@PathVariable("controller") String controller) {
102 IClusterGlobalServices clusterServices = (IClusterGlobalServices) ServiceHelper.getGlobalInstance(
103 IClusterGlobalServices.class, this);
104 if (clusterServices == null) {
107 IConnectionManager connectionManager = (IConnectionManager) ServiceHelper.getGlobalInstance(
108 IConnectionManager.class, this);
109 if (connectionManager == null) {
112 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class,
113 GlobalConstants.DEFAULT.toString(), this);
114 if (switchManager == null) {
118 byte[] address = gson.fromJson(controller, byte[].class);
119 InetAddress controllerAddress = null;
121 controllerAddress = InetAddress.getByAddress(address);
122 } catch (UnknownHostException e) {
126 List<NodeBean> result = new ArrayList<NodeBean>();
128 Set<Node> nodes = connectionManager.getNodes(controllerAddress);
130 return gson.toJson(result);
132 for (Node node : nodes) {
133 Description description = (Description) switchManager.getNodeProp(node, Description.propertyName);
135 if (description == null || description.getValue().equals("None")) {
136 nodeBean = new NodeBean(node);
138 nodeBean = new NodeBean(node, description.getValue());
140 result.add(nodeBean);
143 return gson.toJson(result);
146 @RequestMapping(value = "/users", method = RequestMethod.GET)
148 public List<UserBean> getUsers() {
149 IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
150 if (userManager == null) {
154 List<UserBean> result = new ArrayList<UserBean>();
155 List<UserConfig> configs = userManager.getLocalUserList();
156 for (UserConfig config : configs) {
157 UserBean bean = new UserBean(config);
165 * Password in clear text, moving to HTTP/SSL soon
167 @RequestMapping(value = "/users", method = RequestMethod.POST)
169 public Status saveLocalUserConfig(@RequestParam(required = true) String json,
170 @RequestParam(required = true) String action, HttpServletRequest request) {
172 IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
173 if (userManager == null) {
174 return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
177 if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
178 return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
181 Gson gson = new Gson();
182 UserConfig plainConfig = gson.fromJson(json, UserConfig.class);
183 // Recreate using the proper constructor which will hash the password
184 UserConfig config = new UserConfig(plainConfig.getUser(), plainConfig.getPassword(), plainConfig.getRoles());
186 Status result = (action.equals("add")) ? userManager.addLocalUser(config) : userManager.removeLocalUser(config);
187 if (result.isSuccess()) {
188 if (action.equals("add")) {
189 DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "added", config.getUser()
190 + " as " + config.getRoles().toString());
192 DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", config.getUser());
198 @RequestMapping(value = "/user/modify", method = RequestMethod.POST)
200 public Status modifyUser(@RequestParam(required = true) String json,
201 @RequestParam(required = true) String action, HttpServletRequest request) {
203 IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
204 if (userManager == null) {
205 return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
208 if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
209 return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
212 UserConfig newConfig = gson.fromJson(json, UserConfig.class);
213 List<UserConfig> currentUserConfig = userManager.getLocalUserList();
214 String password = null;
216 String user = newConfig.getUser();
217 for (UserConfig userConfig : currentUserConfig) {
218 if(userConfig.getUser().equals(user)){
219 password = userConfig.getPassword();
220 salt = userConfig.getSalt();
224 if (password == null) {
225 String msg = String.format("User %s not found in configuration database", user);
226 return new Status(StatusCode.NOTFOUND, msg);
229 //While modifying a user role, the password is not provided from GUI for any user.
230 //The password is stored in hash mode, hence it cannot be retrieved and added to UserConfig object
231 //The hashed password is injected below to the json string containing username and new roles before
232 //converting to UserConfig object.
233 Gson gson = new Gson();
234 json = json.replace("\"roles\"", "\"salt\":" + gson.toJson(salt, salt.getClass()) + ",\"password\":\""+ password + "\",\"roles\"");
236 newConfig = gson.fromJson(json, UserConfig.class);
238 Status result = userManager.modifyLocalUser(newConfig);
239 if (result.isSuccess()) {
240 DaylightWebUtil.auditlog("Roles of", request.getUserPrincipal().getName(), "updated", newConfig.getUser()
241 + " to " + newConfig.getRoles().toString());
247 @RequestMapping(value = "/users/{username}", method = RequestMethod.POST)
249 public Status removeLocalUser(@PathVariable("username") String userName, HttpServletRequest request) {
251 String loggedInUser = request.getUserPrincipal().getName();
252 if (loggedInUser.equals(userName)) {
253 String msg = "Invalid Request: User cannot delete itself";
254 return new Status(StatusCode.NOTALLOWED, msg);
257 IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
258 if (userManager == null) {
259 return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
262 if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
263 return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
266 Status status = userManager.removeLocalUser(userName);
267 if (status.isSuccess()) {
268 DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", userName);
274 @RequestMapping(value = "/users/password/{username}", method = RequestMethod.POST)
276 public Status changePassword(
277 @PathVariable("username") String username, HttpServletRequest request,
278 @RequestParam(value = "currentPassword", required=false) String currentPassword,
279 @RequestParam("newPassword") String newPassword) {
280 IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
281 if (userManager == null) {
282 return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
286 String requestingUser = request.getUserPrincipal().getName();
288 //changing own password
289 if (requestingUser.equals(username) ) {
290 status = userManager.changeLocalUserPassword(username, currentPassword, newPassword);
291 //enforce the user to re-login with new password
292 if (status.isSuccess() && !newPassword.equals(currentPassword)) {
293 userManager.userLogout(username);
294 HttpSession session = request.getSession(false);
295 if ( session != null) {
296 session.invalidate();
300 //admin level user resetting other's password
301 } else if (authorize(userManager, UserLevel.NETWORKADMIN, request)) {
303 //Since User Manager doesn't have an unprotected password change API,
304 //we re-create the user with the new password (and current roles).
305 List<String> roles = userManager.getUserRoles(username);
306 UserConfig newConfig = new UserConfig(username, newPassword, roles);
308 //validate before removing existing config, so we don't remove but fail to add
309 status = newConfig.validate();
310 if (!status.isSuccess()) {
314 userManager.userLogout(username);
315 status = userManager.removeLocalUser(username);
316 if (!status.isSuccess()) {
319 if (userManager.addLocalUser(newConfig).isSuccess()) {
320 status = new Status(StatusCode.SUCCESS, "Password for user " + username + " reset successfully.");
323 status = new Status(StatusCode.INTERNALERROR, "Failed resetting password for user " + username + ". User is now removed.");
328 status = new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
331 if (status.isSuccess()) {
332 DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "changed password for",
339 * Is the operation permitted for the given level
343 private boolean authorize(IUserManager userManager, UserLevel level, HttpServletRequest request) {
344 String username = request.getUserPrincipal().getName();
345 UserLevel userLevel = userManager.getUserLevel(username);
346 return userLevel.toNumber() <= level.toNumber();