PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/java/org/nrg/xapi/rest/users/UsersApi.java

https://bitbucket.org/radiologics/xnat-web-dpuk
Java | 929 lines | 842 code | 68 blank | 19 comment | 131 complexity | 8e4f894f3d6ca6ca819be6f80c9e34b2 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * web: org.nrg.xapi.rest.users.UsersApi
  3. * XNAT http://www.xnat.org
  4. * Copyright (c) 2005-2017, Washington University School of Medicine and Howard Hughes Medical Institute
  5. * All Rights Reserved
  6. *
  7. * Released under the Simplified BSD.
  8. */
  9. package org.nrg.xapi.rest.users;
  10. import com.google.common.collect.Lists;
  11. import io.swagger.annotations.*;
  12. import org.apache.commons.lang3.StringUtils;
  13. import org.jetbrains.annotations.Nullable;
  14. import org.nrg.framework.annotations.XapiRestController;
  15. import org.nrg.framework.exceptions.NrgServiceError;
  16. import org.nrg.framework.exceptions.NrgServiceRuntimeException;
  17. import org.nrg.framework.utilities.Patterns;
  18. import org.nrg.xapi.authorization.UserGroupXapiAuthorization;
  19. import org.nrg.xapi.authorization.UserResourceXapiAuthorization;
  20. import org.nrg.xapi.exceptions.DataFormatException;
  21. import org.nrg.xapi.exceptions.NotFoundException;
  22. import org.nrg.xapi.exceptions.ResourceAlreadyExistsException;
  23. import org.nrg.xapi.model.users.User;
  24. import org.nrg.xapi.model.users.UserFactory;
  25. import org.nrg.xapi.rest.*;
  26. import org.nrg.xdat.security.UserGroupI;
  27. import org.nrg.xdat.security.helpers.Groups;
  28. import org.nrg.xdat.security.helpers.Users;
  29. import org.nrg.xdat.security.services.RoleHolder;
  30. import org.nrg.xdat.security.services.UserManagementServiceI;
  31. import org.nrg.xdat.security.user.exceptions.PasswordComplexityException;
  32. import org.nrg.xdat.security.user.exceptions.UserInitException;
  33. import org.nrg.xdat.security.user.exceptions.UserNotFoundException;
  34. import org.nrg.xdat.services.AliasTokenService;
  35. import org.nrg.xdat.turbine.utils.AdminUtils;
  36. import org.nrg.xft.event.EventDetails;
  37. import org.nrg.xft.event.EventUtils;
  38. import org.nrg.xft.security.UserI;
  39. import org.slf4j.Logger;
  40. import org.slf4j.LoggerFactory;
  41. import org.springframework.beans.factory.annotation.Autowired;
  42. import org.springframework.http.HttpStatus;
  43. import org.springframework.http.MediaType;
  44. import org.springframework.http.ResponseEntity;
  45. import org.springframework.jdbc.core.RowMapper;
  46. import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
  47. import org.springframework.security.core.session.SessionInformation;
  48. import org.springframework.security.core.session.SessionRegistry;
  49. import org.springframework.security.core.userdetails.UserDetails;
  50. import org.springframework.web.bind.annotation.*;
  51. import javax.servlet.http.HttpSession;
  52. import java.sql.ResultSet;
  53. import java.sql.SQLException;
  54. import java.sql.Timestamp;
  55. import java.util.*;
  56. import static org.nrg.xdat.security.helpers.AccessLevel.*;
  57. @Api(description = "User Management API")
  58. @XapiRestController
  59. @RequestMapping(value = "/users")
  60. public class UsersApi extends AbstractXapiRestController {
  61. public static final RowMapper<User> USER_ROW_MAPPER = new RowMapper<User>() {
  62. @Override
  63. public User mapRow(final ResultSet resultSet, final int i) throws SQLException {
  64. Timestamp lastSuccessfulLogin = resultSet.getTimestamp("lastSuccessfulLogin");
  65. Date lastSuccessfulLoginDate = null;
  66. if (lastSuccessfulLogin != null) {
  67. lastSuccessfulLoginDate = new Date(lastSuccessfulLogin.getTime());
  68. }
  69. Timestamp lastModified = resultSet.getTimestamp("last_modified");
  70. Date lastModifiedDate = null;
  71. if (lastModified != null) {
  72. lastModifiedDate = new Date(lastModified.getTime());
  73. }
  74. return new User(resultSet.getInt("id"), resultSet.getString("username"), resultSet.getString("firstName"), resultSet.getString("lastName"), resultSet.getString("email"), null, null, null, true, lastModifiedDate, null, resultSet.getInt("enabled") == 1, resultSet.getInt("verified") == 1, lastSuccessfulLoginDate);
  75. }
  76. };
  77. public static final String QUERY_USER_PROFILES = "SELECT enabled, login AS username, xdat_user_id AS id, firstname AS firstName, lastname AS lastName, email, verified, last_modified, auth.max_login AS lastSuccessfulLogin FROM xdat_user JOIN xdat_user_meta_data ON xdat_user.user_info=xdat_user_meta_data.meta_data_id JOIN (SELECT xdat_username, max(last_successful_login) max_login FROM xhbm_xdat_user_auth GROUP BY xdat_username) auth ON xdat_user.login=auth.xdat_username ORDER BY xdat_user.xdat_user_id";
  78. public static final String QUERY_CURRENT_USERS = "SELECT enabled, login AS username, xdat_user_id AS id, firstname AS firstName, lastname AS lastName, email, verified, last_modified, auth.max_login AS lastSuccessfulLogin FROM xdat_user JOIN xdat_user_meta_data ON xdat_user.user_info=xdat_user_meta_data.meta_data_id JOIN (SELECT xdat_username, max(last_successful_login) max_login FROM xhbm_xdat_user_auth GROUP BY xdat_username) auth ON xdat_user.login=auth.xdat_username WHERE (xdat_user.enabled=1 OR (max_login > (CURRENT_DATE - INTERVAL '1 year') OR (max_login IS NULL AND (xdat_user_meta_data.last_modified > (CURRENT_DATE - INTERVAL '1 year') ) ) )) ORDER BY xdat_user.xdat_user_id";
  79. public static final String QUERY_USER_PROFILE = "SELECT enabled, login AS username, xdat_user_id AS id, firstname AS firstName, lastname AS lastName, email, verified, last_modified, auth.max_login AS lastSuccessfulLogin FROM xdat_user JOIN xdat_user_meta_data ON xdat_user.user_info=xdat_user_meta_data.meta_data_id JOIN (SELECT xdat_username, max(last_successful_login) max_login FROM xhbm_xdat_user_auth GROUP BY xdat_username) auth ON xdat_user.login=auth.xdat_username WHERE xdat_user.login=:username";
  80. @Autowired
  81. public UsersApi(final UserManagementServiceI userManagementService,
  82. final UserFactory factory,
  83. final RoleHolder roleHolder,
  84. final SessionRegistry sessionRegistry,
  85. final AliasTokenService aliasTokenService,
  86. final NamedParameterJdbcTemplate jdbcTemplate) {
  87. super(userManagementService, roleHolder);
  88. _sessionRegistry = sessionRegistry;
  89. _aliasTokenService = aliasTokenService;
  90. _factory = factory;
  91. _jdbcTemplate = jdbcTemplate;
  92. }
  93. @ApiOperation(value = "Get list of users.", notes = "The primary users function returns a list of all users of the XNAT system. This includes just the username and nothing else. You can retrieve a particular user by adding the username to the REST API URL or a list of users with abbreviated user profiles by calling /xapi/users/profiles.", response = String.class, responseContainer = "List")
  94. @ApiResponses({@ApiResponse(code = 200, message = "A list of usernames."),
  95. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  96. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the list of usernames."),
  97. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  98. @XapiRequestMapping(produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = Authorizer)
  99. @AuthDelegate(UserResourceXapiAuthorization.class)
  100. @ResponseBody
  101. public ResponseEntity<List<String>> usersGet() {
  102. return new ResponseEntity<List<String>>(new ArrayList<>(Users.getAllLogins()), HttpStatus.OK);
  103. }
  104. @ApiOperation(value = "Get list of user profiles.", notes = "The users' profiles function returns a list of all users of the XNAT system with brief information about each.", response = User.class, responseContainer = "List")
  105. @ApiResponses({@ApiResponse(code = 200, message = "A list of user profiles."),
  106. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  107. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the list of users."),
  108. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  109. @XapiRequestMapping(value = "profiles", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = Authorizer)
  110. @AuthDelegate(UserResourceXapiAuthorization.class)
  111. @ResponseBody
  112. public ResponseEntity<List<User>> usersProfilesGet() {
  113. return new ResponseEntity<>(_jdbcTemplate.query(QUERY_USER_PROFILES, USER_ROW_MAPPER), HttpStatus.OK);
  114. }
  115. @ApiOperation(value = "Get user profile.", notes = "The user profile function returns a user of the XNAT system with brief information.", response = User.class, responseContainer = "List")
  116. @ApiResponses({@ApiResponse(code = 200, message = "A user profile."),
  117. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  118. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the user profile."),
  119. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  120. @XapiRequestMapping(value = "profile/{username}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = Authorizer)
  121. @AuthDelegate(UserResourceXapiAuthorization.class)
  122. @ResponseBody
  123. public ResponseEntity<User> usersProfileGet(@ApiParam(value = "ID of the user to fetch", required = true) @PathVariable("username") @Username final String username) {
  124. List<User> usersList = null;
  125. String regex = "^[a-zA-Z0-9]+[a-zA-Z0-9._-]*$";
  126. if (username.matches(regex)) {
  127. usersList = _jdbcTemplate.query(QUERY_USER_PROFILE, new HashMap<String, Object>() {{
  128. put("username", username);
  129. }}, USER_ROW_MAPPER);
  130. }
  131. if (usersList != null && usersList.size() > 0) {
  132. return new ResponseEntity<>(usersList.get(0), HttpStatus.OK);
  133. } else {
  134. return new ResponseEntity<>(HttpStatus.OK);
  135. }
  136. }
  137. @ApiOperation(value = "Get list of users who are enabled or who have interacted with the site somewhat recently.", notes = "The users' profiles function returns a list of all users of the XNAT system with brief information about each.", response = User.class, responseContainer = "List")
  138. @ApiResponses({@ApiResponse(code = 200, message = "A list of user profiles."),
  139. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  140. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the list of usernames."),
  141. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  142. @XapiRequestMapping(value = "current", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = Authorizer)
  143. @AuthDelegate(UserResourceXapiAuthorization.class)
  144. @ResponseBody
  145. public ResponseEntity<List<User>> currentUsersProfilesGet() {
  146. return new ResponseEntity<>(_jdbcTemplate.query(QUERY_CURRENT_USERS, USER_ROW_MAPPER), HttpStatus.OK);
  147. }
  148. @ApiOperation(value = "Get list of active users.", notes = "Returns a map of usernames for users that have at least one currently active session, i.e. logged in or associated with a valid application session. The number of active sessions and a list of the session IDs is associated with each user.", response = Map.class, responseContainer = "Map")
  149. @ApiResponses({@ApiResponse(code = 200, message = "A list of active users."),
  150. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  151. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the list of usernames."),
  152. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  153. @XapiRequestMapping(value = "active", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = Admin)
  154. @ResponseBody
  155. public ResponseEntity<Map<String, Map<String, Object>>> getActiveUsers() {
  156. final Map<String, Map<String, Object>> activeUsers = new HashMap<>();
  157. for (final Object principal : _sessionRegistry.getAllPrincipals()) {
  158. final String username;
  159. if (principal instanceof String) {
  160. username = (String) principal;
  161. } else if (principal instanceof UserDetails) {
  162. username = ((UserDetails) principal).getUsername();
  163. } else {
  164. username = principal.toString();
  165. }
  166. final List<SessionInformation> sessions = _sessionRegistry.getAllSessions(principal, false);
  167. // Sometimes there are no sessions, which is weird but OK, we don't want to see those entries.
  168. final int count = sessions.size();
  169. if (count == 0) {
  170. continue;
  171. }
  172. // Now add user with a session or more to the list of active users.
  173. final ArrayList<String> sessionIds = new ArrayList<>();
  174. for (final SessionInformation session : sessions) {
  175. sessionIds.add(session.getSessionId());
  176. }
  177. final Map<String, Object> sessionData = new HashMap<>();
  178. sessionData.put("sessions", sessionIds);
  179. sessionData.put("count", count);
  180. activeUsers.put(username, sessionData);
  181. }
  182. return new ResponseEntity<>(activeUsers, HttpStatus.OK);
  183. }
  184. @ApiOperation(value = "Get information about active sessions for the indicated user.", notes = "Returns a map containing a list of session IDs and usernames for users that have at least one currently active session, i.e. logged in or associated with a valid application session. This also includes the number of active sessions for each user.", response = String.class, responseContainer = "List")
  185. @ApiResponses({@ApiResponse(code = 200, message = "A list of active users."),
  186. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  187. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access this user's sessions."),
  188. @ApiResponse(code = 404, message = "The indicated user has no active sessions or is not a valid user."),
  189. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  190. @XapiRequestMapping(value = "active/{username}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = User)
  191. @ResponseBody
  192. public ResponseEntity<List<String>> getUserActiveSessions(@ApiParam(value = "ID of the user to fetch", required = true) @PathVariable("username") @Username final String username) {
  193. for (final Object principal : _sessionRegistry.getAllPrincipals()) {
  194. final Object located = locatePrincipalByUsername(username);
  195. if (located == null) {
  196. continue;
  197. }
  198. final List<SessionInformation> sessions = _sessionRegistry.getAllSessions(principal, false);
  199. final List<String> sessionIds = new ArrayList<>();
  200. for (final SessionInformation session : sessions) {
  201. sessionIds.add(session.getSessionId());
  202. }
  203. return new ResponseEntity<>(sessionIds, HttpStatus.OK);
  204. }
  205. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  206. }
  207. @ApiOperation(value = "Gets the user with the specified user ID.", notes = "Returns the serialized user object with the specified user ID.", response = User.class)
  208. @ApiResponses({@ApiResponse(code = 200, message = "User successfully retrieved."),
  209. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  210. @ApiResponse(code = 403, message = "Not authorized to view this user."),
  211. @ApiResponse(code = 404, message = "User not found."),
  212. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  213. @XapiRequestMapping(value = "{username}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = Authorizer)
  214. @AuthDelegate(UserResourceXapiAuthorization.class)
  215. public ResponseEntity<User> getUser(@ApiParam(value = "Username of the user to fetch.", required = true) @PathVariable("username") @Username final String username) {
  216. try {
  217. final UserI user = getUserManagementService().getUser(username);
  218. return user == null ? new ResponseEntity<User>(HttpStatus.NOT_FOUND) : new ResponseEntity<>(_factory.getUser(user), HttpStatus.OK);
  219. } catch (UserInitException e) {
  220. _log.error("An error occurred initializing the user " + username, e);
  221. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  222. } catch (UserNotFoundException e) {
  223. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  224. }
  225. }
  226. @ApiOperation(value = "Updates the user object with the specified username.", notes = "Returns the updated serialized user object with the specified username.", response = User.class)
  227. @ApiResponses({@ApiResponse(code = 201, message = "User successfully created."),
  228. @ApiResponse(code = 400, message = "The submitted data was invalid."),
  229. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  230. @ApiResponse(code = 403, message = "Not authorized to update this user."),
  231. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  232. @XapiRequestMapping(produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST, restrictTo = Admin)
  233. public ResponseEntity<User> createUser(@RequestBody final User model) throws NotFoundException, PasswordComplexityException, DataFormatException, UserInitException, ResourceAlreadyExistsException {
  234. try {
  235. validateUser(model);
  236. } catch (Exception e) {
  237. return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
  238. }
  239. final UserI user = getUserManagementService().createUser();
  240. if (user == null) {
  241. throw new NrgServiceRuntimeException(NrgServiceError.Unknown, "Failed to create a user object for user " + model.getUsername());
  242. }
  243. user.setLogin(model.getUsername());
  244. user.setFirstname(model.getFirstName());
  245. user.setLastname(model.getLastName());
  246. user.setEmail(model.getEmail());
  247. if (model.isEnabled() != null) {
  248. user.setEnabled(model.isEnabled());
  249. }
  250. if (model.isVerified() != null) {
  251. user.setVerified(model.isVerified());
  252. }
  253. user.setPassword(model.getPassword());
  254. user.setAuthorization(model.getAuthorization());
  255. try {
  256. getUserManagementService().save(user, getSessionUser(), false, new EventDetails(EventUtils.CATEGORY.DATA, EventUtils.TYPE.WEB_SERVICE, Event.Added, "Requested by user " + getSessionUser().getUsername(), "Created new user " + user.getUsername() + " through XAPI user management API."));
  257. if (model.isVerified() && model.isEnabled()) {
  258. //When a user is enabled and verified, send a new user email
  259. try {
  260. AdminUtils.sendNewUserEmailMessage(user.getUsername(), user.getEmail());
  261. } catch (Exception e) {
  262. _log.error("", e);
  263. }
  264. }
  265. return new ResponseEntity<>(_factory.getUser(user), HttpStatus.CREATED);
  266. } catch (Exception e) {
  267. _log.error("Error occurred modifying user " + user.getLogin());
  268. }
  269. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  270. }
  271. @ApiOperation(value = "Updates the user object with the specified username.", notes = "Returns the updated serialized user object with the specified username.", response = User.class)
  272. @ApiResponses({@ApiResponse(code = 200, message = "User successfully updated."),
  273. @ApiResponse(code = 304, message = "The user object was not modified because no attributes were changed."),
  274. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  275. @ApiResponse(code = 403, message = "Not authorized to update this user."),
  276. @ApiResponse(code = 404, message = "User not found."),
  277. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  278. @XapiRequestMapping(value = "{username}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.PUT, restrictTo = User)
  279. public ResponseEntity<User> updateUser(@ApiParam(value = "The username of the user to create or update.", required = true) @PathVariable("username") @Username final String username, @RequestBody final User model) throws NotFoundException, PasswordComplexityException, UserInitException {
  280. final UserI user;
  281. try {
  282. user = getUserManagementService().getUser(username);
  283. } catch (UserNotFoundException e) {
  284. throw new NotFoundException("User with username " + username + " was not found.");
  285. }
  286. if (user == null) {
  287. throw new NrgServiceRuntimeException(NrgServiceError.Unknown, "Failed to retrieve user object for user " + username);
  288. }
  289. boolean oldEnabledFlag = user.isEnabled();
  290. boolean oldVerifiedFlag = user.isVerified();
  291. boolean isDirty = false;
  292. if ((StringUtils.isNotBlank(model.getUsername())) && (!StringUtils.equals(user.getUsername(), model.getUsername()))) {
  293. return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
  294. // user.setLogin(model.getUsername());
  295. // isDirty = true;
  296. }
  297. if ((StringUtils.isNotBlank(model.getFirstName())) && (!StringUtils.equals(user.getFirstname(), model.getFirstName()))) {
  298. user.setFirstname(model.getFirstName());
  299. isDirty = true;
  300. }
  301. if ((StringUtils.isNotBlank(model.getLastName())) && (!StringUtils.equals(user.getLastname(), model.getLastName()))) {
  302. user.setLastname(model.getLastName());
  303. isDirty = true;
  304. }
  305. if ((StringUtils.isNotBlank(model.getEmail())) && (!StringUtils.equals(user.getEmail(), model.getEmail()))) {
  306. user.setEmail(model.getEmail());
  307. isDirty = true;
  308. }
  309. // Don't do password compare: we can't.
  310. if (StringUtils.isNotBlank(model.getPassword())) {
  311. user.setPassword(model.getPassword());
  312. isDirty = true;
  313. }
  314. if (model.getAuthorization() != null && !model.getAuthorization().equals(user.getAuthorization())) {
  315. user.setAuthorization(model.getAuthorization());
  316. isDirty = true;
  317. }
  318. final Boolean enabled = model.isEnabled();
  319. if (enabled != null && enabled != user.isEnabled()) {
  320. user.setEnabled(enabled);
  321. if (!enabled) {
  322. //When a user is disabled, deactivate all their AliasTokens
  323. try {
  324. _aliasTokenService.deactivateAllTokensForUser(user.getLogin());
  325. } catch (Exception e) {
  326. _log.error("", e);
  327. }
  328. }
  329. isDirty = true;
  330. }
  331. final Boolean verified = model.isVerified();
  332. if (verified != null && verified != user.isVerified()) {
  333. user.setVerified(verified);
  334. isDirty = true;
  335. }
  336. if (!isDirty) {
  337. return new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
  338. }
  339. try {
  340. getUserManagementService().save(user, getSessionUser(), false, new EventDetails(EventUtils.CATEGORY.DATA, EventUtils.TYPE.WEB_SERVICE, Event.Modified, "", ""));
  341. if (model.isVerified() && model.isEnabled() && (!oldEnabledFlag || !oldVerifiedFlag)) {
  342. //When a user is enabled and verified, send a new user email
  343. try {
  344. AdminUtils.sendNewUserEmailMessage(user.getUsername(), user.getEmail());
  345. } catch (Exception e) {
  346. _log.error("", e);
  347. }
  348. }
  349. return new ResponseEntity<>(_factory.getUser(user), HttpStatus.OK);
  350. } catch (Exception e) {
  351. _log.error("Error occurred modifying user " + user.getLogin());
  352. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  353. }
  354. }
  355. @ApiOperation(value = "Invalidates all active sessions associated with the specified username.", notes = "Returns a list of session IDs that were invalidated.", response = String.class, responseContainer = "List")
  356. @ApiResponses({@ApiResponse(code = 200, message = "User successfully invalidated."),
  357. @ApiResponse(code = 304, message = "Indicated user has no active sessions, so no action was taken."),
  358. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  359. @ApiResponse(code = 403, message = "Not authorized to invalidate this user's sessions."),
  360. @ApiResponse(code = 404, message = "User not found."),
  361. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  362. @XapiRequestMapping(value = "active/{username}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.DELETE, restrictTo = User)
  363. public ResponseEntity<List<String>> invalidateUser(final HttpSession current, @ApiParam(value = "The username of the user to invalidate.", required = true) @PathVariable("username") @Username final String username) throws NotFoundException {
  364. final UserI user;
  365. final String currentSessionId;
  366. if (StringUtils.equals(getSessionUser().getUsername(), username)) {
  367. user = getSessionUser();
  368. currentSessionId = current.getId();
  369. } else {
  370. try {
  371. user = getUserManagementService().getUser(username);
  372. if (user == null) {
  373. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  374. }
  375. currentSessionId = null;
  376. } catch (UserInitException e) {
  377. _log.error("An error occurred initializing the user " + username, e);
  378. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  379. } catch (UserNotFoundException e) {
  380. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  381. }
  382. }
  383. final Object located = locatePrincipalByUsername(user.getUsername());
  384. if (located == null) {
  385. return new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
  386. }
  387. final List<SessionInformation> sessions = _sessionRegistry.getAllSessions(located, false);
  388. if (sessions.size() == 0) {
  389. return new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
  390. }
  391. final List<String> sessionIds = new ArrayList<>();
  392. for (final SessionInformation session : sessions) {
  393. final String sessionId = session.getSessionId();
  394. if (!StringUtils.equals(currentSessionId, sessionId)) {
  395. sessionIds.add(sessionId);
  396. session.expireNow();
  397. }
  398. }
  399. return new ResponseEntity<>(sessionIds, HttpStatus.OK);
  400. }
  401. @ApiOperation(value = "Returns whether the user with the specified user ID is enabled.", notes = "Returns true or false based on whether the specified user is enabled or not.", response = Boolean.class)
  402. @ApiResponses({@ApiResponse(code = 200, message = "User enabled status successfully retrieved."),
  403. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  404. @ApiResponse(code = 403, message = "Not authorized to get whether this user is enabled."),
  405. @ApiResponse(code = 404, message = "User not found."),
  406. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  407. @XapiRequestMapping(value = "{username}/enabled", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = User)
  408. public ResponseEntity<Boolean> usersIdEnabledGet(@ApiParam(value = "The ID of the user to retrieve the enabled status for.", required = true) @PathVariable("username") @Username final String username) {
  409. try {
  410. final UserI user = getUserManagementService().getUser(username);
  411. if (user == null) {
  412. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  413. }
  414. return new ResponseEntity<>(user.isEnabled(), HttpStatus.OK);
  415. } catch (UserInitException e) {
  416. _log.error("An error occurred initializing the user " + username, e);
  417. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  418. } catch (UserNotFoundException e) {
  419. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  420. }
  421. }
  422. @ApiOperation(value = "Sets the user's enabled state.", notes = "Sets the enabled state of the user with the specified user ID to the value of the flag parameter.", response = Boolean.class)
  423. @ApiResponses({@ApiResponse(code = 200, message = "User enabled status successfully set."),
  424. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  425. @ApiResponse(code = 403, message = "Not authorized to enable or disable this user."),
  426. @ApiResponse(code = 404, message = "User not found."),
  427. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  428. @XapiRequestMapping(value = "{username}/enabled/{flag}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.PUT, restrictTo = Admin)
  429. public ResponseEntity<Boolean> usersIdEnabledFlagPut(@ApiParam(value = "ID of the user to fetch", required = true) @PathVariable("username") @Username final String username, @ApiParam(value = "The value to set for the enabled status.", required = true) @PathVariable("flag") Boolean flag) {
  430. try {
  431. final UserI user = getUserManagementService().getUser(username);
  432. boolean oldEnabledFlag = user.isEnabled();
  433. user.setEnabled(flag);
  434. try {
  435. getUserManagementService().save(user, getSessionUser(), false, new EventDetails(EventUtils.CATEGORY.DATA, EventUtils.TYPE.WEB_SERVICE, flag ? Event.Enabled : Event.Disabled, "", ""));
  436. if (flag && !oldEnabledFlag && user.isVerified()) {
  437. //When a user is enabled, send a new user email if they're also verified
  438. try {
  439. AdminUtils.sendNewUserEmailMessage(username, user.getEmail());
  440. } catch (Exception e) {
  441. _log.error("", e);
  442. }
  443. }
  444. return new ResponseEntity<>(HttpStatus.OK);
  445. } catch (Exception e) {
  446. _log.error("Error occurred " + (flag ? "enabling" : "disabling") + " user " + user.getLogin());
  447. }
  448. return new ResponseEntity<>(false, HttpStatus.INTERNAL_SERVER_ERROR);
  449. } catch (UserInitException e) {
  450. _log.error("An error occurred initializing the user " + username, e);
  451. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  452. } catch (UserNotFoundException e) {
  453. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  454. }
  455. }
  456. @ApiOperation(value = "Returns whether the user with the specified user ID is verified.", notes = "Returns true or false based on whether the specified user is verified or not.", response = Boolean.class)
  457. @ApiResponses({@ApiResponse(code = 200, message = "User verified status successfully retrieved."),
  458. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  459. @ApiResponse(code = 403, message = "Not authorized to view this user."),
  460. @ApiResponse(code = 404, message = "User not found."),
  461. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  462. @XapiRequestMapping(value = "{username}/verified", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = User)
  463. public ResponseEntity<Boolean> usersIdVerifiedGet(@ApiParam(value = "The ID of the user to retrieve the verified status for.", required = true) @PathVariable("username") @Username final String username) {
  464. try {
  465. final UserI user = getUserManagementService().getUser(username);
  466. if (user == null) {
  467. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  468. }
  469. return new ResponseEntity<>(user.isVerified(), HttpStatus.OK);
  470. } catch (UserInitException e) {
  471. _log.error("An error occurred initializing the user " + username, e);
  472. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  473. } catch (UserNotFoundException e) {
  474. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  475. }
  476. }
  477. @ApiOperation(value = "Sets the user's verified state.", notes = "Sets the verified state of the user with the specified user ID to the value of the flag parameter.", response = Boolean.class)
  478. @ApiResponses({@ApiResponse(code = 200, message = "User verified status successfully set."),
  479. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  480. @ApiResponse(code = 403, message = "Not authorized to verify or un-verify this user."),
  481. @ApiResponse(code = 404, message = "User not found."),
  482. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  483. @XapiRequestMapping(value = "{username}/verified/{flag}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.PUT, restrictTo = Admin)
  484. public ResponseEntity<Boolean> usersIdVerifiedFlagPut(@ApiParam(value = "ID of the user to fetch", required = true) @PathVariable("username") @Username final String username, @ApiParam(value = "The value to set for the verified status.", required = true) @PathVariable("flag") Boolean flag) {
  485. try {
  486. final UserI user = getUserManagementService().getUser(username);
  487. if (user == null) {
  488. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  489. }
  490. boolean oldVerifiedFlag = user.isVerified();
  491. user.setVerified(flag);
  492. try {
  493. getUserManagementService().save(user, getSessionUser(), false, new EventDetails(EventUtils.CATEGORY.DATA, EventUtils.TYPE.WEB_SERVICE, flag ? Event.Enabled : Event.Disabled, "", ""));
  494. if (flag && !oldVerifiedFlag && user.isEnabled()) {
  495. //When a user is verified, send a new user email if they're also enabled
  496. try {
  497. AdminUtils.sendNewUserEmailMessage(username, user.getEmail());
  498. } catch (Exception e) {
  499. _log.error("", e);
  500. }
  501. }
  502. return new ResponseEntity<>(HttpStatus.OK);
  503. } catch (Exception e) {
  504. _log.error("Error occurred " + (flag ? "enabling" : "disabling") + " user " + user.getLogin());
  505. }
  506. return new ResponseEntity<>(false, HttpStatus.INTERNAL_SERVER_ERROR);
  507. } catch (UserInitException e) {
  508. _log.error("An error occurred initializing the user " + username, e);
  509. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  510. } catch (UserNotFoundException e) {
  511. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  512. }
  513. }
  514. @ApiOperation(value = "Returns the roles for the user with the specified user ID.", notes = "Returns a collection of the user's roles.", response = Collection.class)
  515. @ApiResponses({@ApiResponse(code = 200, message = "User roles successfully retrieved."),
  516. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  517. @ApiResponse(code = 403, message = "Not authorized to view this user."),
  518. @ApiResponse(code = 404, message = "User not found."),
  519. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  520. @XapiRequestMapping(value = "{username}/roles", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = User)
  521. public ResponseEntity<Collection<String>> usersIdRolesGet(@ApiParam(value = "The ID of the user to retrieve the roles for.", required = true) @PathVariable("username") @Username final String username) {
  522. final Collection<String> roles = getUserRoles(username);
  523. return roles != null ? new ResponseEntity<>(roles, HttpStatus.OK) : new ResponseEntity<Collection<String>>(HttpStatus.FORBIDDEN);
  524. }
  525. @ApiOperation(value = "Adds one or more roles to a user.", notes = "Assigns one or more new roles to a user.", response = String.class, responseContainer = "List")
  526. @ApiResponses({@ApiResponse(code = 200, message = "All specified user roles successfully added."),
  527. @ApiResponse(code = 202, message = "Some user roles successfully added, but some may have failed. Check the return value for roles that the service was unable to add."),
  528. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  529. @ApiResponse(code = 403, message = "Not authorized to add roles to this user."),
  530. @ApiResponse(code = 404, message = "User not found."),
  531. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  532. @XapiRequestMapping(value = "{username}/roles", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.PUT, restrictTo = Admin)
  533. public ResponseEntity<Collection<String>> usersIdAddRoles(@ApiParam(value = "ID of the user to add a role to", required = true) @PathVariable("username") @Username final String username,
  534. @ApiParam(value = "The user's new roles.", required = true) @RequestBody final List<String> roles) {
  535. final Collection<String> failed = Lists.newArrayList();
  536. try {
  537. final UserI user = getUserManagementService().getUser(username);
  538. if (user == null) {
  539. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  540. }
  541. for (final String role : roles) {
  542. try {
  543. getRoleHolder().addRole(getSessionUser(), user, role);
  544. } catch (Exception e) {
  545. failed.add(role);
  546. _log.error("Error occurred adding role " + role + " to user " + user.getLogin() + ".", e);
  547. }
  548. }
  549. } catch (UserInitException e) {
  550. _log.error("An error occurred initializing the user " + username, e);
  551. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  552. } catch (UserNotFoundException e) {
  553. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  554. }
  555. if (failed.size() == 0) {
  556. return new ResponseEntity<>(HttpStatus.OK);
  557. }
  558. return new ResponseEntity<>(failed, HttpStatus.ACCEPTED);
  559. }
  560. @ApiOperation(value = "Removes one or more roles from a user.", notes = "Removes one or more new roles from a user.", response = String.class, responseContainer = "List")
  561. @ApiResponses({@ApiResponse(code = 200, message = "All specified user roles successfully removed."),
  562. @ApiResponse(code = 202, message = "Some user roles successfully removed, but some may have failed. Check the return value for roles that the service was unable to remove."),
  563. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  564. @ApiResponse(code = 403, message = "Not authorized to remove roles from this user."),
  565. @ApiResponse(code = 404, message = "User not found."),
  566. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  567. @XapiRequestMapping(value = "{username}/roles", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.DELETE, restrictTo = Admin)
  568. public ResponseEntity<Collection<String>> usersIdRemoveRoles(@ApiParam(value = "ID of the user to remove role from", required = true) @PathVariable("username") @Username final String username,
  569. @ApiParam(value = "The roles to be removed.", required = true) @RequestBody final List<String> roles) {
  570. final Collection<String> failed = Lists.newArrayList();
  571. try {
  572. final UserI user = getUserManagementService().getUser(username);
  573. if (user == null) {
  574. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  575. }
  576. for (final String role : roles) {
  577. try {
  578. getRoleHolder().deleteRole(getSessionUser(), user, role);
  579. } catch (Exception e) {
  580. failed.add(role);
  581. _log.error("Error occurred remove role " + role + " from user " + user.getLogin() + ".", e);
  582. }
  583. }
  584. } catch (UserInitException e) {
  585. _log.error("An error occurred initializing the user " + username, e);
  586. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  587. } catch (UserNotFoundException e) {
  588. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  589. }
  590. if (failed.size() == 0) {
  591. return new ResponseEntity<>(HttpStatus.OK);
  592. }
  593. return new ResponseEntity<>(failed, HttpStatus.ACCEPTED);
  594. }
  595. @ApiOperation(value = "Adds a role to a user.", notes = "Assigns a new role to a user.", response = Boolean.class)
  596. @ApiResponses({@ApiResponse(code = 200, message = "User role successfully added."),
  597. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  598. @ApiResponse(code = 403, message = "Not authorized to add a role to this user."),
  599. @ApiResponse(code = 404, message = "User not found."),
  600. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  601. @XapiRequestMapping(value = "{username}/roles/{role}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.PUT, restrictTo = Admin)
  602. public ResponseEntity<Boolean> usersIdAddRole(@ApiParam(value = "ID of the user to add a role to", required = true) @PathVariable("username") @Username final String username,
  603. @ApiParam(value = "The user's new role.", required = true) @PathVariable("role") final String role) {
  604. try {
  605. final UserI user = getUserManagementService().getUser(username);
  606. if (user == null) {
  607. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  608. }
  609. try {
  610. getRoleHolder().addRole(getSessionUser(), user, role);
  611. return new ResponseEntity<>(HttpStatus.OK);
  612. } catch (Exception e) {
  613. _log.error("Error occurred adding role " + role + " to user " + user.getLogin() + ".");
  614. }
  615. return new ResponseEntity<>(false, HttpStatus.INTERNAL_SERVER_ERROR);
  616. } catch (UserInitException e) {
  617. _log.error("An error occurred initializing the user " + username, e);
  618. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  619. } catch (UserNotFoundException e) {
  620. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  621. }
  622. }
  623. @ApiOperation(value = "Remove a user's role.", notes = "Removes a user's role.", response = Boolean.class)
  624. @ApiResponses({@ApiResponse(code = 200, message = "User role successfully removed."),
  625. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  626. @ApiResponse(code = 403, message = "Not authorized to remove a role from this user."),
  627. @ApiResponse(code = 404, message = "User not found."),
  628. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  629. @XapiRequestMapping(value = "{username}/roles/{role}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.DELETE, restrictTo = Admin)
  630. public ResponseEntity<Boolean> usersIdRemoveRole(@ApiParam(value = "ID of the user to delete a role from", required = true) @PathVariable("username") @Username final String username,
  631. @ApiParam(value = "The user role to delete.", required = true) @PathVariable("role") String role) {
  632. try {
  633. final UserI user = getUserManagementService().getUser(username);
  634. if (user == null) {
  635. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  636. }
  637. try {
  638. getRoleHolder().deleteRole(getSessionUser(), user, role);
  639. return new ResponseEntity<>(HttpStatus.OK);
  640. } catch (Exception e) {
  641. _log.error("Error occurred removing role " + role + " from user " + user.getLogin() + ".");
  642. }
  643. return new ResponseEntity<>(false, HttpStatus.INTERNAL_SERVER_ERROR);
  644. } catch (UserInitException e) {
  645. _log.error("An error occurred initializing the user " + username, e);
  646. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  647. } catch (UserNotFoundException e) {
  648. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  649. }
  650. }
  651. @ApiOperation(value = "Returns the groups for the user with the specified user ID.", notes = "Returns a collection of the user's groups.", response = Set.class)
  652. @ApiResponses({@ApiResponse(code = 200, message = "User groups successfully retrieved."),
  653. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  654. @ApiResponse(code = 403, message = "Not authorized to get the groups for this user."),
  655. @ApiResponse(code = 404, message = "User not found."),
  656. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  657. @XapiRequestMapping(value = "{username}/groups", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET, restrictTo = User)
  658. public ResponseEntity<Set<String>> usersIdGroupsGet(@ApiParam(value = "The ID of the user to retrieve the groups for.", required = true) @PathVariable("username") @Username final String username) {
  659. try {
  660. final UserI user = getUserManagementService().getUser(username);
  661. if (user == null) {
  662. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  663. }
  664. Map<String, UserGroupI> groups = Groups.getGroupsForUser(user);
  665. return new ResponseEntity<>(groups.keySet(), HttpStatus.OK);
  666. } catch (UserInitException e) {
  667. _log.error("An error occurred initializing the user " + username, e);
  668. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  669. } catch (UserNotFoundException e) {
  670. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  671. }
  672. }
  673. @ApiOperation(value = "Adds the user to one or more groups.", notes = "Assigns the user to one or more new groups.", response = String.class, responseContainer = "List")
  674. @ApiResponses({@ApiResponse(code = 200, message = "User successfully added for all specified groups."),
  675. @ApiResponse(code = 202, message = "User was successfully added to some of the specified groups, but some may have failed. Check the return value for groups that the service was unable to add."),
  676. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  677. @ApiResponse(code = 403, message = "Not authorized to add this user to groups."),
  678. @ApiResponse(code = 404, message = "User not found."),
  679. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  680. @XapiRequestMapping(value = "{username}/groups", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.PUT, restrictTo = Authorizer)
  681. @AuthDelegate(UserGroupXapiAuthorization.class)
  682. public ResponseEntity<Collection<String>> usersIdAddGroups(@ApiParam(value = "ID of the user to add to the specified groups", required = true) @PathVariable("username") @Username final String username,
  683. @ApiParam(value = "The groups to which the user should be added.", required = true) @RestUserGroup @RequestBody final List<String> groups) {
  684. final Collection<String> failed = Lists.newArrayList();
  685. try {
  686. final UserI user = getUserManagementService().getUser(username);
  687. if (user == null) {
  688. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  689. }
  690. for (final String group : groups) {
  691. try {
  692. Groups.addUserToGroup(group, user, getSessionUser(), EventUtils.ADMIN_EVENT(getSessionUser()));
  693. } catch (Exception e) {
  694. failed.add(group);
  695. _log.error("Error occurred adding user " + user.getLogin() + " to group " + group + ".", e);
  696. }
  697. }
  698. } catch (UserInitException e) {
  699. _log.error("An error occurred initializing the user " + username, e);
  700. return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  701. } catch (UserNotFoundException e) {
  702. return new ResponseEntity<>(HttpStatus.NOT_FOUND

Large files files are truncated, but you can click here to view the full file