Merge "Validate user input in FlowSepc Configuration"
[controller.git] / opendaylight / web / root / src / main / java / org / opendaylight / controller / web / DaylightWebAdmin.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.web;
10
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Set;
16
17 import javax.servlet.http.HttpServletRequest;
18 import javax.servlet.http.HttpSession;
19
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;
38
39 import com.google.gson.Gson;
40
41 @Controller
42 @RequestMapping("/admin")
43 public class DaylightWebAdmin {
44     Gson gson = new Gson();
45
46     /**
47      * Returns list of clustered controllers. Highlights "this" controller and
48      * if controller is coordinator
49      * @return List<ClusterBean>
50      */
51     @RequestMapping("/cluster")
52     @ResponseBody
53     public String getClusteredControllers() {
54         IClusterGlobalServices clusterServices = (IClusterGlobalServices) ServiceHelper.getGlobalInstance(
55                 IClusterGlobalServices.class, this);
56         if (clusterServices == null) {
57             return null;
58         }
59         IConnectionManager connectionManager = (IConnectionManager) ServiceHelper.getGlobalInstance(
60                 IConnectionManager.class, this);
61         if (connectionManager == null) {
62             return null;
63         }
64
65         List<ClusterNodeBean> clusterNodes = new ArrayList<ClusterNodeBean>();
66
67         List<InetAddress> controllers = clusterServices.getClusteredControllers();
68         for (InetAddress controller : controllers) {
69             ClusterNodeBean.Builder clusterBeanBuilder = new ClusterNodeBean.Builder(controller);
70
71             //get number of connected nodes
72             Set<Node> connectedNodes = connectionManager.getNodes(controller);
73             int numNodes = connectedNodes == null ? 0 : connectedNodes.size();
74             clusterBeanBuilder.nodesConnected(numNodes);
75
76             //determine if this is the executing controller
77             if (controller.equals(clusterServices.getMyAddress())) {
78                 clusterBeanBuilder.highlightMe();
79             }
80
81             //determine whether this is coordinator
82             if (clusterServices.getCoordinatorAddress().equals(controller)) {
83                 clusterBeanBuilder.iAmCoordinator();
84             }
85             clusterNodes.add(clusterBeanBuilder.build());
86         }
87
88         return gson.toJson(clusterNodes);
89     }
90
91     /**
92      * Return nodes connected to controller {controller}
93      * @param controller
94      *            - byte[] of the address of the controller
95      * @return List<NodeBean>
96      */
97     @RequestMapping("/cluster/controller/{controller}")
98     @ResponseBody
99     public String getNodesConnectedToController(@PathVariable("controller") String controller) {
100         IClusterGlobalServices clusterServices = (IClusterGlobalServices) ServiceHelper.getGlobalInstance(
101                 IClusterGlobalServices.class, this);
102         if (clusterServices == null) {
103             return null;
104         }
105         IConnectionManager connectionManager = (IConnectionManager) ServiceHelper.getGlobalInstance(
106                 IConnectionManager.class, this);
107         if (connectionManager == null) {
108             return null;
109         }
110         ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class,
111                 GlobalConstants.DEFAULT.toString(), this);
112         if (switchManager == null) {
113             return null;
114         }
115
116         byte[] address = gson.fromJson(controller, byte[].class);
117         InetAddress controllerAddress = null;
118         try {
119             controllerAddress = InetAddress.getByAddress(address);
120         } catch (UnknownHostException e) {
121             return null;
122         }
123
124         List<NodeBean> result = new ArrayList<NodeBean>();
125
126         Set<Node> nodes = connectionManager.getNodes(controllerAddress);
127         if (nodes == null) {
128             return gson.toJson(result);
129         }
130         for (Node node : nodes) {
131             Description description = (Description) switchManager.getNodeProp(node, Description.propertyName);
132             NodeBean nodeBean;
133             if (description == null || description.getValue().equals("None")) {
134                 nodeBean = new NodeBean(node);
135             } else {
136                 nodeBean = new NodeBean(node, description.getValue());
137             }
138             result.add(nodeBean);
139         }
140
141         return gson.toJson(result);
142     }
143
144     @RequestMapping("/users")
145     @ResponseBody
146     public List<UserConfig> getUsers() {
147         IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
148         if (userManager == null) {
149             return null;
150         }
151
152         List<UserConfig> userConfList = userManager.getLocalUserList();
153
154         return userConfList;
155     }
156
157     /*
158      * Password in clear text, moving to HTTP/SSL soon
159      */
160     @RequestMapping(value = "/users", method = RequestMethod.POST)
161     @ResponseBody
162     public String saveLocalUserConfig(@RequestParam(required = true) String json,
163             @RequestParam(required = true) String action, HttpServletRequest request) {
164
165         IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
166         if (userManager == null) {
167             return "Internal Error";
168         }
169
170         if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
171             return "Operation not permitted";
172         }
173
174         Gson gson = new Gson();
175         UserConfig plainConfig = gson.fromJson(json, UserConfig.class);
176         // Recreate using the proper constructor which will hash the password
177         UserConfig config = new UserConfig(plainConfig.getUser(), plainConfig.getPassword(), plainConfig.getRoles());
178
179         Status result = (action.equals("add")) ? userManager.addLocalUser(config) : userManager.removeLocalUser(config);
180         if (result.isSuccess()) {
181             String userAction = (action.equals("add")) ? "added" : "removed";
182             DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), userAction, config.getUser());
183             return "Success";
184         }
185         return result.getDescription();
186     }
187
188     @RequestMapping(value = "/users/{username}", method = RequestMethod.POST)
189     @ResponseBody
190     public String removeLocalUser(@PathVariable("username") String userName, HttpServletRequest request) {
191
192         String username = request.getUserPrincipal().getName();
193         if (username.equals(userName)) {
194             return "Invalid Request: User cannot delete itself";
195         }
196
197         IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
198         if (userManager == null) {
199             return "Internal Error";
200         }
201
202         if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
203             return "Operation not permitted";
204         }
205
206         Status result = userManager.removeLocalUser(userName);
207         if (result.isSuccess()) {
208             DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", userName);
209             return "Success";
210         }
211         return result.getDescription();
212     }
213
214     @RequestMapping(value = "/users/password/{username}", method = RequestMethod.POST)
215     @ResponseBody
216     public Status changePassword(
217             @PathVariable("username") String username, HttpServletRequest request,
218             @RequestParam(value = "currentPassword", required=false) String currentPassword,
219             @RequestParam("newPassword") String newPassword) {
220         IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
221         if (userManager == null) {
222             return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
223         }
224
225         Status status;
226         String requestingUser = request.getUserPrincipal().getName();
227
228         //changing own password
229         if (requestingUser.equals(username) ) {
230             status = userManager.changeLocalUserPassword(username, currentPassword, newPassword);
231             //enforce the user to re-login with new password
232             if (status.isSuccess() && !newPassword.equals(currentPassword)) {
233                 userManager.userLogout(username);
234                 HttpSession session = request.getSession(false);
235                 if ( session != null) {
236                     session.invalidate();
237                 }
238             }
239
240         //admin level user resetting other's password
241         } else if (authorize(userManager, UserLevel.NETWORKADMIN, request)) {
242
243             //Since User Manager doesn't have an unprotected password change API,
244             //we re-create the user with the new password (and current roles).
245             List<String> roles = userManager.getUserRoles(username);
246             UserConfig newConfig = new UserConfig(username, newPassword, roles);
247
248             //validate before removing existing config, so we don't remove but fail to add
249             status = newConfig.validate();
250             if (!status.isSuccess()) {
251                 return status;
252             }
253
254             userManager.userLogout(username);
255             status = userManager.removeLocalUser(username);
256             if (!status.isSuccess()) {
257                 return status;
258             }
259             if (userManager.addLocalUser(newConfig).isSuccess()) {
260                 status = new Status(StatusCode.SUCCESS, "Password for user " + username + " reset successfully.");
261             } else {
262                 //unexpected
263                 status = new Status(StatusCode.INTERNALERROR, "Failed resetting password for user " + username + ". User is now removed.");
264             }
265
266         //unauthorized
267         } else {
268             status = new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
269         }
270
271         if (status.isSuccess()) {
272             DaylightWebUtil.auditlog("User", requestingUser, "changed password for", username);
273         }
274         return status;
275     }
276
277     /**
278      * Is the operation permitted for the given level
279      * @param level
280      */
281     private boolean authorize(IUserManager userManager, UserLevel level, HttpServletRequest request) {
282         String username = request.getUserPrincipal().getName();
283         UserLevel userLevel = userManager.getUserLevel(username);
284         return userLevel.toNumber() <= level.toNumber();
285     }
286 }