+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.usermanager.northbound;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+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;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+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.UserLevel;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.controller.usermanager.UserConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class provides REST APIs to manage users.
+ * This API will only be availalbe via HTTPS.
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b> HTTPS </b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default so to
+ * use UserManager APIs turn on HTTPS on Web Server
+ */
+
+@Path("/")
+public class UserManagerNorthbound {
+ protected static final Logger logger = LoggerFactory.getLogger(UserManagerNorthbound.class);
+
+ private String username;
+
+ @Context
+ public void setSecurityContext(SecurityContext context) {
+ if (context != null && context.getUserPrincipal() != null) {
+ username = context.getUserPrincipal().getName();
+ }
+ }
+
+ protected String getUserName() {
+ return username;
+ }
+
+ private void handleNameMismatch(String name, String nameinURL) {
+ if (name == null || nameinURL == null) {
+ throw new BadRequestException(RestMessages.INVALIDDATA.toString() + " : Name is null");
+ }
+
+ if (name.equals(nameinURL)) {
+ return;
+ }
+ throw new ResourceConflictException(RestMessages.INVALIDDATA.toString()
+ + " : Name in URL does not match the name in request body");
+ }
+
+ /**
+ * Add a user
+ *
+ * @param userName
+ * name of new user to be added
+ * @param userConfigData
+ * the {@link UserConfig} user config structure in request body
+ *
+ * @return Response as dictated by the HTTP Response Status code
+ *
+ * <pre>
+ * Example:
+ *
+ * Request URL:
+ * https://localhost/controller/nb/v2/usermanager/user/testuser
+ *
+ * Request body in XML:
+ * <userConfig>
+ * <name>testuser</name>
+ * <roles>Network-Admin</roles>
+ * <password>pass!23</password>
+ * </userConfig>
+ *
+ * Request body in JSON:
+ * {
+ * "name":"testuser",
+ * "password":"pass!23",
+ * "roles":[
+ * "Network-Admin"
+ * ]
+ * }
+ * </pre>
+ */
+
+ @Path("/user/{userName}")
+ @PUT
+ @StatusCodes({ @ResponseCode(code = 201, condition = "User created successfully"),
+ @ResponseCode(code = 400, condition = "Invalid data passed"),
+ @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
+ @ResponseCode(code = 409, condition = "User name in url conflicts with name in request body"),
+ @ResponseCode(code = 404, condition = "User config is null"),
+ @ResponseCode(code = 500, condition = "Internal Server Error: Addition of user failed"),
+ @ResponseCode(code = 503, condition = "Service unavailable") })
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response addLocalUser(@PathParam("userName") String newUserName,@TypeHint(UserConfig.class) UserConfig userConfigData) {
+
+ if (!isAdminUser()) {
+ throw new UnauthorizedException("User is not authorized to perform user management operations ");
+ }
+
+ // Reconstructing the object so password can be hashed in userConfig
+ UserConfig userCfgObject = new UserConfig(userConfigData.getUser(),userConfigData.getPassword(),
+ userConfigData.getRoles());
+
+ handleNameMismatch(userCfgObject.getUser(), newUserName);
+
+ IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
+ if (userManager == null) {
+ throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+ Status status = userManager.addLocalUser(userCfgObject);
+ if (status.isSuccess()) {
+
+ NorthboundUtils.auditlog("User", username, "added", newUserName);
+ return Response.status(Response.Status.CREATED).build();
+ }
+ return NorthboundUtils.getResponse(status);
+ }
+
+ /**
+ * Delete a user
+ *
+ * @param userName
+ * name of user to be deleted
+ * @return Response as dictated by the HTTP Response Status code
+ *
+ * <pre>
+ * Example:
+ *
+ * Request URL:
+ * https://localhost/controller/nb/v2/usermanager/user/testuser
+ *
+ * </pre>
+ */
+ @Path("/user/{userName}")
+ @DELETE
+ @StatusCodes({ @ResponseCode(code = 204, condition = "User Deleted Successfully"),
+ @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
+ @ResponseCode(code = 404, condition = "The userName passed was not found"),
+ @ResponseCode(code = 500, condition = "Internal Server Error : Removal of user failed"),
+ @ResponseCode(code = 503, condition = "Service unavailable") })
+ public Response removeLocalUser(@PathParam("userName") String userToBeRemoved) {
+
+ if (!isAdminUser()) {
+ throw new UnauthorizedException("User is not authorized to perform user management operations ");
+ }
+
+ IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
+ if (userManager == null) {
+ throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+ Status status = userManager.removeLocalUser(userToBeRemoved);
+ if (status.isSuccess()) {
+ NorthboundUtils.auditlog("User", username, "removed", userToBeRemoved);
+ return Response.noContent().build();
+ }
+ return NorthboundUtils.getResponse(status);
+ }
+
+ private boolean isAdminUser(){
+ // get UserManager's instance
+ IUserManager auth = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
+ // check if logged in user has privileges of NETWORK_ADMIN or SYSTEM_ADMIN, if so return true
+ return auth.getUserLevel(getUserName()).ordinal() <= UserLevel.NETWORKADMIN.ordinal();
+ }
+
+}