PageRenderTime 83ms CodeModel.GetById 2ms app.highlight 70ms RepoModel.GetById 2ms app.codeStats 0ms

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

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

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