Uploaded image for project: 'PUBLIC - Liferay Portal Community Edition'
  1. PUBLIC - Liferay Portal Community Edition
  2. LPS-92932

Indirect permission checks in *LocalServiceImpl classes

    Details

      Description

      Certain LocalServiceImpl classes call filterFindBy* and filterCountBy* methods which means those service methods are doing indirect permission checking. Permission check should not happen in a local service as it is also stated by our official materials, e.g.:
      https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/implementing-permission-checks-at-the-service-layer

      Steps to reproduce:

      1. Set in portal-ext.properties
        user.groups.search.with.index=false
        
      2. Start the portal and login as Administrator.
      3. Create a new regular role "User Groups Admin".
      4. Create 2 new user groups: "Public User Group" and "Private User Group". Note that only "Owner" role has any permission on these resources. All other role have no permission on them.
      5. Assign "VIEW" permission to "User Groups Admin" role for "Public User Group" user group.
      6. Create a new User with screenname "testuser".
      7. Assign "User Groups Admin" role to user "testuser".
      8. Create another User with screenname "groupuser".
      9. Assing "groupuser" to both usergroups
      10. Run the following Groovy script (also attached as search_user_groups.groovy) under Control Panel > Configuration > Server Administration > Script
        The scrip is simply imitating that "testuser" is searching for the user groups where "groupuser" is a member. We use DB search via local service.
        import com.liferay.portal.kernel.dao.orm.QueryUtil
        import com.liferay.portal.kernel.exception.NoSuchUserException
        import com.liferay.portal.kernel.model.User
        import com.liferay.portal.kernel.model.UserGroup
        import com.liferay.portal.kernel.security.permission.PermissionChecker
        import com.liferay.portal.kernel.security.permission.PermissionCheckerFactoryUtil
        import com.liferay.portal.kernel.security.permission.PermissionThreadLocal
        import com.liferay.portal.kernel.service.ServiceContext
        import com.liferay.portal.kernel.service.ServiceContextFactory
        import com.liferay.portal.kernel.service.UserLocalServiceUtil
        import com.liferay.portal.kernel.service.UserGroupLocalServiceUtil
        import com.liferay.portal.kernel.util.comparator.UserGroupNameComparator
        import com.liferay.portal.kernel.util.StringPool
        
        import java.util.LinkedHashMap;
        
        ServiceContext serviceContext =
          ServiceContextFactory.getInstance(actionRequest);
        
        long companyId = serviceContext.getCompanyId();
        
        User testUser = null;
        User groupUser = null;
        
        try {
          testUser = UserLocalServiceUtil.getUserByScreenName(companyId, "testuser");
          groupUser = UserLocalServiceUtil.getUserByScreenName(companyId, "groupuser");
        }
        catch (NoSuchUserException nsue) {
          out.println("No user with screen name: " + screenName);
        
          return;
        }
        
        PermissionChecker permissionChecker =
          PermissionCheckerFactoryUtil.create(testUser);
        
        PermissionThreadLocal.setPermissionChecker(permissionChecker);
        
        System.out.println("screenname: " + testUser.getScreenName());
        
        // Now the active user is 'testuser'
        
        LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        
        // UserGroupLocalServiceImpl.isUseCustomSQL(LinkedHashMap params) returns true
        // only if params contains at least one of UserGroupFinderConstants.PARAM_KEYS.
        // Otherwise index search will be used.
        
        params.put("userGroupsUsers", groupUser.getUserId());
        
        String keywords = StringPool.BLANK;
        
        List<UserGroup> userGroups = UserGroupLocalServiceUtil.search(
          companyId, keywords, params, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
          new UserGroupNameComparator());
        
        for (UserGroup userGroup : userGroups) {
          out.println(
            userGroup.getUserGroupId() + " - " + userGroup.getName());
        }
        

      Expected: Both user groups are returned as local service should not call filterFindBy*, only findBy* methods.
      Actual: Only "Public User Group" is returned.

        Attachments

          Issue Links

            Activity

              People

              • Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Days since last comment:
                  1 week ago

                  Packages

                  Version Package
                  Master