none
Hot to get users with a permission?

    Question

  • I'm getting troubles trying to get the Users who has an specific Permission, I have this query, but it does not work, it doesn't give me results

    var usuarios = DataWorkspace.SecurityData.UserRegistrations.
                    Where(u => u.RoleAssignments.Where(r => r.Role.RolePermissions.
                        Where(p => p.PermissionId == Permissions.AsistenciaOperaciones).Count() > 0).Count() > 0).Execute().ToList();

    I have changed the "==" for .Equals comparer, but that's not the problem.

    Please help, I'm stuck here.

    Thanks :D

    Thursday, May 10, 2012 2:10 PM

Answers

  • Even with SecurityAdministrator permission, your query will not work because it is not supported by the SecurityData data service.  There are several workaround.  The one Paul Van Bladel linked is one example.  Another would be the following.

    IEnumerable<UserRegistration> userRegistrations = this.DataWorkspace.SecurityData.UserRegistrations.GetQuery().Execute()
        .Where(u => u.RoleAssignments.Any(ra => ra.Role.RolePermissions.Any(p => p.PermissionId == Permissions.CustomPermission)));

    Thursday, May 10, 2012 4:50 PM

All replies

  • Try this link: http://social.msdn.microsoft.com/Forums/en-US/lightswitch/thread/043c23fd-ae72-44e5-8944-b18b315cb84c

    Did you check the SecurityAdministrator permission? You need this permission, otherwise it wouldn't work.


    paul van bladel

    Thursday, May 10, 2012 4:09 PM
  • Even with SecurityAdministrator permission, your query will not work because it is not supported by the SecurityData data service.  There are several workaround.  The one Paul Van Bladel linked is one example.  Another would be the following.

    IEnumerable<UserRegistration> userRegistrations = this.DataWorkspace.SecurityData.UserRegistrations.GetQuery().Execute()
        .Where(u => u.RoleAssignments.Any(ra => ra.Role.RolePermissions.Any(p => p.PermissionId == Permissions.CustomPermission)));

    Thursday, May 10, 2012 4:50 PM
  • Snomis,

    I like your solution. Correct me if I'm wrong  but still, the user running the code,  would need the security admin permission to work correctly.

    I like using the permission mechanism as much as possible and never refer directly to "roles" when handling e.g. row level security. But given the above, that is not always possible. Imagine the table scenario: Employee - Manager. Employee and managers are also direct users of the app.  There is a role manager and it has, among others, the permission "IsManager", which I would like to use for filtering the dropdown in my Employee screen (so for assigning a manager to an employee).  If every user would have security admin permission, that would work with the above query. But that's not the case.

    My workaround for this, is to speak directly with the aspnet role provider, which has a method to get the list of users having a certain role.


    paul van bladel

    Thursday, May 10, 2012 5:34 PM
  • Paul Van Bladel,

    Yes you are correct that the user running the code needs the security admin permission.  If this code is running as part of the save pipeline, you can utilize the permissions elevation feature.  It sounds like to handle your scenario, you would need permission elevation within the query pipeline which is currently not supported.

    Thursday, May 10, 2012 6:47 PM
  • But... I'm getting values even without SecurityAdmin permission :3
    And snomis, it works perfectly :D, thanks!!

    But, I don't understand when I have to use GetQuery or Excute?


    SebaXOR


    • Edited by sebaxor Friday, May 11, 2012 1:08 AM
    Friday, May 11, 2012 1:07 AM
  • Hi SebaXOR,

    Which version of LS are you using? LS 2011 or 11?

    in LS 2011 when you don't have the security admin permission you can only get results for the current logged on user not for the other users in the user table.

    So, if the user running the app doesn't have security admin permission, the query of Snomis will return maximum 1 record (= the current logged on user under the assumption he has the permission on which you are checking). If the current logged on user has not the security admin permission you will always get 0 records returned.

    Can you please check this.


    paul van bladel

    Friday, May 11, 2012 4:59 AM
  • I'm using Microsoft Visual Studio LightSwitch 2011 (10.0.40219) over Visual Studio 2010.. :/


    SebaXOR

    Friday, May 11, 2012 6:22 AM
  • ... and you are getting +1 results without security admin permission?

    paul van bladel

    Friday, May 11, 2012 7:28 AM
  • Yeah, I was getting one but I added another User with that Permission and it returned 2. U_U

    SebaXOR

    Friday, May 11, 2012 7:13 PM
  • what you are describing can ONLY happen when the user who is running the app has the security admin permission.

    Are you seeing the users and role screen when you are running the app?


    paul van bladel

    Saturday, May 12, 2012 6:53 AM
  • Nop, I have test it with and without security admin permission.. it works fine with both of them

    SebaXOR

    Saturday, May 12, 2012 3:17 PM
  • in debug mode or when app is deployed?

    Can you provide the code with which you get get a list of users with a certain permission while the app is running under an account which has NOT the SecurityAdmin permission.


    paul van bladel

    Saturday, May 12, 2012 5:00 PM
  • I have tested in debug and release mode but I haven't check when the app is deployed, I'll do and tell you later

    SebaXOR



    • Edited by sebaxor Sunday, May 13, 2012 2:11 PM
    Sunday, May 13, 2012 2:11 PM
  • Hi again,

    Thanks for your continuous feedback.

    Can you please follow my scenario:

    1. Activate SecurityAdministration permission and add 2 users which permission "MyPermission".

    2. Take any screen an put a button on it with the code of Snomis :

           IEnumerable<UserRegistration> userRegistrations = this.DataWorkspace.SecurityData.UserRegistrations.GetQuery().Execute()
        .Where(u => u.RoleAssignments.Any(ra => ra.Role.RolePermissions.Any(p => p.PermissionId == Permissions.MyPermission)));
                this.ShowMessageBox(userRegistrations.Count().ToString());
    

    3. Disable  now SecurityAdmnistration permission

    4. if you get a messagebox saying something different than "0" you must have a LightSwitch private edition :)


    paul van bladel

    Sunday, May 13, 2012 6:10 PM
  • Ok, let me check it and I will tell you what I get

    SebaXOR

    Wednesday, May 16, 2012 8:00 PM
  • I'm getting just the current user.. not the other one.. so what version I have.. and is that good or bad?? XD 

    So is mandatory now to perform the permission elevation...

    I just tryed to elevate permissions but I'm getting an InvalidOperationExcption.. I have this

     partial void Directores_PreprocessQuery(ref IQueryable<usuario> query)
            {
                bool Granted = false;
                if (!Application.User.HasPermission(Permissions.SecurityAdministration))
                {
                    Granted = true;
                    Application.User.AddPermissions(Permissions.SecurityAdministration);
                }
                IEnumerable<UserRegistration> userRegistrations = this.DataWorkspace.SecurityData.UserRegistrations.GetQuery().Execute()
                    .Where(u => u.RoleAssignments.Any(ra => ra.Role.RolePermissions.Any(p => p.PermissionId == Permissions.DireccionOperaciones)));

                query = query.Where(x => userRegistrations.Any(u => u.UserName == x.usuario1));
                if (Granted)
                    Application.User.RemovePermissions(Permissions.SecurityAdministration);
            }

    The Query is called from an "Updated" method of another entity.. and LS tells me that I can't do the permission elevation within a saved-related method :/... so how should I perform this permission elevation without getting the exception in this scenario?

    Thanks


    SebaXOR



    • Edited by sebaxor Thursday, May 17, 2012 12:16 PM some bad typing XD
    Thursday, May 17, 2012 12:13 PM
  • The query behavior you describe is what is expected.  If you are running as the Security Admin you are able to query all of the rows in the security related tables.  If you are not the Security Admin, when you query the security related tables, a filter will get applied by LightSwitch that will only allow you to query the rows that belong to you.  Hence in your scenario you will only find the current user's UserRegistration if they have the specified permission.

    Regarding your workaround, you will need to elevate the permission within the Updated method before invoking the query.  Also as a side note, you can use a using statement which makes the permission elevation code a little simpler IMO.

        using (this.Application.User.AddPermissions(Permissions.SecurityAdministration))
        {
            var results = this.DataWorkspace.ApplicationData.Directores().Execute();
        }

    Thursday, May 17, 2012 1:48 PM
  • It works perfectly, tnx.. but I don't understand 2 things..

    1. Why it's possible to do this with and using? I mean.. the using will dispose the returned IUser after the execution, but is not this User unique in LS? or I can create any instances as I want with permission elevation and then dispose them without affecting the Applicarion.User object?

    2. The exception talks about "Save-related methods" I'm still in a save-related method and it works.. why is that? I'm a little confused.

    Tnx


    SebaXOR

    Tuesday, May 22, 2012 11:20 AM
  • the elevation mechanism only works in the SAVE pipeline and not in the Query pipeline.

    paul van bladel

    Tuesday, May 22, 2012 11:39 AM
  • Regarding your first question - "Why it's possible to do this with and using?".  AddPermission doesn't return an IUser, rather it returns a disposable object that defines the modification of the user's permissions.  When this object is disposed, the permission modifications are reverted.

    I believe Paul already answered your second question.

     
    Tuesday, May 22, 2012 1:35 PM
  • So.. how can I elevate permissions in a Query pipeline? or how can I structure my query to have the permissions and get the data ?

    SebaXOR

    Tuesday, July 24, 2012 8:50 AM
  • As mentioned above, permission elevation only works in the SAVE pipeline, not in the query pipeline.

    If you want to filter data based on a permission (and without giving admin permission to the user) the only fallback is doing the check on the role but NOT via the lightswitch role but via the role provider directly.

    E.g.:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.LightSwitch;
    using Microsoft.LightSwitch.Security.Server;
    using System.Web.Security;
    using Microsoft.LightSwitch.Security;
    using System.Web.Profile;
    namespace LightSwitchApplication
    {
        public partial class ApplicationDataService
        {
            partial void GetApprovers_PreprocessQuery(ref IQueryable<ApplicationUser> query)
            {
                string requiredRole = "Approver";
    
                if (Roles.GetAllRoles().Contains(requiredRole) == false)
                    return;
    
                var approvers = Roles.GetUsersInRole(requiredRole).ToList();
                query = query.Where(au => approvers.Contains(au.UserId));
            }
        }
    }



    paul van bladel

    Tuesday, July 24, 2012 10:22 AM
  • Umm, why aren't you using the built-in Application.Current.User.HasPermisssion("PermissionName")?

    You shouldn't ever be dealing with Roles in your code, always Permissions only.


    Yann - LightSwitch Central - Click here for FREE Themes, Controls, Types and Commands
     
    If you find a reply helpful, please click "Vote as Helpful", if a reply answers your question, please click "Mark as Answer"
     
    By doing this you'll help people find answers faster.

    Tuesday, July 24, 2012 2:51 PM
  • Yann,

    I know, but in the scenario of the OOP, who wants to populate a LIST of users having a certain permission, there is no other possibility. 

    Of course, when you need to know something about the permissionSet of the currentuser, you don't need to have security admin permission, but for browsing the permissions of ALL users, you need security admin permission. Giving all your users sec. admin permisssion is a bad idea.

    A solution for the above would be QUERY pipeline permission elevation, but that's not implemented in the LS V1 nor 2011. Currently, there is only save pipeline permission elevation.


    paul van bladel

    Tuesday, July 24, 2012 5:02 PM
  • It's not how LS was designed to be used, so I'm not surprised that he's having trouble doing it.

    Yann - LightSwitch Central - Click here for FREE Themes, Controls, Types and Commands
     
    If you find a reply helpful, please click "Vote as Helpful", if a reply answers your question, please click "Mark as Answer"
     
    By doing this you'll help people find answers faster.

    Wednesday, July 25, 2012 5:10 AM
  • Hi Yann,

    Based on the reply of Snomis, I don't think there is another option, unless you give every user security admin permission.


    paul van bladel

    Wednesday, July 25, 2012 8:15 AM
  • Ok, I like the Role provider option ^^

    But.. isn't this a  "security hole", I mean.. this option allows you to have the same information, basically by other way.. so if the idea is to seal the Security Information for the users with the SecurityAdministration Permission only, why you still can have that info with this method? (Don't misunderstand me, I'm have to know there's an alternative to do what I need.. and I will test it, but I still wanna know why is this possible if the "right" way to do it is a security violation..)

    Tnx ^^


    SebaXOR

    Wednesday, July 25, 2012 12:30 PM
  • It is not really a security hole, because you can access only the role provider server side, not client side.

    But I completely agree with Yann, that you should never directly use Roles in your app. A role is just a container for a set of permissions. But as said, if you want to populate a list of users having a certain permission, the approach with the asp.net role provider is the only way.


    paul van bladel

    Wednesday, July 25, 2012 12:43 PM
  • Have a look at the article "Check User Permissions Programmatically in SharePoint 2010" at http://tad.co.in/?p=748

    http://tad.co.in

    Friday, November 02, 2012 6:26 PM