checking user roles in AX 2012

It’s been a while since I’ve posted anything related to Dynamics AX / X++, so I thought I’d write up something I stumbled across recently. I had created a custom form, with a number of buttons on it. Two of the buttons needed to be available only to users in a certain role.

Well, first, I should point out that this can be done without any code. See here and here for information on that. And there are good reasons to do it this way, in many cases.

But there are also some good reasons to do this in code. It allows you to document what you’re doing and why, and it gives you more flexibility than just doing it through properties in the AOT. In my case, the business rules around this didn’t really fit into the permissions available in the AOT (Read, Update, Create, and Delete), so while I could have picked one of those and used it, it wouldn’t have accurately reflected the actual use case.

So I first wanted to find a method in X++ that would tell me if a given user was in a given role. I’m familiar with Roles.IsUserInRole from the .NET Framework, and have used it frequently in the context of ASP.NET sites using custom membership providers. So I looked for something similar in AX. That led me to the SysUserManagement Class.

I wound up writing a utility method that made use of this class:

/andyhuey/9326912
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/// <summary>
/// return true is the specified user is in any of the roles in the roleNames container.
/// </summary>
/// <param name="axUserId">
/// AX user id, e.g. curUserId()
/// </param>
/// <param name="roleNames">
/// container of role names to check. (use role NAME, not label.)
/// </param>
/// <returns>
/// true if user is in ANY of the specified roles.
/// </returns>
/// <remarks>
///
/// </remarks>
 
public static boolean isUserInRole(UserId axUserId, container roleNames)
{
    SysUserManagement userManagement = new SysUserManagement();
    List roleList = userManagement.getRolesForUser(axUserId);
    ListEnumerator listEnum = null;
    boolean isInRole = false;
    str roleStr = '';
 
    if (!roleList)
        return false;
 
    listEnum = roleList.getEnumerator();
    while (listEnum.moveNext())
    {
        if (conFind(roleNames, listEnum.current()))
            return true;
    }
 
    return false;
}

It worked fine on my VM, when logged in under my own ID. But, after deployment, it quickly became apparent that X++ code running under a normal user account (without SYSADMIN rights) can’t call methods in the SysUserManagement class. Now, there’s nothing I can see in the documentation that indicates that, but I should of course have tested my code under a normal user account.

So I rewrote my code to access the appropriate role-related tables directly, and it turns out that a normal user can do that, no problem:

/andyhuey/9326939
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/// <summary>
/// return true is the specified user is in any of the roles in the roleNames container.
/// </summary>
/// <param name="axUserId">
/// AX user id, e.g. curUserId()
/// </param>
/// <param name="roleNames">
/// container of role names to check. (use role NAME, not label.)
/// </param>
/// <returns>
/// true if user is in ANY of the specified roles.
/// </returns>
/// <remarks>
/// ajh 2014-02-12: previous method req'd admin perm. to run. Doh!
/// </remarks>
 
public static boolean isUserInRole(UserId axUserId, container roleNames)
{
    SecurityUserRole securityUserRole;
    SecurityRole securityRole;
 
    while select AotName from securityRole
    join securityUserRole
    where securityUserRole.User == axUserId
    && securityUserRole.SecurityRole == securityRole.RecId
    {
        if (conFind(roleNames, securityRole.AotName))
            return true;
    }
    return false;
}

So I guess the lesson here is to always test your code under a normal user account, and not to assume that the MSDN page for a given AX class will tell you everything you need to know about that class.

And, as with a lot of stuff in AX, I have a feeling that I’m *still* doing this “the wrong way”, even though my code works and is fairly simple. I’m guessing that, a year from now, I’ll have figured out that there’s a better way to do this.

3 Comments


  1. Hi,
    A year passed, have you find a better solution?

    Reply

    1. Nope, still using this code.

      Reply

      1. Cant you just override permissions on a security role for that class/method.

        Reply

Leave a Reply