130 views

Description

When users are removed from a group, it does not remove the roles, contained roles, granted by that group. When the roles that are contained by a group are removed, then some roles that contained by these roles are not removed from the users. The issue is there are many No-Express roles that are contained by the itil and itil_admin roles. Whenever an itil or itil_admin is added via groups, these contained roles are added as well, but when they are removed the contained roles are not removed. This issue occurs even when roles are assigned containing Non-Express roles manually to the users. This is reproducible on Geneva Express instance or instances that have been upgraded from Geneva.

Steps to Reproduce

 

  1. Login to Geneva Express instance
  2. Create a test group
  3. Add role itil_admin to this group
  4. Add a member to this group
  5. Impersonate an admin or itil_admin
  6. Remove the user from the group 
Removing the user from the group should remove all the roles that are associated with that group and all the roles associated with the roles from the group, however, if you login as maint, you see that the user still has some roles that itil_admin contains.
 
Same thing can be reproduced if roles are removed containing No-Express roles from a group, or remove them directly from users.

Workaround

After converting to Enterprise, there is a possibility that some Non-Express roles are added to the users by the customers manually. The users are required to have these roles. Hence it is always advised to take a backup of the sys_user_has_role table before running any of the scripts and to cross check with customers about the records that need deletion.

Before running the workaround scripts:

  1. Take a backup of the sys_user_has_role table
  2. Run any of the following Workaround scripts according to the requirement. There are many cases as to why this issue can happen. Here is a general work around which removes all the Non-Express roles that a user has if the user doesn't have an Express role that grants these roles. 

    General workaround to remove all the Non-Express roles that are contained by a user if he doesn't have at least on Express role that grants them
    deleteNonExpressRolesIfTheUserDoesNotContainExpressRoleThatGrantsThem();

    function getIncludedRoles(role) {
    var roleL = [];
    roleL.push(role);
    var gt = new GlideRecord("sys_user_role_contains");
    gt.addQuery('role', role);
    gt.query();
    while (gt.next())
    roleL = roleL.concat(getIncludedRoles(gt.getValue("contains")));

    return roleL
    }


    function deleteNonExpressRolesIfTheUserDoesNotContainExpressRoleThatGrantsThem() {
    var gr = new GlideRecord("sys_user_has_role")
    var qc = gr.addNullQuery("role.snbe");
    qc.addOrCondition("role.snbe", false);
    gr.addQuery("role.name", "NOT IN", "admin, itil, itil_admin, snc_read_only");
    gr.addQuery("inherited", true);
    gr.query();
    var expEnabledMap = {};
    var recordsToDel = [];
    var SNBERoles = {};
    while(gr.next()) {
    var contains = false;
    var user = gr.getValue("user");
    if (!expEnabledMap[user]) {
    var curRoles = [];
    var gt = new GlideRecord("sys_user_has_role");
    gt.addQuery("role.snbe", true)
    .addOrCondition("role.name", "admin")
    .addOrCondition("role.name", "itil")
    .addOrCondition("role.name", "itil_admin")
    .addOrCondition("role.name", "snc_read_only")
    gt.addQuery("user", user);
    gt.query();
    while (gt.next()) {
    curRoles.push(gt.getValue("role"));
    if (!SNBERoles[gt.getValue("role")]) {
    SNBERoles[gt.getValue("role")] = getIncludedRoles(gt.getValue("role"));
    }
    }

    expEnabledMap[user] = curRoles;
    }
    var uRoles = expEnabledMap[user];
    for (var i in uRoles) {

    if (SNBERoles[uRoles[i]].indexOf(gr.getValue("role")) >= 0) {
    // gs.print(gr.getValue("sys_id"));
    contains = true;
    break;
    }

    }
    if (!contains)
    recordsToDel.push(gr.getValue("sys_id"));
    }

    var gm = new GlideRecord("sys_user_has_role");
    gm.addQuery("sys_id", "IN", recordsToDel);
    gm.query();
    while(gm.next()) {
    gs.print("role: " + gm.getDisplayValue("role") + " has been grated to user: "+ gm.getDisplayValue("user")+" This will be deleted");
    //gm.deleteRecord();
    }

    gs.print("sys_id s of records that will be deleted: ");
    gs.print(recordsToDel.join(","));
    }

    Workaround script to delete the roles from a user, granted when the user was a part of the group but the user was removed from the group later:

    deleteRolesFromGroupsUserDoesNotBelong();

    function deleteRolesFromGroupsUserDoesNotBelong() {
    //script to delete the role for a user who is no longer part of a group
    var gr = new GlideRecord('sys_user_has_role');
    gr.addNotNullQuery('granted_by');
    gr.query();
    var toDel = [];
    while(gr.next()) {
    var gp = new GlideRecord('sys_user_grmember');
    gp.addQuery('group', gr.getValue('granted_by'));
    gp.addQuery('user', gr.getValue('user'));
    gp.query();
    if (!gp.hasNext()) {
    gs.print("The role: " + gr.getDisplayValue('role') + " was granted to user: " + gr.getDisplayValue('user') + " by the group: " +
    gr.getDisplayValue('granted_by') + ". This will be deleted.");
    toDel.push(gr.getValue("sys_id"));
    //gr.deleteRecord();
    }
    }
    gs.print("the sys_ids of sys_user_has_role records taht will be deleted are ");
    gs.print(toDel.join(","));
    }

    Workaround script to delete the roles granted by a role which is part of a group, but has been removed from the Group later:

    deleteRolesThatWereRemovedFromGroups();

    function getGroupRoles(group) {
    var roleL = [];
    var gr = new GlideRecord("sys_group_has_role");
    gr.addQuery('group', group);
    gr.query();
    while (gr.next())
    roleL = roleL.concat(getIncludedRoles(gr.getValue("role")));

    return roleL;
    }

    function getIncludedRoles(role) {
    var roleL = [];
    roleL.push(role);
    var gt = new GlideRecord("sys_user_role_contains");
    gt.addQuery('role', role);
    gt.query();
    while (gt.next())
    roleL = roleL.concat(getIncludedRoles(gt.getValue("contains")));

    return roleL
    }

    function deleteRolesThatWereRemovedFromGroups() {
    var toDel = [];
    var gr = new GlideRecord("sys_user_group");
    gr.query();
    while (gr.next()) {
    var grpId = gr.getValue("sys_id");
    var roleL = getGroupRoles(grpId);
    var grm = new GlideRecord("sys_user_grmember");
    grm.addQuery('group', grpId);
    grm.query();
    while (grm.next()) {
    var user = grm.getValue("user");
    var gst = new GlideRecord("sys_user_has_role");
    gst.addQuery('user', user);
    gst.addQuery('granted_by', grpId);
    // need not add not null query here since we anyway want to delete the empty roles
    gst.addQuery('role', 'NOT IN', roleL);
    gst.query();
    while (gst.next()) {
    var rol = gst.getValue("role");
    toDel.push(gst.getValue("sys_id"));
    gs.print("the role: " + gst.getDisplayValue("role") + " was added to user " + gst.getDisplayValue("user") + " by group
    "+gst.getDisplayValue("granted_by") + ".The user is not supposed to have this role. This will be deleted");
    //gst.deleteRecord();
    }
    }
    }
    gs.print("the sys_ids of sys_user_has_role records taht will be deleted are ");
    gs.print(toDel.join(","));
    }
  3. Take a note of the sys_id(s) of the sys_user_has_role records or the note of the roles that will be removed by copying the log these scripts output.
  4. Navigate to the sys_user_has_role list and use the filter [Sys ID] [Is one of] [the sys_ids that are copied in the above step] If any of the scripts returns the sys_ids
  5. Ask the customer to cross verify if these are the records that need deletion.
  6. Run the script again, this time by uncommenting the deletion part.

Related Problem: PRB1091283

Seen In

Geneva

Associated Community Threads

There is no data to report.

Article Information

Last Updated:2018-03-22 04:57:48
Published:2017-11-17