Tuesday, July 6, 2010

Security Rights

We all know that AX never came with enough Security reports.  Security is complex in AX, if someone asks a functional question, "Who has access to view fixed assets?" I've found it is not as simple as looking...instead you find yourself answering a dozen questions to answer just the one simple one...Who belongs to which groups?  Which groups have access?  What type of access - View, Edit, Delete?  Do they have access to the form as well as the table?  Has someone else in my team modified security recently?

This is a job which answers the question from above by iterating through groups and users.

static void listSecurityRights_AssetTable(Args _args)
{
    TableId             tableId;
    DictTable           dictTable;
    DictField           dictField;
    DictSecurityKey     dictSecurityKey;
    SecurityKeySet      securitySet;
    UserGroupInfo       userGroupInfo;
    UserInfo            userInfo;
    AccessType          access;
    AccessType          menuAccess;
    ;
    setPrefix(funcname());

    info('AssetTable - Access to Fixed Assets');

    while select id, name from userGroupInfo
    {
        setPrefix("@SYS26106");

        securitySet = new SecurityKeySet();
        securitySet.loadGroupRights(userGroupInfo.id, '');

        access = securitySet.tableAccess(tablenum(AssetTable));
        menuAccess = securitySet.secureNodeAccess(menuItemDisplayStr(AssetTable), UtilElementType::DisplayTool);

        if (menuAccess < access)
            access = menuAccess;

        if (access > AccessType::NoAccess)
            info(strfmt("Group %2 - %1 can %3", userGroupInfo.name, userGroupInfo.id, access));
    }

    while select id, name from userInfo
    where userInfo.enable == true
    {
        setPrefix("@SYS25412");

        securitySet = new SecurityKeySet();
        securitySet.loadUserRights(userInfo.id, '');
        access = securitySet.tableAccess(tablenum(AssetTable));
        menuAccess = securitySet.secureNodeAccess(menuItemDisplayStr(AssetTable), UtilElementType::DisplayTool);

        if (menuAccess < access)
            access = menuAccess;

        if (access > AccessType::NoAccess)
            info(strfmt("User %2 - %1 can %3",  userInfo.name, userInfo.id, access));
    }
}

What?  You tried the job and it took forever to run.  Well yeah!  It uses the same method of accessing security as the slow User group permissions form.  How do we solve that?  Another faster job accessing tables which are, well largely undocumented.  The documentation describes the AccessRightsList table:
"Use of this table might lead to an Elevation of Privileges attack or a Denial of Service attack. The Application Object Server (AOS) authorizes each create, update, or delete action on the table by confirming that the current user has permission to perform the requested operation on that table. If the user who initiates the operation is not authorized to perform the operation, an exception will be thrown."
Well it won't hurt to take a peek!  This code actually does the same thing within seconds.

static void listSecurityRights_ElementName_aaaaaaa(Args _args)
{
    AccessRightsList AccessRightsList;
    ;
    while select accessRightsList
    where accessRightsList.elementName == 'CustTable'
    {
        if (accessRightsList.accessType > accessType::NoAccess)
            info(accessRightsList.groupId + ' ' + enum2str(accessRightsList.accessType));
    }
}

Bon appetit!

No comments:

Post a Comment