PageRenderTime 67ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/radiologics/xnat-web-old-v2
Java | 936 lines | 850 code | 70 blank | 16 comment | 119 complexity | 899edda1997a94a71ac1bd73463a03f6 MD5 | raw 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.base.Function;
  11. import com.google.common.collect.Lists;
  12. import io.swagger.annotations.*;
  13. import lombok.extern.slf4j.Slf4j;
  14. import org.apache.commons.lang3.BooleanUtils;
  15. import org.apache.commons.lang3.StringUtils;
  16. import org.nrg.framework.annotations.XapiRestController;
  17. import org.nrg.framework.exceptions.NrgServiceError;
  18. import org.nrg.framework.exceptions.NrgServiceRuntimeException;
  19. import org.nrg.framework.utilities.Patterns;
  20. import org.nrg.xapi.authorization.UserGroupXapiAuthorization;
  21. import org.nrg.xapi.authorization.UserResourceXapiAuthorization;
  22. import org.nrg.xapi.exceptions.DataFormatException;
  23. import org.nrg.xapi.exceptions.NotFoundException;
  24. import org.nrg.xapi.exceptions.ResourceAlreadyExistsException;
  25. import org.nrg.xapi.model.users.User;
  26. import org.nrg.xapi.model.users.UserFactory;
  27. import org.nrg.xapi.rest.*;
  28. import org.nrg.xdat.security.UserGroupI;
  29. import org.nrg.xdat.security.helpers.Groups;
  30. import org.nrg.xdat.security.helpers.Users;
  31. import org.nrg.xdat.security.services.PermissionsServiceI;
  32. import org.nrg.xdat.security.services.RoleHolder;
  33. import org.nrg.xdat.security.services.UserManagementServiceI;
  34. import org.nrg.xdat.security.user.exceptions.UserInitException;
  35. import org.nrg.xdat.security.user.exceptions.UserNotFoundException;
  36. import org.nrg.xdat.services.AliasTokenService;
  37. import org.nrg.xdat.turbine.utils.AdminUtils;
  38. import org.nrg.xft.event.EventDetails;
  39. import org.nrg.xft.event.EventUtils;
  40. import org.nrg.xft.security.UserI;
  41. import org.springframework.beans.factory.annotation.Autowired;
  42. import org.springframework.http.ResponseEntity;
  43. import org.springframework.jdbc.core.RowMapper;
  44. import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
  45. import org.springframework.security.core.session.SessionInformation;
  46. import org.springframework.security.core.session.SessionRegistry;
  47. import org.springframework.security.core.userdetails.UserDetails;
  48. import org.springframework.web.bind.annotation.PathVariable;
  49. import org.springframework.web.bind.annotation.RequestBody;
  50. import org.springframework.web.bind.annotation.RequestMapping;
  51. import org.springframework.web.bind.annotation.ResponseBody;
  52. import javax.annotation.Nullable;
  53. import javax.servlet.http.HttpSession;
  54. import java.sql.ResultSet;
  55. import java.sql.SQLException;
  56. import java.sql.Timestamp;
  57. import java.util.*;
  58. import static org.nrg.xdat.security.helpers.AccessLevel.*;
  59. import static org.springframework.http.HttpStatus.*;
  60. import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
  61. import static org.springframework.web.bind.annotation.RequestMethod.*;
  62. @SuppressWarnings({"SqlNoDataSourceInspection", "SqlResolve"})
  63. @Api(description = "User Management API")
  64. @XapiRestController
  65. @RequestMapping(value = "/users")
  66. @Slf4j
  67. public class UsersApi extends AbstractXapiRestController {
  68. public static final RowMapper<User> USER_ROW_MAPPER = new RowMapper<User>() {
  69. @Override
  70. public User mapRow(final ResultSet resultSet, final int index) throws SQLException {
  71. final int userId = resultSet.getInt("id");
  72. final String username = resultSet.getString("username");
  73. final String firstName = resultSet.getString("firstName");
  74. final String lastName = resultSet.getString("lastName");
  75. final String email = resultSet.getString("email");
  76. final Timestamp lastModified = resultSet.getTimestamp("last_modified");
  77. final Date lastModifiedDate = lastModified != null ? new Date(lastModified.getTime()) : null;
  78. final boolean enabled = resultSet.getInt("enabled") == 1;
  79. final boolean verified = resultSet.getInt("verified") == 1;
  80. final Timestamp lastSuccessfulLogin = resultSet.getTimestamp("lastSuccessfulLogin");
  81. final Date lastSuccessfulLoginDate = lastSuccessfulLogin != null ? new Date(lastSuccessfulLogin.getTime()) : null;
  82. return new User(userId, username, firstName, lastName, email, null, null, null, true, lastModifiedDate, null, enabled, verified, lastSuccessfulLoginDate);
  83. }
  84. };
  85. 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";
  86. 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";
  87. 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";
  88. @Autowired
  89. public UsersApi(final UserManagementServiceI userManagementService,
  90. final UserFactory factory,
  91. final RoleHolder roleHolder,
  92. final SessionRegistry sessionRegistry,
  93. final AliasTokenService aliasTokenService,
  94. final PermissionsServiceI permissionsService,
  95. final NamedParameterJdbcTemplate jdbcTemplate) {
  96. super(userManagementService, roleHolder);
  97. _sessionRegistry = sessionRegistry;
  98. _aliasTokenService = aliasTokenService;
  99. _permissionsService = permissionsService;
  100. _factory = factory;
  101. _jdbcTemplate = jdbcTemplate;
  102. }
  103. @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")
  104. @ApiResponses({@ApiResponse(code = 200, message = "A list of usernames."),
  105. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  106. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the list of usernames."),
  107. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  108. @XapiRequestMapping(produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = Authorizer)
  109. @AuthDelegate(UserResourceXapiAuthorization.class)
  110. @ResponseBody
  111. public ResponseEntity<List<String>> usersGet() {
  112. return new ResponseEntity<List<String>>(new ArrayList<>(Users.getAllLogins()), OK);
  113. }
  114. @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")
  115. @ApiResponses({@ApiResponse(code = 200, message = "A list of user profiles."),
  116. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  117. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the list of users."),
  118. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  119. @XapiRequestMapping(value = "profiles", produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = Authorizer)
  120. @AuthDelegate(UserResourceXapiAuthorization.class)
  121. @ResponseBody
  122. public ResponseEntity<List<User>> usersProfilesGet() {
  123. return new ResponseEntity<>(_jdbcTemplate.query(QUERY_USER_PROFILES, USER_ROW_MAPPER), OK);
  124. }
  125. @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")
  126. @ApiResponses({@ApiResponse(code = 200, message = "A user profile."),
  127. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  128. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the user profile."),
  129. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  130. @XapiRequestMapping(value = "profile/{username}", produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = Authorizer)
  131. @AuthDelegate(UserResourceXapiAuthorization.class)
  132. @ResponseBody
  133. public ResponseEntity<User> usersProfileGet(@ApiParam(value = "ID of the user to fetch", required = true) @PathVariable("username") @Username final String username) {
  134. List<User> usersList = null;
  135. String regex = "^[a-zA-Z0-9]+[a-zA-Z0-9._-]*$";
  136. if (username.matches(regex)) {
  137. usersList = _jdbcTemplate.query(QUERY_USER_PROFILE, new HashMap<String, Object>() {{
  138. put("username", username);
  139. }}, USER_ROW_MAPPER);
  140. }
  141. if (usersList != null && usersList.size() > 0) {
  142. return new ResponseEntity<>(usersList.get(0), OK);
  143. } else {
  144. return new ResponseEntity<>(OK);
  145. }
  146. }
  147. @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")
  148. @ApiResponses({@ApiResponse(code = 200, message = "A list of user profiles."),
  149. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  150. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the list of usernames."),
  151. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  152. @XapiRequestMapping(value = "current", produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = Authorizer)
  153. @AuthDelegate(UserResourceXapiAuthorization.class)
  154. @ResponseBody
  155. public ResponseEntity<List<User>> currentUsersProfilesGet() {
  156. return new ResponseEntity<>(_jdbcTemplate.query(QUERY_CURRENT_USERS, USER_ROW_MAPPER), OK);
  157. }
  158. @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")
  159. @ApiResponses({@ApiResponse(code = 200, message = "A list of active users."),
  160. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  161. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access the list of usernames."),
  162. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  163. @XapiRequestMapping(value = "active", produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = Admin)
  164. @ResponseBody
  165. public ResponseEntity<Map<String, Map<String, Object>>> getActiveUsers() {
  166. final Map<String, Map<String, Object>> activeUsers = new HashMap<>();
  167. for (final Object principal : _sessionRegistry.getAllPrincipals()) {
  168. final String username;
  169. if (principal instanceof String) {
  170. username = (String) principal;
  171. } else if (principal instanceof UserDetails) {
  172. username = ((UserDetails) principal).getUsername();
  173. } else {
  174. username = principal.toString();
  175. }
  176. final List<SessionInformation> sessions = _sessionRegistry.getAllSessions(principal, false);
  177. // Sometimes there are no sessions, which is weird but OK, we don't want to see those entries.
  178. if (sessions.isEmpty()) {
  179. continue;
  180. }
  181. final Map<String, Object> sessionData = new HashMap<>();
  182. sessionData.put("sessions", Lists.transform(sessions, INFO_TO_ID_FUNCTION));
  183. sessionData.put("count", sessions.size());
  184. activeUsers.put(username, sessionData);
  185. }
  186. return new ResponseEntity<>(activeUsers, OK);
  187. }
  188. @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")
  189. @ApiResponses({@ApiResponse(code = 200, message = "A list of active users."),
  190. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  191. @ApiResponse(code = 403, message = "You do not have sufficient permissions to access this user's sessions."),
  192. @ApiResponse(code = 404, message = "The indicated user has no active sessions or is not a valid user."),
  193. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  194. @XapiRequestMapping(value = "active/{username}", produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = User)
  195. @ResponseBody
  196. public ResponseEntity<List<String>> getUserActiveSessions(@ApiParam(value = "ID of the user to fetch", required = true) @PathVariable("username") @Username final String username) {
  197. final Object located = locatePrincipalByUsername(username);
  198. if (located == null) {
  199. return new ResponseEntity<>(NOT_FOUND);
  200. }
  201. final List<SessionInformation> sessions = _sessionRegistry.getAllSessions(located, false);
  202. if (sessions.isEmpty()) {
  203. return new ResponseEntity<>(NOT_MODIFIED);
  204. }
  205. return new ResponseEntity<>(Lists.transform(sessions, INFO_TO_ID_FUNCTION), OK);
  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 = APPLICATION_JSON_VALUE, method = 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>(NOT_FOUND) : new ResponseEntity<>(_factory.getUser(user), OK);
  219. } catch (UserInitException e) {
  220. log.error("An error occurred initializing the user " + username, e);
  221. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  222. } catch (UserNotFoundException e) {
  223. return new ResponseEntity<>(NOT_FOUND);
  224. }
  225. }
  226. @ApiOperation(value = "Creates a new user from the request body.", notes = "Returns the newly created user object.", 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 = APPLICATION_JSON_VALUE, method = POST, restrictTo = Admin)
  233. public ResponseEntity<User> createUser(@RequestBody final User model) throws DataFormatException, ResourceAlreadyExistsException {
  234. validateUser(model);
  235. final UserI user = getUserManagementService().createUser();
  236. if (user == null) {
  237. throw new NrgServiceRuntimeException(NrgServiceError.Unknown, "Failed to create a user object for user " + model.getUsername());
  238. }
  239. user.setLogin(model.getUsername());
  240. user.setFirstname(model.getFirstName());
  241. user.setLastname(model.getLastName());
  242. user.setEmail(model.getEmail());
  243. user.setPassword(model.getPassword());
  244. user.setAuthorization(model.getAuthorization());
  245. if (model.isEnabled() != null) {
  246. user.setEnabled(model.isEnabled());
  247. }
  248. if (model.isVerified() != null) {
  249. user.setVerified(model.isVerified());
  250. }
  251. try {
  252. 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."));
  253. if (model.isVerified() && model.isEnabled()) {
  254. //When a user is enabled and verified, send a new user email
  255. try {
  256. AdminUtils.sendNewUserEmailMessage(user.getUsername(), user.getEmail());
  257. } catch (Exception e) {
  258. log.error("An error occurred trying to send email to the admin: new user '{}' created with email '{}'", user.getUsername(), user.getEmail(), e);
  259. }
  260. }
  261. return new ResponseEntity<>(_factory.getUser(user), CREATED);
  262. } catch (Exception e) {
  263. log.error("Error occurred modifying user " + user.getLogin());
  264. }
  265. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  266. }
  267. @ApiOperation(value = "Updates the user object with the specified username.", notes = "Returns the updated serialized user object with the specified username.", response = User.class)
  268. @ApiResponses({@ApiResponse(code = 200, message = "User successfully updated."),
  269. @ApiResponse(code = 304, message = "The user object was not modified because no attributes were changed."),
  270. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  271. @ApiResponse(code = 403, message = "Not authorized to update this user."),
  272. @ApiResponse(code = 404, message = "User not found."),
  273. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  274. @XapiRequestMapping(value = "{username}", produces = APPLICATION_JSON_VALUE, method = PUT, restrictTo = User)
  275. 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, UserInitException {
  276. final UserI user;
  277. try {
  278. user = getUserManagementService().getUser(username);
  279. } catch (UserNotFoundException e) {
  280. throw new NotFoundException("User with username " + username + " was not found.");
  281. }
  282. if (user == null) {
  283. throw new NrgServiceRuntimeException(NrgServiceError.Unknown, "Failed to retrieve user object for user " + username);
  284. }
  285. boolean oldEnabledFlag = user.isEnabled();
  286. boolean oldVerifiedFlag = user.isVerified();
  287. boolean isDirty = false;
  288. if ((StringUtils.isNotBlank(model.getUsername())) && (!StringUtils.equals(user.getUsername(), model.getUsername()))) {
  289. return new ResponseEntity<>(BAD_REQUEST);
  290. }
  291. if ((StringUtils.isNotBlank(model.getFirstName())) && (!StringUtils.equals(user.getFirstname(), model.getFirstName()))) {
  292. user.setFirstname(model.getFirstName());
  293. isDirty = true;
  294. }
  295. if ((StringUtils.isNotBlank(model.getLastName())) && (!StringUtils.equals(user.getLastname(), model.getLastName()))) {
  296. user.setLastname(model.getLastName());
  297. isDirty = true;
  298. }
  299. if ((StringUtils.isNotBlank(model.getEmail())) && (!StringUtils.equals(user.getEmail(), model.getEmail()))) {
  300. user.setEmail(model.getEmail());
  301. isDirty = true;
  302. }
  303. // Don't do password compare: we can't.
  304. if (StringUtils.isNotBlank(model.getPassword())) {
  305. user.setPassword(model.getPassword());
  306. isDirty = true;
  307. }
  308. if (model.getAuthorization() != null && !model.getAuthorization().equals(user.getAuthorization())) {
  309. user.setAuthorization(model.getAuthorization());
  310. isDirty = true;
  311. }
  312. final Boolean enabled = model.isEnabled();
  313. if (enabled != null && enabled != user.isEnabled()) {
  314. user.setEnabled(enabled);
  315. if (!enabled) {
  316. //When a user is disabled, deactivate all their AliasTokens
  317. try {
  318. _aliasTokenService.deactivateAllTokensForUser(user.getLogin());
  319. } catch (Exception e) {
  320. log.error("", e);
  321. }
  322. }
  323. isDirty = true;
  324. }
  325. final Boolean verified = model.isVerified();
  326. if (verified != null && verified != user.isVerified()) {
  327. user.setVerified(verified);
  328. isDirty = true;
  329. }
  330. if (!isDirty) {
  331. return new ResponseEntity<>(NOT_MODIFIED);
  332. }
  333. try {
  334. getUserManagementService().save(user, getSessionUser(), false, new EventDetails(EventUtils.CATEGORY.DATA, EventUtils.TYPE.WEB_SERVICE, Event.Modified, "", ""));
  335. if (BooleanUtils.toBooleanDefaultIfNull(model.isVerified(), false) && BooleanUtils.toBooleanDefaultIfNull(model.isEnabled(), false) && (!oldEnabledFlag || !oldVerifiedFlag)) {
  336. //When a user is enabled and verified, send a new user email
  337. try {
  338. AdminUtils.sendNewUserEmailMessage(user.getUsername(), user.getEmail());
  339. } catch (Exception e) {
  340. log.error("", e);
  341. }
  342. }
  343. return new ResponseEntity<>(_factory.getUser(user), OK);
  344. } catch (Exception e) {
  345. log.error("Error occurred modifying user '{}'", user.getUsername(), e);
  346. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  347. }
  348. }
  349. @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")
  350. @ApiResponses({@ApiResponse(code = 200, message = "User successfully invalidated."),
  351. @ApiResponse(code = 304, message = "Indicated user has no active sessions, so no action was taken."),
  352. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  353. @ApiResponse(code = 403, message = "Not authorized to invalidate this user's sessions."),
  354. @ApiResponse(code = 404, message = "User not found."),
  355. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  356. @XapiRequestMapping(value = "active/{username}", produces = APPLICATION_JSON_VALUE, method = DELETE, restrictTo = User)
  357. 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) {
  358. final UserI user;
  359. final String currentSessionId;
  360. if (StringUtils.equals(getSessionUser().getUsername(), username)) {
  361. user = getSessionUser();
  362. currentSessionId = current.getId();
  363. } else {
  364. try {
  365. user = getUserManagementService().getUser(username);
  366. if (user == null) {
  367. return new ResponseEntity<>(NOT_FOUND);
  368. }
  369. currentSessionId = null;
  370. } catch (UserInitException e) {
  371. log.error("An error occurred initializing the user " + username, e);
  372. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  373. } catch (UserNotFoundException e) {
  374. return new ResponseEntity<>(NOT_FOUND);
  375. }
  376. }
  377. final Object located = locatePrincipalByUsername(user.getUsername());
  378. if (located == null) {
  379. return new ResponseEntity<>(NOT_MODIFIED);
  380. }
  381. final List<SessionInformation> sessions = _sessionRegistry.getAllSessions(located, false);
  382. if (sessions.size() == 0) {
  383. return new ResponseEntity<>(NOT_MODIFIED);
  384. }
  385. final List<String> sessionIds = Lists.transform(sessions, INFO_TO_ID_INVALIDATOR_FUNCTION);
  386. sessionIds.remove(currentSessionId);
  387. return new ResponseEntity<>(sessionIds, OK);
  388. }
  389. @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)
  390. @ApiResponses({@ApiResponse(code = 200, message = "User enabled status successfully retrieved."),
  391. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  392. @ApiResponse(code = 403, message = "Not authorized to get whether this user is enabled."),
  393. @ApiResponse(code = 404, message = "User not found."),
  394. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  395. @XapiRequestMapping(value = "{username}/enabled", produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = User)
  396. 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) {
  397. try {
  398. final UserI user = getUserManagementService().getUser(username);
  399. if (user == null) {
  400. return new ResponseEntity<>(NOT_FOUND);
  401. }
  402. return new ResponseEntity<>(user.isEnabled(), OK);
  403. } catch (UserInitException e) {
  404. log.error("An error occurred initializing the user " + username, e);
  405. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  406. } catch (UserNotFoundException e) {
  407. return new ResponseEntity<>(NOT_FOUND);
  408. }
  409. }
  410. @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)
  411. @ApiResponses({@ApiResponse(code = 200, message = "User enabled status successfully set."),
  412. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  413. @ApiResponse(code = 403, message = "Not authorized to enable or disable this user."),
  414. @ApiResponse(code = 404, message = "User not found."),
  415. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  416. @XapiRequestMapping(value = "{username}/enabled/{flag}", produces = APPLICATION_JSON_VALUE, method = PUT, restrictTo = Admin)
  417. 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) {
  418. try {
  419. final UserI user = getUserManagementService().getUser(username);
  420. boolean oldEnabledFlag = user.isEnabled();
  421. user.setEnabled(flag);
  422. try {
  423. getUserManagementService().save(user, getSessionUser(), false, new EventDetails(EventUtils.CATEGORY.DATA, EventUtils.TYPE.WEB_SERVICE, flag ? Event.Enabled : Event.Disabled, "", ""));
  424. if (flag && !oldEnabledFlag && user.isVerified()) {
  425. //When a user is enabled, send a new user email if they're also verified
  426. try {
  427. AdminUtils.sendNewUserEmailMessage(username, user.getEmail());
  428. } catch (Exception e) {
  429. log.error("", e);
  430. }
  431. }
  432. return new ResponseEntity<>(OK);
  433. } catch (Exception e) {
  434. log.error("Error occurred " + (flag ? "enabling" : "disabling") + " user " + user.getLogin());
  435. }
  436. return new ResponseEntity<>(false, INTERNAL_SERVER_ERROR);
  437. } catch (UserInitException e) {
  438. log.error("An error occurred initializing the user " + username, e);
  439. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  440. } catch (UserNotFoundException e) {
  441. return new ResponseEntity<>(NOT_FOUND);
  442. }
  443. }
  444. @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)
  445. @ApiResponses({@ApiResponse(code = 200, message = "User verified status successfully retrieved."),
  446. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  447. @ApiResponse(code = 403, message = "Not authorized to view this user."),
  448. @ApiResponse(code = 404, message = "User not found."),
  449. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  450. @XapiRequestMapping(value = "{username}/verified", produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = User)
  451. 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) {
  452. try {
  453. final UserI user = getUserManagementService().getUser(username);
  454. if (user == null) {
  455. return new ResponseEntity<>(NOT_FOUND);
  456. }
  457. return new ResponseEntity<>(user.isVerified(), OK);
  458. } catch (UserInitException e) {
  459. log.error("An error occurred initializing the user " + username, e);
  460. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  461. } catch (UserNotFoundException e) {
  462. return new ResponseEntity<>(NOT_FOUND);
  463. }
  464. }
  465. @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)
  466. @ApiResponses({@ApiResponse(code = 200, message = "User verified status successfully set."),
  467. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  468. @ApiResponse(code = 403, message = "Not authorized to verify or un-verify this user."),
  469. @ApiResponse(code = 404, message = "User not found."),
  470. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  471. @XapiRequestMapping(value = "{username}/verified/{flag}", produces = APPLICATION_JSON_VALUE, method = PUT, restrictTo = Admin)
  472. 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) {
  473. try {
  474. final UserI user = getUserManagementService().getUser(username);
  475. if (user == null) {
  476. return new ResponseEntity<>(NOT_FOUND);
  477. }
  478. boolean oldVerifiedFlag = user.isVerified();
  479. user.setVerified(flag);
  480. try {
  481. getUserManagementService().save(user, getSessionUser(), false, new EventDetails(EventUtils.CATEGORY.DATA, EventUtils.TYPE.WEB_SERVICE, flag ? Event.Enabled : Event.Disabled, "", ""));
  482. if (flag && !oldVerifiedFlag && user.isEnabled()) {
  483. //When a user is verified, send a new user email if they're also enabled
  484. try {
  485. AdminUtils.sendNewUserEmailMessage(username, user.getEmail());
  486. } catch (Exception e) {
  487. log.error("", e);
  488. }
  489. }
  490. return new ResponseEntity<>(OK);
  491. } catch (Exception e) {
  492. log.error("Error occurred " + (flag ? "enabling" : "disabling") + " user " + user.getLogin());
  493. }
  494. return new ResponseEntity<>(false, INTERNAL_SERVER_ERROR);
  495. } catch (UserInitException e) {
  496. log.error("An error occurred initializing the user " + username, e);
  497. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  498. } catch (UserNotFoundException e) {
  499. return new ResponseEntity<>(NOT_FOUND);
  500. }
  501. }
  502. @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)
  503. @ApiResponses({@ApiResponse(code = 200, message = "User roles successfully retrieved."),
  504. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  505. @ApiResponse(code = 403, message = "Not authorized to view this user."),
  506. @ApiResponse(code = 404, message = "User not found."),
  507. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  508. @XapiRequestMapping(value = "{username}/roles", produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = User)
  509. 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) {
  510. final Collection<String> roles = getUserRoles(username);
  511. return roles != null ? new ResponseEntity<>(roles, OK) : new ResponseEntity<Collection<String>>(FORBIDDEN);
  512. }
  513. @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")
  514. @ApiResponses({@ApiResponse(code = 200, message = "All specified user roles successfully added."),
  515. @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."),
  516. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  517. @ApiResponse(code = 403, message = "Not authorized to add roles to 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 = APPLICATION_JSON_VALUE, method = PUT, restrictTo = Admin)
  521. public ResponseEntity<Collection<String>> usersIdAddRoles(@ApiParam(value = "ID of the user to add a role to", required = true) @PathVariable("username") @Username final String username,
  522. @ApiParam(value = "The user's new roles.", required = true) @RequestBody final List<String> roles) {
  523. final Collection<String> failed = new ArrayList<>();
  524. try {
  525. final UserI user = getUserManagementService().getUser(username);
  526. if (user == null) {
  527. return new ResponseEntity<>(NOT_FOUND);
  528. }
  529. for (final String role : roles) {
  530. try {
  531. getRoleHolder().addRole(getSessionUser(), user, role);
  532. } catch (Exception e) {
  533. failed.add(role);
  534. log.error("Error occurred adding role " + role + " to user " + user.getLogin() + ".", e);
  535. }
  536. }
  537. } catch (UserInitException e) {
  538. log.error("An error occurred initializing the user " + username, e);
  539. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  540. } catch (UserNotFoundException e) {
  541. return new ResponseEntity<>(NOT_FOUND);
  542. }
  543. if (failed.size() == 0) {
  544. return new ResponseEntity<>(OK);
  545. }
  546. return new ResponseEntity<>(failed, ACCEPTED);
  547. }
  548. @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")
  549. @ApiResponses({@ApiResponse(code = 200, message = "All specified user roles successfully removed."),
  550. @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."),
  551. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  552. @ApiResponse(code = 403, message = "Not authorized to remove roles from this user."),
  553. @ApiResponse(code = 404, message = "User not found."),
  554. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  555. @XapiRequestMapping(value = "{username}/roles", produces = APPLICATION_JSON_VALUE, method = DELETE, restrictTo = Admin)
  556. public ResponseEntity<Collection<String>> usersIdRemoveRoles(@ApiParam(value = "ID of the user to remove role from", required = true) @PathVariable("username") @Username final String username,
  557. @ApiParam(value = "The roles to be removed.", required = true) @RequestBody final List<String> roles) {
  558. final Collection<String> failed = new ArrayList<>();
  559. try {
  560. final UserI user = getUserManagementService().getUser(username);
  561. if (user == null) {
  562. return new ResponseEntity<>(NOT_FOUND);
  563. }
  564. for (final String role : roles) {
  565. try {
  566. getRoleHolder().deleteRole(getSessionUser(), user, role);
  567. } catch (Exception e) {
  568. failed.add(role);
  569. log.error("Error occurred remove role " + role + " from user " + user.getLogin() + ".", e);
  570. }
  571. }
  572. } catch (UserInitException e) {
  573. log.error("An error occurred initializing the user " + username, e);
  574. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  575. } catch (UserNotFoundException e) {
  576. return new ResponseEntity<>(NOT_FOUND);
  577. }
  578. if (failed.size() == 0) {
  579. return new ResponseEntity<>(OK);
  580. }
  581. return new ResponseEntity<>(failed, ACCEPTED);
  582. }
  583. @ApiOperation(value = "Adds a role to a user.", notes = "Assigns a new role to a user.", response = Boolean.class)
  584. @ApiResponses({@ApiResponse(code = 200, message = "User role successfully added."),
  585. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  586. @ApiResponse(code = 403, message = "Not authorized to add a role to this user."),
  587. @ApiResponse(code = 404, message = "User not found."),
  588. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  589. @XapiRequestMapping(value = "{username}/roles/{role}", produces = APPLICATION_JSON_VALUE, method = PUT, restrictTo = Admin)
  590. public ResponseEntity<Boolean> usersIdAddRole(@ApiParam(value = "ID of the user to add a role to", required = true) @PathVariable("username") @Username final String username,
  591. @ApiParam(value = "The user's new role.", required = true) @PathVariable("role") final String role) {
  592. try {
  593. final UserI user = getUserManagementService().getUser(username);
  594. if (user == null) {
  595. return new ResponseEntity<>(NOT_FOUND);
  596. }
  597. try {
  598. getRoleHolder().addRole(getSessionUser(), user, role);
  599. return new ResponseEntity<>(OK);
  600. } catch (Exception e) {
  601. log.error("Error occurred adding role " + role + " to user " + user.getLogin() + ".");
  602. }
  603. return new ResponseEntity<>(false, INTERNAL_SERVER_ERROR);
  604. } catch (UserInitException e) {
  605. log.error("An error occurred initializing the user " + username, e);
  606. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  607. } catch (UserNotFoundException e) {
  608. return new ResponseEntity<>(NOT_FOUND);
  609. }
  610. }
  611. @ApiOperation(value = "Remove a user's role.", notes = "Removes a user's role.", response = Boolean.class)
  612. @ApiResponses({@ApiResponse(code = 200, message = "User role successfully removed."),
  613. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  614. @ApiResponse(code = 403, message = "Not authorized to remove a role from this user."),
  615. @ApiResponse(code = 404, message = "User not found."),
  616. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  617. @XapiRequestMapping(value = "{username}/roles/{role}", produces = APPLICATION_JSON_VALUE, method = DELETE, restrictTo = Admin)
  618. public ResponseEntity<Boolean> usersIdRemoveRole(@ApiParam(value = "ID of the user to delete a role from", required = true) @PathVariable("username") @Username final String username,
  619. @ApiParam(value = "The user role to delete.", required = true) @PathVariable("role") String role) {
  620. try {
  621. final UserI user = getUserManagementService().getUser(username);
  622. if (user == null) {
  623. return new ResponseEntity<>(NOT_FOUND);
  624. }
  625. try {
  626. getRoleHolder().deleteRole(getSessionUser(), user, role);
  627. return new ResponseEntity<>(OK);
  628. } catch (Exception e) {
  629. log.error("Error occurred removing role " + role + " from user " + user.getLogin() + ".");
  630. }
  631. return new ResponseEntity<>(false, INTERNAL_SERVER_ERROR);
  632. } catch (UserInitException e) {
  633. log.error("An error occurred initializing the user " + username, e);
  634. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  635. } catch (UserNotFoundException e) {
  636. return new ResponseEntity<>(NOT_FOUND);
  637. }
  638. }
  639. @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)
  640. @ApiResponses({@ApiResponse(code = 200, message = "User groups successfully retrieved."),
  641. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  642. @ApiResponse(code = 403, message = "Not authorized to get the groups for this user."),
  643. @ApiResponse(code = 404, message = "User not found."),
  644. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  645. @XapiRequestMapping(value = "{username}/groups", produces = APPLICATION_JSON_VALUE, method = GET, restrictTo = User)
  646. 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) {
  647. try {
  648. final UserI user = getUserManagementService().getUser(username);
  649. if (user == null) {
  650. return new ResponseEntity<>(NOT_FOUND);
  651. }
  652. Map<String, UserGroupI> groups = Groups.getGroupsForUser(user);
  653. return new ResponseEntity<>(groups.keySet(), OK);
  654. } catch (UserInitException e) {
  655. log.error("An error occurred initializing the user " + username, e);
  656. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  657. } catch (UserNotFoundException e) {
  658. return new ResponseEntity<>(NOT_FOUND);
  659. }
  660. }
  661. @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")
  662. @ApiResponses({@ApiResponse(code = 200, message = "User successfully added for all specified groups."),
  663. @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."),
  664. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  665. @ApiResponse(code = 403, message = "Not authorized to add this user to groups."),
  666. @ApiResponse(code = 404, message = "User not found."),
  667. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  668. @XapiRequestMapping(value = "{username}/groups", produces = APPLICATION_JSON_VALUE, method = PUT, restrictTo = Authorizer)
  669. @AuthDelegate(UserGroupXapiAuthorization.class)
  670. 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,
  671. @ApiParam(value = "The groups to which the user should be added.", required = true) @RestUserGroup @RequestBody final List<String> groups) {
  672. final Collection<String> failed = new ArrayList<>();
  673. try {
  674. final UserI user = getUserManagementService().getUser(username);
  675. if (user == null) {
  676. return new ResponseEntity<>(NOT_FOUND);
  677. }
  678. for (final String group : groups) {
  679. try {
  680. Groups.addUserToGroup(group, user, getSessionUser(), EventUtils.ADMIN_EVENT(getSessionUser()));
  681. } catch (Exception e) {
  682. failed.add(group);
  683. log.error("Error occurred adding user " + user.getLogin() + " to group " + group + ".", e);
  684. }
  685. }
  686. } catch (UserInitException e) {
  687. log.error("An error occurred initializing the user " + username, e);
  688. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  689. } catch (UserNotFoundException e) {
  690. return new ResponseEntity<>(NOT_FOUND);
  691. }
  692. if (failed.size() == 0) {
  693. return new ResponseEntity<>(OK);
  694. }
  695. return new ResponseEntity<>(failed, ACCEPTED);
  696. }
  697. @ApiOperation(value = "Removes the user from one or more groups.", notes = "Removes the user from one or more groups.", response = String.class, responseContainer = "List")
  698. @ApiResponses({@ApiResponse(code = 200, message = "User successfully removed from all specified groups."),
  699. @ApiResponse(code = 202, message = "User was successfully removed from some of the specified groups, but some may have failed. Check the return value for groups that the service was unable to remove."),
  700. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  701. @ApiResponse(code = 403, message = "Not authorized to remove this user from groups."),
  702. @ApiResponse(code = 404, message = "User not found."),
  703. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  704. @XapiRequestMapping(value = "{username}/groups", produces = APPLICATION_JSON_VALUE, method = DELETE, restrictTo = User)
  705. public ResponseEntity<Collection<String>> usersIdRemoveGroups(@ApiParam(value = "ID of the user to remove role from", required = true) @PathVariable("username") @Username final String username,
  706. @ApiParam(value = "The groups from which the user should be removed.", required = true) @RequestBody final List<String> groups) {
  707. final Collection<String> failed = new ArrayList<>();
  708. try {
  709. final UserI user = getUserManagementService().getUser(username);
  710. if (user == null) {
  711. return new ResponseEntity<>(NOT_FOUND);
  712. }
  713. for (final String group : groups) {
  714. try {
  715. Groups.removeUserFromGroup(user, getSessionUser(), group, EventUtils.ADMIN_EVENT(getSessionUser()));
  716. } catch (Exception e) {
  717. failed.add(group);
  718. log.error("Error occurred removing group " + group + " from user " + user.getLogin() + ".", e);
  719. }
  720. }
  721. } catch (UserInitException e) {
  722. log.error("An error occurred initializing the user " + username, e);
  723. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  724. } catch (UserNotFoundException e) {
  725. return new ResponseEntity<>(NOT_FOUND);
  726. }
  727. if (failed.size() == 0) {
  728. return new ResponseEntity<>(OK);
  729. }
  730. return new ResponseEntity<>(failed, ACCEPTED);
  731. }
  732. @ApiOperation(value = "Adds a user to a group.", notes = "Assigns user to a group.", response = Boolean.class)
  733. @ApiResponses({@ApiResponse(code = 200, message = "User successfully added to group."),
  734. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  735. @ApiResponse(code = 403, message = "Not authorized to assign this user to groups."),
  736. @ApiResponse(code = 404, message = "User not found."),
  737. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  738. @XapiRequestMapping(value = "{username}/groups/{group}", produces = APPLICATION_JSON_VALUE, method = PUT, restrictTo = Authorizer)
  739. @AuthDelegate(UserGroupXapiAuthorization.class)
  740. public ResponseEntity<Boolean> usersIdAddGroup(@ApiParam(value = "ID of the user to add to a group", required = true) @PathVariable("username") @Username final String username, @ApiParam(value = "The user's new group.", required = true) @RestUserGroup @PathVariable("group") final String group) {
  741. try {
  742. final UserI user = getUserManagementService().getUser(username);
  743. if (user == null) {
  744. return new ResponseEntity<>(NOT_FOUND);
  745. }
  746. if (user.getID().equals(Users.getGuest().getID())) {
  747. return new ResponseEntity<>(PRECONDITION_FAILED);
  748. }
  749. try {
  750. Groups.addUserToGroup(group, user, getSessionUser(), null);
  751. return new ResponseEntity<>(OK);
  752. } catch (Exception e) {
  753. log.error("Error occurred adding user " + user.getLogin() + " to group " + group + ".");
  754. }
  755. return new ResponseEntity<>(false, INTERNAL_SERVER_ERROR);
  756. } catch (UserInitException e) {
  757. log.error("An error occurred initializing the user " + username, e);
  758. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  759. } catch (UserNotFoundException e) {
  760. return new ResponseEntity<>(NOT_FOUND);
  761. }
  762. }
  763. @ApiOperation(value = "Removes a user from a group.", notes = "Removes a user from a group.", response = Boolean.class)
  764. @ApiResponses({@ApiResponse(code = 200, message = "User's group successfully removed."),
  765. @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
  766. @ApiResponse(code = 403, message = "Not authorized to remove this user from groups."),
  767. @ApiResponse(code = 404, message = "User not found."),
  768. @ApiResponse(code = 500, message = "An unexpected error occurred.")})
  769. @XapiRequestMapping(value = "{username}/groups/{group}", produces = APPLICATION_JSON_VALUE, method = DELETE, restrictTo = User)
  770. public ResponseEntity<Boolean> usersIdRemoveGroup(@ApiParam(value = "ID of the user to remove from group", required = true) @PathVariable("username") @Username final String username, @ApiParam(value = "The group to remove the user from.", required = true) @PathVariable("group") final String group) {
  771. try {
  772. final UserI user = getUserManagementService().getUser(username);
  773. if (user == null) {
  774. return new ResponseEntity<>(NOT_FOUND);
  775. }
  776. try {
  777. Groups.removeUserFromGroup(user, getSessionUser(), group, null);
  778. return new ResponseEntity<>(OK);
  779. } catch (Exception e) {
  780. log.error("Error occurred removing user " + user.getLogin() + " from group " + group + ".");
  781. }
  782. return new ResponseEntity<>(false, INTERNAL_SERVER_ERROR);
  783. } catch (UserInitException e) {
  784. log.error("An error occurred initializing the user " + username, e);
  785. return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
  786. } catch (UserNotFoundException e) {
  787. return new ResponseEntity<>(NOT_FOUND);
  788. }
  789. }
  790. @ApiOperation(value = "Returns list of projects that user has edit access.", notes = "Returns list of projects that user has edit access.", response = String.class, responseContainer = "List")
  791. @XapiRequestMapping(value = "projects", produces = APPLICATION_JSON_VALUE, method = GET)
  792. public ResponseEntity<List<String>> getProjectsByUser() {
  793. return new ResponseEntity<>(_permissionsService.getUserEditableProjects(getSessionUser()), OK);
  794. }
  795. @SuppressWarnings("unused")
  796. public static class Event {
  797. public static String Added = "Added User";
  798. public static String Disabled = "Disabled User";
  799. public static String Enabled = "Enabled User";
  800. public static String DisabledForInactivity = "Disabled User Due To Inactivity";
  801. public static String Modified = "Modified User";
  802. public static String ModifiedEmail = "Modified User Email";
  803. public static String ModifiedPassword = "Modified User Password";
  804. public static String ModifiedPermissions = "Modified User Permissions";
  805. public static String ModifiedSettings = "Modified User Settings";
  806. public static String VerifiedEmail = "Verified User Email";
  807. }
  808. @Nullable
  809. private Object locatePrincipalByUsername(final String username) {
  810. Object located = null;
  811. for (final Object principal : _sessionRegistry.getAllPrincipals()) {
  812. if (principal instanceof String && username.equals(principal)) {
  813. located = principal;
  814. break;
  815. } else if (principal instanceof UserDetails && username.equals(((UserDetails) principal).getUsername())) {
  816. located = principal;
  817. break;
  818. } else if (username.equals(principal.toString())) {
  819. located = principal;
  820. break;
  821. }
  822. }
  823. return located;
  824. }
  825. private void validateUser(final User model) throws DataFormatException, ResourceAlreadyExistsException {
  826. final DataFormatException exception = new DataFormatException();
  827. exception.validateBlankAndRegex("username", model.getUsername(), Patterns.USERNAME);
  828. exception.validateBlankAndRegex("email", model.getEmail(), Patterns.EMAIL);
  829. exception.validateBlankAndRegex("firstName", model.getFirstName(), Patterns.LIMIT_XSS_CHARS);
  830. exception.validateBlankAndRegex("lastName", model.getLastName(), Patterns.LIMIT_XSS_CHARS);
  831. if (exception.hasDataFormatErrors()) {
  832. throw exception;
  833. }
  834. final String username = model.getUsername();
  835. try {
  836. final UserI user = getUserManagementService().getUser(username);
  837. if (user != null) {
  838. throw new ResourceAlreadyExistsException("user", username);
  839. }
  840. } catch (UserNotFoundException ignored) {
  841. // This is actually what we want.
  842. } catch (UserInitException e) {
  843. log.error("An error occurred trying to check for duplicate username", e);
  844. }
  845. }
  846. private static class SessionInfoToIdFunction implements Function<SessionInformation, String> {
  847. SessionInfoToIdFunction(final boolean invalidate) {
  848. _invalidate = invalidate;
  849. }
  850. @Override
  851. public String apply(final SessionInformation sessionInformation) {
  852. if (_invalidate) {
  853. sessionInformation.expireNow();
  854. }
  855. return sessionInformation.getSessionId();
  856. }
  857. private final boolean _invalidate;
  858. }
  859. private static final SessionInfoToIdFunction INFO_TO_ID_FUNCTION = new SessionInfoToIdFunction(false);
  860. private static final SessionInfoToIdFunction INFO_TO_ID_INVALIDATOR_FUNCTION = new SessionInfoToIdFunction(true);
  861. private final SessionRegistry _sessionRegistry;
  862. private final AliasTokenService _aliasTokenService;
  863. private final PermissionsServiceI _permissionsService;
  864. private final UserFactory _factory;
  865. private final NamedParameterJdbcTemplate _jdbcTemplate;
  866. }