← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15277: User administration restrictions

 

------------------------------------------------------------
revno: 15277
committer: jimgrace@xxxxxxxxx
branch nick: dhis2
timestamp: Thu 2014-05-15 09:16:11 -0400
message:
  User administration restrictions
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetAccessSettingsAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemAccessSettings.vm
  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/UpdateUserAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/org/hisp/dhis/user/i18n_module.properties
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml


--
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-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java	2014-05-06 16:34:26 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java	2014-05-15 13:16:11 +0000
@@ -90,6 +90,7 @@
     final String KEY_OPENID_PROVIDER = "keyOpenIdProvider";
     final String KEY_OPENID_PROVIDER_LABEL = "keyOpenIdProviderLabel";
     final String KEY_CAN_GRANT_OWN_USER_AUTHORITY_GROUPS = "keyCanGrantOwnUserAuthorityGroups";
+    final String KEY_ONLY_MANAGE_WITHIN_USER_GROUPS = "keyOnlyManageWithinUserGroups";
     final String KEY_HIDE_UNAPPROVED_DATA_IN_ANALYTICS = "keyHideUnapprovedDataInAnalytics";
     final String KEY_ANALYTICS_MAX_LIMIT = "keyAnalyticsMaxLimit";
 

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserService.java	2014-05-13 17:35:09 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserService.java	2014-05-15 13:16:11 +0000
@@ -83,7 +83,7 @@
     /**
      * Retrieves the User with the given unique identifier.
      *
-     * @param id the identifier of the User to retrieve.
+     * @param uid the identifier of the User to retrieve.
      * @return the User.
      */
     User getUser( String uid );
@@ -278,7 +278,7 @@
     /**
      * Retrieves the UserAuthorityGroup with the given identifier.
      *
-     * @param id the identifier of the UserAuthorityGroup to retrieve.
+     * @param uid the identifier of the UserAuthorityGroup to retrieve.
      * @return the UserAuthorityGroup.
      */
     UserAuthorityGroup getUserAuthorityGroup( String uid );
@@ -301,21 +301,21 @@
     /**
      * Retrieves all UserAuthorityGroups.
      *
-     * @return a Collectio of UserAuthorityGroups.
+     * @return a Collection of UserAuthorityGroups.
      */
     Collection<UserAuthorityGroup> getAllUserAuthorityGroups();
 
     /**
      * Retrieves all UserAuthorityGroups.
      *
-     * @return a Collectio of UserAuthorityGroups.
+     * @return a Collection of UserAuthorityGroups.
      */
     Collection<UserAuthorityGroup> getUserRolesBetween( int first, int max );
 
     /**
      * Retrieves all UserAuthorityGroups.
      *
-     * @return a Collectio of UserAuthorityGroups.
+     * @return a Collection of UserAuthorityGroups.
      */
     Collection<UserAuthorityGroup> getUserRolesBetweenByName( String name, int first, int max );
 

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java	2014-05-13 17:35:09 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java	2014-05-15 13:16:11 +0000
@@ -45,13 +45,17 @@
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.period.PeriodType;
+import org.hisp.dhis.security.SecurityService;
 import org.hisp.dhis.setting.SystemSettingManager;
 import org.hisp.dhis.system.filter.UserAuthorityGroupCanIssueFilter;
-import org.hisp.dhis.system.filter.UserCredentialsCanUpdateFilter;
 import org.hisp.dhis.system.util.DateUtils;
+import org.hisp.dhis.system.util.Filter;
 import org.hisp.dhis.system.util.FilterUtils;
 import org.springframework.transaction.annotation.Transactional;
 
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_CAN_GRANT_OWN_USER_AUTHORITY_GROUPS;
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_ONLY_MANAGE_WITHIN_USER_GROUPS;
+
 /**
  * @author Chau Thu Tran
  */
@@ -93,6 +97,13 @@
         this.currentUserService = currentUserService;
     }
 
+    private SecurityService securityService;
+
+    public void setSecurityService( SecurityService securityService )
+    {
+        this.securityService = securityService;
+    }
+
     private SystemSettingManager systemSettingManager;
 
     public void setSystemSettingManager( SystemSettingManager systemSettingManager )
@@ -522,11 +533,15 @@
 
     public void canUpdateFilter( Collection<UserCredentials> userCredentials )
     {
-        User user = currentUserService.getCurrentUser();
-
-        boolean canGrantOwnUserAuthorityGroups = (Boolean) systemSettingManager.getSystemSetting( KEY_CAN_GRANT_OWN_USER_AUTHORITY_GROUPS, false );
-
-        FilterUtils.filter( userCredentials, new UserCredentialsCanUpdateFilter( user, canGrantOwnUserAuthorityGroups ) );
+        FilterUtils.filter( userCredentials,
+            new Filter<UserCredentials>()
+            {
+                public boolean retain( UserCredentials object )
+                {
+                    return hasAuthorityToUpdateUser( object ) && hasGroupsToUpdateUser( object );
+                }
+            }
+        );
     }
 
     // -------------------------------------------------------------------------
@@ -632,4 +647,59 @@
 
         return months < credentialsExpires;
     }
+
+    // -------------------------------------------------------------------------
+    // Supportive methods
+    // -------------------------------------------------------------------------
+
+    /**
+     * Determines if the current user has all the authorities required to
+     * update a user.
+     *
+     * @param userCredentials The user to be updated.
+     * @return true if current user has authorities, else false.
+     */
+    private boolean hasAuthorityToUpdateUser( UserCredentials userCredentials )
+    {
+        UserCredentials currentUserCredentials = currentUserService.getCurrentUser().getUserCredentials();
+
+        boolean canGrantOwnUserAuthorityGroups = (Boolean) systemSettingManager.getSystemSetting( KEY_CAN_GRANT_OWN_USER_AUTHORITY_GROUPS, false );
+
+        return currentUserCredentials != null && userCredentials != null
+                && currentUserCredentials.canIssueAll( userCredentials.getUserAuthorityGroups(), canGrantOwnUserAuthorityGroups );
+    }
+
+    /**
+     * Determines if the current user read/write access to at least one group
+     * to which the user belongs, if this is a requirement on this system
+     * for updating a user.
+     *
+     * @param userCredentials The user to be updated.
+     * @return true if current user has read/write access to a group to which
+     * the user belongs, or if this requirement is not applicable, else false.
+     */
+    private boolean hasGroupsToUpdateUser( UserCredentials userCredentials )
+    {
+        UserCredentials currentUserCredentials = currentUserService.getCurrentUser().getUserCredentials();
+
+        boolean onlyManageWithinUserGroups = (Boolean) systemSettingManager.getSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, false );
+
+        if ( onlyManageWithinUserGroups && !currentUserCredentials.getAllAuthorities().contains( "ALL" ) )
+        {
+            if ( userCredentials.getUser().getGroups() != null )
+            {
+                for ( UserGroup group : userCredentials.getUser().getGroups() )
+                {
+                    if ( securityService.canWrite( group ) )
+                    {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        return true;
+    }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-05-13 09:42:58 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-05-15 13:16:11 +0000
@@ -589,6 +589,7 @@
     <property name="userCredentialsStore" ref="org.hisp.dhis.user.UserCredentialsStore" />
     <property name="userAuthorityGroupStore" ref="org.hisp.dhis.user.UserAuthorityGroupStore" />
     <property name="currentUserService" ref="org.hisp.dhis.user.CurrentUserService" />
+    <property name="securityService" ref="org.hisp.dhis.security.SecurityService" />
     <property name="systemSettingManager" ref="org.hisp.dhis.setting.SystemSettingManager" />
   </bean>
 

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java	2014-04-30 15:46:01 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java	2014-05-15 13:16:11 +0000
@@ -112,6 +112,7 @@
         map.put( KEY_OPENID_PROVIDER, systemSettingManager.getSystemSetting( KEY_OPENID_PROVIDER ) );
         map.put( KEY_OPENID_PROVIDER_LABEL, systemSettingManager.getSystemSetting( KEY_OPENID_PROVIDER_LABEL ) );
         map.put( KEY_CAN_GRANT_OWN_USER_AUTHORITY_GROUPS, systemSettingManager.getSystemSetting( KEY_CAN_GRANT_OWN_USER_AUTHORITY_GROUPS, false ) );
+        map.put( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, systemSettingManager.getSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, false ) );
 
         map.put( SYSPROP_PORTAL, defaultIfEmpty( System.getProperty( SYSPROP_PORTAL ), String.valueOf( false ) ) );
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetAccessSettingsAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetAccessSettingsAction.java	2014-03-23 18:26:50 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetAccessSettingsAction.java	2014-05-15 13:16:11 +0000
@@ -98,7 +98,7 @@
     {
         this.accountInvite = accountInvite;
     }
-    
+
     private Boolean canGrantOwnUserAuthorityGroups;
 
     public void setCanGrantOwnUserAuthorityGroups( Boolean canGrantOwnUserAuthorityGroups )
@@ -106,6 +106,13 @@
         this.canGrantOwnUserAuthorityGroups = canGrantOwnUserAuthorityGroups;
     }
 
+    private Boolean onlyManageWithinUserGroups;
+
+    public void setOnlyManageWithinUserGroups( Boolean onlyManageWithinUserGroups )
+    {
+        this.onlyManageWithinUserGroups = onlyManageWithinUserGroups;
+    }
+
     private Integer credentialsExpires;
 
     public void setCredentialsExpires( Integer credentialsExpires )
@@ -172,6 +179,7 @@
         systemSettingManager.saveSystemSetting( KEY_ACCOUNT_RECOVERY, accountRecovery );
         systemSettingManager.saveSystemSetting( KEY_ACCOUNT_INVITE, accountInvite );
         systemSettingManager.saveSystemSetting( KEY_CAN_GRANT_OWN_USER_AUTHORITY_GROUPS, canGrantOwnUserAuthorityGroups );
+        systemSettingManager.saveSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, onlyManageWithinUserGroups );
         systemSettingManager.saveSystemSetting( KEY_SELF_REGISTRATION_NO_RECAPTCHA, selfRegistrationNoRecaptcha );
 
         systemSettingManager.saveSystemSetting( KEY_OPENID_PROVIDER, StringUtils.isEmpty( openIdProvider ) ? null : openIdProvider );

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties	2014-05-13 11:15:35 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties	2014-05-15 13:16:11 +0000
@@ -96,6 +96,7 @@
 openid_provider_label=OpenID Provider Label
 openid_provider=OpenID Provider
 allow_users_to_grant_own_user_roles=Allow users to grant own user roles
+users_must_belong_to_a_group_controlled_by_the_user_manager=Users must belong to a group controlled by the user manager
 object_not_deleted_associated_by_objects=Object not deleted because it is associated by objects of type
 analytics_max_limit=Maximum number of analytics records 
 unlimited=Unlimited
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemAccessSettings.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemAccessSettings.vm	2014-03-23 18:26:50 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemAccessSettings.vm	2014-05-15 13:16:11 +0000
@@ -8,6 +8,7 @@
             accountRecovery: jQuery( '#accountRecovery' ).is( ':checked' ),
             accountInvite: jQuery( '#accountInvite' ).is( ':checked' ),
             canGrantOwnUserAuthorityGroups: jQuery( '#canGrantOwnUserAuthorityGroups' ).is( ':checked' ),
+            onlyManageWithinUserGroups: jQuery( '#onlyManageWithinUserGroups' ).is( ':checked' ),
             credentialsExpires: jQuery( '#credentialsExpires' ).val(),
             openIdProvider: jQuery( '#openIdProvider' ).val(),
             openIdProviderLabel: jQuery( '#openIdProviderLabel' ).val()
@@ -68,6 +69,11 @@
     <label for="canGrantOwnUserAuthorityGroups">$i18n.getString( "allow_users_to_grant_own_user_roles" )</label>
 </div>
 
+<div class="setting">
+    <input type="checkbox" id="onlyManageWithinUserGroups" name="onlyManageWithinUserGroups"#if( $keyOnlyManageWithinUserGroups ) checked="checked"#end>
+    <label for="onlyManageWithinUserGroups">$i18n.getString( "users_must_belong_to_a_group_controlled_by_the_user_manager" )</label>
+</div>
+
 <div class="settingLabel">$i18n.getString( "user_credentials_expires" )</div>
 
 <div class="setting">

=== 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-04-08 19:36:25 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java	2014-05-15 13:16:11 +0000
@@ -38,15 +38,18 @@
 import org.hisp.dhis.attribute.AttributeService;
 import org.hisp.dhis.dataelement.CategoryOptionGroupSet;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
+import org.hisp.dhis.i18n.I18n;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.oust.manager.SelectionTreeManager;
 import org.hisp.dhis.ouwt.manager.OrganisationUnitSelectionManager;
 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.system.util.AttributeUtils;
 import org.hisp.dhis.system.util.LocaleUtils;
 import org.hisp.dhis.user.User;
+import org.hisp.dhis.user.CurrentUserService;
 import org.hisp.dhis.user.UserAuthorityGroup;
 import org.hisp.dhis.user.UserCredentials;
 import org.hisp.dhis.user.UserGroup;
@@ -59,6 +62,8 @@
 
 import com.opensymphony.xwork2.Action;
 
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_ONLY_MANAGE_WITHIN_USER_GROUPS;
+
 /**
  * @author Torgeir Lorange Ostby
  */
@@ -113,12 +118,25 @@
         this.attributeService = attributeService;
     }
 
+    private I18n i18n;
+
+    public void setI18n( I18n i18n )
+    {
+        this.i18n = i18n;
+    }
+
+    @Autowired
+    private CurrentUserService currentUserService;
+
     @Autowired
     private UserGroupService userGroupService;
 
     @Autowired
     private DataElementCategoryService categoryService;
-    
+
+    @Autowired
+    private SystemSettingManager systemSettingManager;
+
     // -------------------------------------------------------------------------
     // Input & Output
     // -------------------------------------------------------------------------
@@ -247,6 +265,13 @@
         this.jsonAttributeValues = jsonAttributeValues;
     }
 
+    private String message;
+
+    public String getMessage()
+    {
+        return message;
+    }
+
     // -------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------
@@ -263,6 +288,37 @@
         inviteUsername = inviteUsername.trim();
         inviteEmail = inviteEmail.trim();
 
+        User currentUser = currentUserService.getCurrentUser();
+
+        // ---------------------------------------------------------------------
+        // Check if user group is required, before we add the user
+        // ---------------------------------------------------------------------
+
+        if ( (boolean) systemSettingManager.getSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, false )
+                && !currentUser.getUserCredentials().getAllAuthorities().contains( "ALL" ) )
+        {
+            boolean groupFound = false;
+
+            for ( String ug : ugSelected )
+            {
+                UserGroup group = userGroupService.getUserGroup( ug );
+
+                if ( group != null && securityService.canWrite( group ) )
+                {
+                    groupFound = true;
+
+                    break;
+                }
+            }
+
+            if ( !groupFound )
+            {
+                message = i18n.getString( "users_must_belong_to_a_group_controlled_by_the_user_manager" );
+
+                return ERROR;
+            }
+        }
+
         // ---------------------------------------------------------------------
         // User credentials and user
         // ---------------------------------------------------------------------
@@ -313,6 +369,11 @@
         Set<OrganisationUnit> dataViewOrgUnits = new HashSet<OrganisationUnit>( selectionTreeManager.getReloadedSelectedOrganisationUnits() );
         user.setDataViewOrganisationUnits( dataViewOrgUnits );
 
+        if ( dataViewOrgUnits.size() == 0 && currentUser.getDataViewOrganisationUnits().size() != 0 )
+        {
+            user.setDataViewOrganisationUnits( new HashSet<OrganisationUnit>( currentUser.getDataViewOrganisationUnits() ) );
+        }
+
         // ---------------------------------------------------------------------
         // User roles
         // ---------------------------------------------------------------------
@@ -330,14 +391,19 @@
 
         // ---------------------------------------------------------------------
         // Dimension constraints
+        //
+        // Note that any new user must inherit dimension constraints (if any)
+        // from the current user.
         // ---------------------------------------------------------------------
 
+        userCredentials.setCogsDimensionConstraints( new HashSet<CategoryOptionGroupSet>( currentUser.getUserCredentials().getCogsDimensionConstraints() ) );
+
         for ( String id : dcSelected )
         {
             CategoryOptionGroupSet cogs = categoryService.getCategoryOptionGroupSet( id );
             userCredentials.getCogsDimensionConstraints().add( cogs );
         }
-        
+
         userService.addUser( user );
         userService.addUserCredentials( userCredentials );
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java	2014-04-10 23:15:56 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java	2014-05-15 13:16:11 +0000
@@ -36,14 +36,18 @@
 import org.hisp.dhis.attribute.AttributeService;
 import org.hisp.dhis.dataelement.CategoryOptionGroupSet;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
+import org.hisp.dhis.i18n.I18n;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.oust.manager.SelectionTreeManager;
 import org.hisp.dhis.ouwt.manager.OrganisationUnitSelectionManager;
 import org.hisp.dhis.security.PasswordManager;
+import org.hisp.dhis.security.SecurityService;
+import org.hisp.dhis.setting.SystemSettingManager;
 import org.hisp.dhis.system.util.AttributeUtils;
 import org.hisp.dhis.system.util.LocaleUtils;
 import org.hisp.dhis.user.CurrentUserService;
 import org.hisp.dhis.user.User;
+import org.hisp.dhis.user.CurrentUserService;
 import org.hisp.dhis.user.UserAuthorityGroup;
 import org.hisp.dhis.user.UserCredentials;
 import org.hisp.dhis.user.UserGroup;
@@ -56,6 +60,8 @@
 
 import com.opensymphony.xwork2.Action;
 
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_ONLY_MANAGE_WITHIN_USER_GROUPS;
+
 /**
  * @author Torgeir Lorange Ostby
  */
@@ -101,6 +107,13 @@
         this.currentUserService = currentUserService;
     }
 
+    private SecurityService securityService;
+
+    public void setSecurityService( SecurityService securityService )
+    {
+        this.securityService = securityService;
+    }
+
     private AttributeService attributeService;
 
     public void setAttributeService( AttributeService attributeService )
@@ -108,12 +121,22 @@
         this.attributeService = attributeService;
     }
 
+    private I18n i18n;
+
+    public void setI18n( I18n i18n )
+    {
+        this.i18n = i18n;
+    }
+
     @Autowired
     private UserGroupService userGroupService;
 
     @Autowired
     private DataElementCategoryService categoryService;
-    
+
+    @Autowired
+    private SystemSettingManager systemSettingManager;
+
     // -------------------------------------------------------------------------
     // Input & Output
     // -------------------------------------------------------------------------
@@ -209,6 +232,13 @@
         this.jsonAttributeValues = jsonAttributeValues;
     }
 
+    private String message;
+
+    public String getMessage()
+    {
+        return message;
+    }
+
     // -------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------
@@ -226,6 +256,37 @@
             rawPassword = null;
         }
 
+        User currentUser = currentUserService.getCurrentUser();
+
+        // ---------------------------------------------------------------------
+        // Check if user group is required, before we start updating the user
+        // ---------------------------------------------------------------------
+
+        if ( (boolean) systemSettingManager.getSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, false )
+                && !currentUser.getUserCredentials().getAllAuthorities().contains( "ALL" ) )
+        {
+            boolean groupFound = false;
+
+            for ( String ug : ugSelected )
+            {
+                UserGroup group = userGroupService.getUserGroup( ug );
+
+                if ( group != null && securityService.canWrite( group ) )
+                {
+                    groupFound = true;
+
+                    break;
+                }
+            }
+
+            if ( !groupFound )
+            {
+                message = i18n.getString( "users_must_belong_to_a_group_controlled_by_the_user_manager" );
+
+                return ERROR;
+            }
+        }
+
         // ---------------------------------------------------------------------
         // User credentials and user
         // ---------------------------------------------------------------------
@@ -268,6 +329,11 @@
         Set<OrganisationUnit> dataViewOrgUnits = new HashSet<OrganisationUnit>( selectionTreeManager.getReloadedSelectedOrganisationUnits() );
         user.setDataViewOrganisationUnits( dataViewOrgUnits );
 
+        if ( dataViewOrgUnits.size() == 0 && currentUser.getDataViewOrganisationUnits().size() != 0 )
+        {
+            user.setDataViewOrganisationUnits( new HashSet<OrganisationUnit>( currentUser.getDataViewOrganisationUnits() ) );
+        }
+
         // ---------------------------------------------------------------------
         // User roles
         // ---------------------------------------------------------------------
@@ -285,9 +351,12 @@
 
         // ---------------------------------------------------------------------
         // Dimension constraints
+        //
+        // Note that any new user must inherit dimension constraints (if any)
+        // from the current user.
         // ---------------------------------------------------------------------
 
-        userCredentials.getCogsDimensionConstraints().clear();
+        userCredentials.setCogsDimensionConstraints( new HashSet<CategoryOptionGroupSet>( currentUser.getUserCredentials().getCogsDimensionConstraints() ) );
         
         for ( String id : dcSelected )
         {

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/META-INF/dhis/beans.xml	2014-04-30 08:37:29 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/META-INF/dhis/beans.xml	2014-05-15 13:16:11 +0000
@@ -43,6 +43,7 @@
 
   <bean id="org.hisp.dhis.user.action.UpdateUserAction" class="org.hisp.dhis.user.action.UpdateUserAction" scope="prototype">
     <property name="userService" ref="org.hisp.dhis.user.UserService" />
+    <property name="securityService" ref="org.hisp.dhis.security.SecurityService" />
     <property name="passwordManager" ref="org.hisp.dhis.security.PasswordManager" />
     <property name="selectionTreeManager" ref="org.hisp.dhis.oust.manager.SelectionTreeManager" />
     <property name="selectionManager" ref="org.hisp.dhis.ouwt.manager.OrganisationUnitSelectionManager" />

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/org/hisp/dhis/user/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/org/hisp/dhis/user/i18n_module.properties	2014-04-13 13:14:11 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/org/hisp/dhis/user/i18n_module.properties	2014-05-15 13:16:11 +0000
@@ -324,6 +324,7 @@
 user_use_group=There are user associated with this user role.
 can_not_remove_last_super_user=Can not remove the last super user.
 can_not_remove_last_super_user_role=Can not remove the last super user role.
+users_must_belong_to_a_group_controlled_by_the_user_manager=Users must belong to a group controlled by the user manager.
 delete_current_user=Delete Current User
 last_login=Last login
 inactive_for=Inactive for
@@ -338,6 +339,7 @@
 data_capture_maintenance_org_units=Data capture and maintenance organisation units
 data_output_analysis_org_units=Data output and analysis organisation units
 data_capture_organisation_unit_required_for_user=User must be assigned to at least one data capture organisation unit
+user_must_be_assigned_to_at_least_one_user_group=User must be assigned to at least one user group
 available_dimension_restrictions_for_data_analytics=Available dimension restrictions for data analytics
 selected_dimension_restrictions_for_data_analytics=Selected dimension restrictions for data analytics
 show_more_options=Show more options

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml	2014-04-30 08:37:29 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/resources/struts.xml	2014-05-15 13:16:11 +0000
@@ -54,7 +54,7 @@
 
     <action name="addUser" class="org.hisp.dhis.user.action.AddUserAction">
       <result name="success" type="redirect">user.action?currentPage=${keyCurrentPage}&amp;key=${keyCurrentKey}</result>
-      <result name="error" type="redirect">showAddUserForm.action</result>
+      <result name="error" type="velocity-json">/dhis-web-commons/ajax/jsonResponseError.vm</result>
       <param name="javascripts">javascript/user.js</param>
       <param name="requiredAuthorities">F_USER_ADD</param>
     </action>
@@ -68,7 +68,7 @@
 
     <action name="updateUser" class="org.hisp.dhis.user.action.UpdateUserAction">
       <result name="success" type="redirect">user.action?currentPage=${keyCurrentPage}&amp;key=${keyCurrentKey}</result>
-      <result name="error" type="redirect">showUpdateUserForm.action</result>
+      <result name="error" type="velocity-json">/dhis-web-commons/ajax/jsonResponseError.vm</result>
       <param name="requiredAuthorities">F_USER_ADD</param>
     </action>