Merge authors: Jim Grace (jimgrace) ------------------------------------------------------------ revno: 15421 [merge] committer: jimgr...@gmail.com branch nick: dhis2 timestamp: Mon 2014-05-26 15:10:33 -0400 message: Add to webapi: POST /users/invite modified: dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java
-- lp:dhis2 https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk Your team DHIS 2 developers is subscribed to branch lp:dhis2. To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java 2014-03-27 08:25:39 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java 2014-05-24 18:16:41 +0000 @@ -110,25 +110,25 @@ // SecurityService implementation // ------------------------------------------------------------------------- - public boolean prepareUserForInvite( UserCredentials credentials ) + public boolean prepareUserForInvite( User user ) { - if ( credentials == null || credentials.getUser() == null ) + if ( user == null || user.getUserCredentials() == null ) { return false; } - if ( credentials.getUsername().isEmpty() ) + if ( user.getUsername() == null || user.getUsername().isEmpty() ) { String username = "user_invitation_" + CodeGenerator.generateCode( INVITED_USERNAME_UNIQUE_LENGTH ); - credentials.setUsername( username ); + user.getUserCredentials().setUsername( username ); } String rawPassword = CodeGenerator.generateCode( INVITED_USER_PASSWORD_LENGTH ); - credentials.getUser().setSurname( "(TBD)" ); - credentials.getUser().setFirstName( "(TBD)" ); - credentials.setPassword( passwordManager.encodePassword( credentials.getUsername(), rawPassword ) ); + user.setSurname( "(TBD)" ); + user.setFirstName( "(TBD)" ); + user.getUserCredentials().setPassword( passwordManager.encodePassword( user.getUsername(), rawPassword ) ); return true; } === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java 2014-03-18 08:10:10 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/SecurityService.java 2014-05-24 18:16:41 +0000 @@ -29,6 +29,7 @@ */ import org.hisp.dhis.common.IdentifiableObject; +import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserCredentials; /** @@ -40,10 +41,10 @@ * Sets information for a user who will be invited by email to finish * setting up their user account. * - * @param credentials the credentials of the user to invite. + * @param user the user to invite. * @return true if the invitation was sent, otherwise false. */ - boolean prepareUserForInvite( UserCredentials credentials ); + boolean prepareUserForInvite( User user ); /** * Invokes the initRestore method and dispatches email messages with === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java 2014-05-22 12:40:24 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java 2014-05-26 19:10:33 +0000 @@ -29,6 +29,7 @@ */ import com.google.common.collect.Lists; +import org.apache.struts2.ServletActionContext; import org.hisp.dhis.webapi.controller.AbstractCrudController; import org.hisp.dhis.webapi.controller.WebMetaData; import org.hisp.dhis.webapi.controller.WebOptions; @@ -39,7 +40,12 @@ import org.hisp.dhis.hibernate.exception.UpdateAccessDeniedException; import org.hisp.dhis.importexport.ImportStrategy; import org.hisp.dhis.security.PasswordManager; +import org.hisp.dhis.security.RestoreOptions; +import org.hisp.dhis.security.SecurityService; +import org.hisp.dhis.setting.SystemSettingManager; import org.hisp.dhis.user.User; +import org.hisp.dhis.user.UserGroup; +import org.hisp.dhis.user.UserGroupService; import org.hisp.dhis.user.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -59,6 +65,8 @@ import java.util.List; import java.util.Map; +import static org.hisp.dhis.setting.SystemSettingManager.KEY_ONLY_MANAGE_WITHIN_USER_GROUPS; + /** * @author Morten Olav Hansen <morte...@gmail.com> */ @@ -68,13 +76,23 @@ extends AbstractCrudController<User> { public static final String RESOURCE_PATH = "/users"; + public static final String INVITE_PATH = "/invite"; @Autowired private UserService userService; @Autowired + private UserGroupService userGroupService; + + @Autowired private PasswordManager passwordManager; + @Autowired + private SecurityService securityService; + + @Autowired + private SystemSettingManager systemSettingManager; + @Override @PreAuthorize( "hasRole('ALL') or hasRole('F_USER_VIEW')" ) public String getObjectList( @RequestParam Map<String, String> parameters, Model model, HttpServletResponse response, HttpServletRequest request ) @@ -130,38 +148,34 @@ @RequestMapping( method = RequestMethod.POST, consumes = { "application/xml", "text/xml" } ) public void postXmlObject( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception { - if ( !aclService.canCreate( currentUserService.getCurrentUser(), getEntityClass() ) ) - { - throw new CreateAccessDeniedException( "You don't have the proper permissions to create this object." ); - } - User user = renderService.fromXml( request.getInputStream(), getEntityClass() ); - String encodePassword = passwordManager.encodePassword( user.getUsername(), - user.getUserCredentials().getPassword() ); - user.getUserCredentials().setPassword( encodePassword ); - - ImportTypeSummary summary = importService.importObject( currentUserService.getCurrentUser().getUid(), user, ImportStrategy.CREATE ); - renderService.toJson( response.getOutputStream(), summary ); + createUser( user, response ); } @Override @RequestMapping( method = RequestMethod.POST, consumes = "application/json" ) public void postJsonObject( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception { - if ( !aclService.canCreate( currentUserService.getCurrentUser(), getEntityClass() ) ) - { - throw new CreateAccessDeniedException( "You don't have the proper permissions to create this object." ); - } - - User user = renderService.fromJson( request.getInputStream(), getEntityClass() ); - - String encodePassword = passwordManager.encodePassword( user.getUsername(), - user.getUserCredentials().getPassword() ); - user.getUserCredentials().setPassword( encodePassword ); - - ImportTypeSummary summary = importService.importObject( currentUserService.getCurrentUser().getUid(), user, ImportStrategy.CREATE ); - renderService.toJson( response.getOutputStream(), summary ); + User user = renderService.fromJson( request.getInputStream(), getEntityClass() ); + + createUser( user, response ); + } + + @RequestMapping( value = INVITE_PATH, method = RequestMethod.POST, consumes = { "application/xml", "text/xml" } ) + public void postXmlInvite( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception + { + User user = renderService.fromXml( request.getInputStream(), getEntityClass() ); + + inviteUser( user, response ); + } + + @RequestMapping( value = INVITE_PATH, method = RequestMethod.POST, consumes = "application/json" ) + public void postJsonInvite( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception + { + User user = renderService.fromJson( request.getInputStream(), getEntityClass() ); + + inviteUser( user, response ); } //-------------------------------------------------------------------------- @@ -230,4 +244,128 @@ ImportTypeSummary summary = importService.importObject( currentUserService.getCurrentUser().getUid(), parsed, ImportStrategy.UPDATE ); renderService.toJson( response.getOutputStream(), summary ); } + + //-------------------------------------------------------------------------- + // Supportive methods + //-------------------------------------------------------------------------- + + /** + * Creates a user invitation and invites the user + * + * @param user user object parsed from the POST request + * @param response response for created user invitation + * @throws Exception + */ + private void inviteUser( User user, HttpServletResponse response ) throws Exception + { + RestoreOptions restoreOptions = user.getUsername() == null || user.getUsername().isEmpty() ? + RestoreOptions.INVITE_WITH_USERNAME_CHOICE : RestoreOptions.INVITE_WITH_DEFINED_USERNAME; + + securityService.prepareUserForInvite( user ); + + createUser( user, response ); + + securityService.sendRestoreMessage( user.getUserCredentials(), + ContextUtils.getContextPath( ServletActionContext.getRequest() ), restoreOptions ); + } + + /** + * Creates a user + * + * @param user user object parsed from the POST request + * @param response response for created user + * @throws Exception + */ + private void createUser( User user, HttpServletResponse response ) throws Exception + { + if ( currentUserService.getCurrentUser() == null ) + { + throw new CreateAccessDeniedException( "Internal error: currentUserService.getCurrentUser() returns null." ); + } + + if ( !aclService.canCreate( currentUserService.getCurrentUser(), getEntityClass() ) ) + { + throw new CreateAccessDeniedException( "You don't have the proper permissions to create this object." ); + } + + checkUserGroups( user ); + + user.getUserCredentials().getCogsDimensionConstraints().addAll( + currentUserService.getCurrentUser().getUserCredentials().getCogsDimensionConstraints() ); + + String encodePassword = passwordManager.encodePassword( user.getUsername(), + user.getUserCredentials().getPassword() ); + user.getUserCredentials().setPassword( encodePassword ); + + ImportTypeSummary summary = importService.importObject( currentUserService.getCurrentUser().getUid(), user, ImportStrategy.CREATE ); + + renderService.toJson( response.getOutputStream(), summary ); + + addUserGroups( user ); + } + + /** + * Before adding the user, checks to see that any specified user groups + * exist. Also checks to see that user can be created by the current + * user, if it is required that the current user have read/write access + * to a user group that is assigned to the new user. + * + * @param user user object parsed from the POST request + */ + private void checkUserGroups( User user ) + { + boolean writeGroupRequired = (Boolean) systemSettingManager.getSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, false ); + + boolean writeGroupFound = false; + + if ( currentUserService.getCurrentUser() != null && user.getGroups() != null ) + { + for ( UserGroup ug : user.getGroups() ) + { + UserGroup group = userGroupService.getUserGroup( ug.getUid() ); + + if ( group == null ) + { + throw new UpdateAccessDeniedException( "Can't add user: Can't find user group with UID = " + ug.getUid() ); + } + + if ( writeGroupRequired && securityService.canWrite( group ) ) + { + writeGroupFound = true; + + break; + } + } + } + + if ( writeGroupRequired && !writeGroupFound ) + { + throw new CreateAccessDeniedException( "The new user must be assigned to a user group to which you have write access." ); + } + } + + /** + * Adds user groups (if any) to the newly-created user + * + * @param user user object (including user groups) parsed from the POST request + */ + private void addUserGroups( User user ) + { + if ( user.getGroups() != null ) + { + boolean writeGroupRequired = (Boolean) systemSettingManager.getSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, false ); + + for ( UserGroup ug : new ArrayList<UserGroup>( user.getGroups() ) ) + { + UserGroup group = userGroupService.getUserGroup( ug.getUid() ); + + if ( group != null && ( !writeGroupRequired || securityService.canWrite( group ) ) ) + { + group.addUser( user ); + + userGroupService.updateUserGroup( group ); + } + } + } + } } === modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java' --- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java 2014-05-22 12:40:24 +0000 +++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java 2014-05-26 19:10:33 +0000 @@ -342,7 +342,7 @@ userCredentials.setUsername( inviteUsername ); user.setEmail( inviteEmail ); - securityService.prepareUserForInvite( userCredentials ); + securityService.prepareUserForInvite( user ); } else {
_______________________________________________ Mailing list: https://launchpad.net/~dhis2-devs Post to : dhis2-devs@lists.launchpad.net Unsubscribe : https://launchpad.net/~dhis2-devs More help : https://help.launchpad.net/ListHelp