public void setUserRoles(
      Session session, final ITenant theTenant, final String userName, final String[] roles)
      throws RepositoryException, NotFoundException {
    if (hasAdminRole(getUserRoles(theTenant, userName)) && (roles.length == 0)) {
      throw new RepositoryException(
          Messages.getInstance()
              .getString("AbstractJcrBackedUserRoleDao.ERROR_0005_LAST_ADMIN_USER", userName));
    }

    Set<String> roleSet = new HashSet<String>();
    if (roles != null) {
      roleSet.addAll(Arrays.asList(roles));
    }
    roleSet.add(authenticatedRoleName);

    User jackrabbitUser = getJackrabbitUser(theTenant, userName, session);

    if ((jackrabbitUser == null)
        || !TenantUtils.isAccessibleTenant(
            theTenant == null
                ? tenantedUserNameUtils.getTenant(jackrabbitUser.getID())
                : theTenant)) {
      throw new NotFoundException(
          Messages.getInstance()
              .getString("AbstractJcrBackedUserRoleDao.ERROR_0003_USER_NOT_FOUND"));
    }
    HashMap<String, Group> currentlyAssignedGroups = new HashMap<String, Group>();
    Iterator<Group> currentGroups = jackrabbitUser.memberOf();
    while (currentGroups.hasNext()) {
      Group currentGroup = currentGroups.next();
      currentlyAssignedGroups.put(currentGroup.getID(), currentGroup);
    }

    HashMap<String, Group> finalCollectionOfAssignedGroups = new HashMap<String, Group>();
    ITenant tenant = theTenant == null ? JcrTenantUtils.getTenant(userName, true) : theTenant;
    for (String role : roleSet) {
      Group jackrabbitGroup = getJackrabbitGroup(tenant, role, session);
      if (jackrabbitGroup != null) {
        finalCollectionOfAssignedGroups.put(
            tenantedRoleNameUtils.getPrincipleId(tenant, role), jackrabbitGroup);
      }
    }

    ArrayList<String> groupsToRemove = new ArrayList<String>(currentlyAssignedGroups.keySet());
    groupsToRemove.removeAll(finalCollectionOfAssignedGroups.keySet());

    ArrayList<String> groupsToAdd = new ArrayList<String>(finalCollectionOfAssignedGroups.keySet());
    groupsToAdd.removeAll(currentlyAssignedGroups.keySet());

    for (String groupId : groupsToRemove) {
      currentlyAssignedGroups.get(groupId).removeMember(jackrabbitUser);
    }

    for (String groupId : groupsToAdd) {
      finalCollectionOfAssignedGroups.get(groupId).addMember(jackrabbitUser);
    }

    // Purge the UserDetails cache
    purgeUserFromCache(userName);
  }
  public void deleteUser(Session session, final IPentahoUser user)
      throws NotFoundException, RepositoryException {
    if (canDeleteUser(session, user)) {
      User jackrabbitUser = getJackrabbitUser(user.getTenant(), user.getUsername(), session);
      if (jackrabbitUser != null
          && TenantUtils.isAccessibleTenant(
              tenantedUserNameUtils.getTenant(jackrabbitUser.getID()))) {

        // [BISERVER-9215] Adding new user with same user name as a previously deleted user,
        // defaults to all previous roles
        Iterator<Group> currentGroups = jackrabbitUser.memberOf();
        while (currentGroups.hasNext()) {
          currentGroups.next().removeMember(jackrabbitUser);
        }
        // [BISERVER-9215]

        jackrabbitUser.remove();
      } else {
        throw new NotFoundException(""); // $NON-NLS-1$
      }
    } else {
      throw new RepositoryException(
          Messages.getInstance()
              .getString(
                  "AbstractJcrBackedUserRoleDao.ERROR_0004_LAST_USER_NEEDED_IN_ROLE",
                  tenantAdminRoleName));
    }
  }
  public IPentahoRole createRole(
      Session session,
      final ITenant theTenant,
      final String roleName,
      final String description,
      final String[] memberUserNames)
      throws AuthorizableExistsException, RepositoryException {
    ITenant tenant = theTenant;
    String role = roleName;
    if (tenant == null) {
      tenant = JcrTenantUtils.getTenant(roleName, false);
      role = JcrTenantUtils.getPrincipalName(roleName, false);
    }
    if (tenant == null || tenant.getId() == null) {
      tenant = JcrTenantUtils.getCurrentTenant();
    }
    if (!TenantUtils.isAccessibleTenant(tenant)) {
      throw new NotFoundException(
          Messages.getInstance()
              .getString(
                  "AbstractJcrBackedUserRoleDao.ERROR_0006_TENANT_NOT_FOUND", theTenant.getId()));
    }
    String roleId = tenantedRoleNameUtils.getPrincipleId(tenant, role);

    UserManager tenantUserMgr = getUserManager(tenant, session);
    // Intermediate path will always be an empty string. The path is already provided while creating
    // a user manager
    tenantUserMgr.createGroup(new PrincipalImpl(roleId), ""); // $NON-NLS-1$
    setRoleMembers(session, tenant, role, memberUserNames);
    setRoleDescription(session, tenant, role, description);
    return getRole(session, theTenant, roleName);
  }
 public List<IPentahoRole> getRoles(
     Session session, final ITenant theTenant, boolean includeSubtenants)
     throws RepositoryException {
   ArrayList<IPentahoRole> roles = new ArrayList<IPentahoRole>();
   if (TenantUtils.isAccessibleTenant(theTenant)) {
     UserManager userMgr = getUserManager(theTenant, session);
     pPrincipalName = ((SessionImpl) session).getJCRName(P_PRINCIPAL_NAME);
     Iterator<Authorizable> it =
         userMgr.findAuthorizables(pPrincipalName, null, UserManager.SEARCH_TYPE_GROUP);
     while (it.hasNext()) {
       Group group = (Group) it.next();
       IPentahoRole pentahoRole = convertToPentahoRole(group);
       // Exclude the system role from the list of roles to be returned back
       if (!extraRoles.contains(pentahoRole.getName())) {
         if (includeSubtenants) {
           roles.add(pentahoRole);
         } else {
           if (pentahoRole.getTenant() != null && pentahoRole.getTenant().equals(theTenant)) {
             roles.add(pentahoRole);
           }
         }
       }
     }
   }
   return roles;
 }
 public IPentahoRole getRole(Session session, final ITenant tenant, final String name)
     throws RepositoryException {
   Group jackrabbitGroup = getJackrabbitGroup(tenant, name, session);
   return jackrabbitGroup != null
           && TenantUtils.isAccessibleTenant(
               tenant == null ? tenantedRoleNameUtils.getTenant(jackrabbitGroup.getID()) : tenant)
       ? convertToPentahoRole(jackrabbitGroup)
       : null;
 }
  public void setRoleBindings(
      Session session, ITenant tenant, String runtimeRoleName, List<String> logicalRoleNames)
      throws NamespaceException, RepositoryException {
    if (tenant == null) {
      tenant = JcrTenantUtils.getTenant(runtimeRoleName, false);
      runtimeRoleName = getPrincipalName(runtimeRoleName);
    }

    if (!TenantUtils.isAccessibleTenant(tenant)) {
      throw new NotFoundException("Tenant " + tenant.getId() + " not found");
    }

    PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
    final String phoNsPrefix =
        session.getNamespacePrefix(PentahoJcrConstants.PHO_NS) + ":"; // $NON-NLS-1$
    final String onlyPentahoPattern = phoNsPrefix + "*"; // $NON-NLS-1$
    Node runtimeRolesFolderNode = getRuntimeRolesFolderNode(session, tenant);
    NodeIterator runtimeRoleNodes = runtimeRolesFolderNode.getNodes(onlyPentahoPattern);
    int i = 0;
    while (runtimeRoleNodes.hasNext()) {
      runtimeRoleNodes.nextNode();
      i++;
    }
    if (i == 0) {
      // no bindings setup yet; install bootstrap bindings; bootstrapRoleBindings will now no longer
      // be
      // consulted
      for (Map.Entry<String, List<String>> entry : bootstrapRoleBindings.entrySet()) {
        JcrRoleAuthorizationPolicyUtils.internalSetBindings(
            pentahoJcrConstants,
            runtimeRolesFolderNode,
            entry.getKey(),
            entry.getValue(),
            phoNsPrefix);
      }
    }
    if (!isImmutable(runtimeRoleName)) {
      JcrRoleAuthorizationPolicyUtils.internalSetBindings(
          pentahoJcrConstants,
          runtimeRolesFolderNode,
          runtimeRoleName,
          logicalRoleNames,
          phoNsPrefix);
    } else {
      throw new RuntimeException(
          Messages.getInstance()
              .getString(
                  "JcrRoleAuthorizationPolicyRoleBindingDao.ERROR_0001_ATTEMPT_MOD_IMMUTABLE",
                  runtimeRoleName)); //$NON-NLS-1$
    }
    session.save();
    Assert.isTrue(NodeHelper.hasNode(runtimeRolesFolderNode, phoNsPrefix, runtimeRoleName));

    // update cache
    String roleId = tenantedRoleNameUtils.getPrincipleId(tenant, runtimeRoleName);
    cacheManager.putInRegionCache(LOGICAL_ROLE_BINDINGS_REGION, roleId, logicalRoleNames);
  }
 public IPentahoUser getUser(Session session, final ITenant tenant, final String name)
     throws RepositoryException {
   User jackrabbitUser = getJackrabbitUser(tenant, name, session);
   return jackrabbitUser != null
           && TenantUtils.isAccessibleTenant(
               tenant == null ? tenantedUserNameUtils.getTenant(jackrabbitUser.getID()) : tenant)
       ? convertToPentahoUser(jackrabbitUser)
       : null;
 }
  /**
   * Imports UserExport objects into the platform as users.
   *
   * @param users
   * @return A map of role names to list of users in that role
   */
  protected Map<String, List<String>> importUsers(List<UserExport> users) {
    Map<String, List<String>> roleToUserMap = new HashMap<>();
    IUserRoleDao roleDao = PentahoSystem.get(IUserRoleDao.class);
    ITenant tenant = new Tenant("/pentaho/" + TenantUtils.getDefaultTenant(), true);

    if (users != null && roleDao != null) {
      for (UserExport user : users) {
        String password = user.getPassword();
        log.debug("Importing user: "******"USER.Already.Exists", user.getUsername()));

          try {
            if (isOverwriteFile()) {
              // set the roles, maybe they changed
              roleDao.setUserRoles(tenant, user.getUsername(), userRoles);

              // set the password just in case it changed
              roleDao.setPassword(tenant, user.getUsername(), password);
            }
          } catch (Exception ex) {
            // couldn't set the roles or password either
            log.debug("Failed to set roles or password for existing user on import", ex);
          }
        } catch (Exception e) {
          log.error(Messages.getInstance().getString("ERROR.CreatingUser", user.getUsername()));
        }
        importUserSettings(user);
      }
    }
    return roleToUserMap;
  }
 public void deleteRole(Session session, final IPentahoRole role)
     throws NotFoundException, RepositoryException {
   if (canDeleteRole(session, role)) {
     Group jackrabbitGroup = getJackrabbitGroup(role.getTenant(), role.getName(), session);
     if (jackrabbitGroup != null
         && TenantUtils.isAccessibleTenant(
             tenantedRoleNameUtils.getTenant(jackrabbitGroup.getID()))) {
       jackrabbitGroup.remove();
     } else {
       throw new NotFoundException(""); // $NON-NLS-1$
     }
   } else {
     throw new RepositoryException(
         Messages.getInstance()
             .getString("AbstractJcrBackedUserRoleDao.ERROR_0007_ATTEMPTED_SYSTEM_ROLE_DELETE"));
   }
 }
 public List<IPentahoUser> getRoleMembers(
     Session session, final ITenant theTenant, final String roleName) throws RepositoryException {
   List<IPentahoUser> users = new ArrayList<IPentahoUser>();
   Group jackrabbitGroup = getJackrabbitGroup(theTenant, roleName, session);
   if ((jackrabbitGroup != null)
       && TenantUtils.isAccessibleTenant(
           theTenant == null
               ? tenantedRoleNameUtils.getTenant(jackrabbitGroup.getID())
               : theTenant)) {
     Iterator<Authorizable> authorizables = jackrabbitGroup.getMembers();
     while (authorizables.hasNext()) {
       Authorizable authorizable = authorizables.next();
       if (authorizable instanceof User) {
         users.add(convertToPentahoUser((User) authorizable));
       }
     }
   }
   return users;
 }
  public void setPassword(
      Session session, final ITenant theTenant, final String userName, final String password)
      throws NotFoundException, RepositoryException {
    User jackrabbitUser = getJackrabbitUser(theTenant, userName, session);
    if ((jackrabbitUser == null)
        || !TenantUtils.isAccessibleTenant(
            theTenant == null
                ? tenantedUserNameUtils.getTenant(jackrabbitUser.getID())
                : theTenant)) {
      throw new NotFoundException(
          Messages.getInstance()
              .getString("AbstractJcrBackedUserRoleDao.ERROR_0003_USER_NOT_FOUND"));
    }
    jackrabbitUser.changePassword(password);

    /** BISERVER-9906 Clear cache after changing password */
    purgeUserFromCache(userName);
    userCache.remove(jackrabbitUser.getID());
  }
 public List<IPentahoRole> getUserRoles(
     Session session, final ITenant theTenant, final String userName) throws RepositoryException {
   ArrayList<IPentahoRole> roles = new ArrayList<IPentahoRole>();
   User jackrabbitUser = getJackrabbitUser(theTenant, userName, session);
   if ((jackrabbitUser != null)
       && TenantUtils.isAccessibleTenant(
           theTenant == null
               ? tenantedUserNameUtils.getTenant(jackrabbitUser.getID())
               : theTenant)) {
     Iterator<Group> groups = jackrabbitUser.memberOf();
     while (groups.hasNext()) {
       IPentahoRole role = convertToPentahoRole(groups.next());
       // Exclude the extra role from the list of roles to be returned back
       if (!extraRoles.contains(role.getName())) {
         roles.add(role);
       }
     }
   }
   return roles;
 }
 public void setUserDescription(
     Session session, final ITenant theTenant, final String userName, final String description)
     throws NotFoundException, RepositoryException {
   User jackrabbitUser = getJackrabbitUser(theTenant, userName, session);
   if ((jackrabbitUser == null)
       || !TenantUtils.isAccessibleTenant(
           theTenant == null
               ? tenantedUserNameUtils.getTenant(jackrabbitUser.getID())
               : theTenant)) {
     throw new NotFoundException(
         Messages.getInstance()
             .getString("AbstractJcrBackedUserRoleDao.ERROR_0003_USER_NOT_FOUND"));
   }
   if (description == null) {
     jackrabbitUser.removeProperty("description"); // $NON-NLS-1$
   } else {
     jackrabbitUser.setProperty(
         "description", session.getValueFactory().createValue(description)); // $NON-NLS-1$
   }
 }
 protected Map<String, List<String>> getRoleBindings(Session session, ITenant tenant)
     throws RepositoryException {
   Map<String, List<String>> map = new HashMap<String, List<String>>();
   if (tenant == null) {
     tenant = JcrTenantUtils.getTenant();
   }
   if (!TenantUtils.isAccessibleTenant(tenant)) {
     return map;
   }
   PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
   final String phoNsPrefix =
       session.getNamespacePrefix(PentahoJcrConstants.PHO_NS) + ":"; // $NON-NLS-1$
   final String onlyPentahoPattern = phoNsPrefix + "*"; // $NON-NLS-1$
   Node runtimeRolesFolderNode = getRuntimeRolesFolderNode(session, tenant);
   NodeIterator runtimeRoleNodes = runtimeRolesFolderNode.getNodes(onlyPentahoPattern);
   if (!runtimeRoleNodes.hasNext()) {
     // no bindings setup yet; fall back on bootstrap bindings
     map.putAll(bootstrapRoleBindings);
   } else {
     while (runtimeRoleNodes.hasNext()) {
       Node runtimeRoleNode = runtimeRoleNodes.nextNode();
       if (runtimeRoleNode.hasProperty(pentahoJcrConstants.getPHO_BOUNDROLES())) {
         // get clean runtime role name
         String runtimeRoleName =
             JcrStringHelper.fileNameDecode(
                 runtimeRoleNode.getName().substring(phoNsPrefix.length()));
         // get logical role names
         List<String> logicalRoleNames = new ArrayList<String>();
         Value[] values =
             runtimeRoleNode.getProperty(pentahoJcrConstants.getPHO_BOUNDROLES()).getValues();
         for (Value value : values) {
           logicalRoleNames.add(value.getString());
         }
         map.put(runtimeRoleName, logicalRoleNames);
       }
     }
   }
   // add all immutable bindings
   map.putAll(immutableRoleBindingNames);
   return map;
 }
 public void setRoleDescription(
     Session session, final ITenant theTenant, final String roleName, final String description)
     throws NotFoundException, RepositoryException {
   Group jackrabbitGroup = getJackrabbitGroup(theTenant, roleName, session);
   if (jackrabbitGroup != null
       && TenantUtils.isAccessibleTenant(
           theTenant == null
               ? tenantedRoleNameUtils.getTenant(jackrabbitGroup.getID())
               : theTenant)) {
     if (description == null) {
       jackrabbitGroup.removeProperty("description"); // $NON-NLS-1$
     } else {
       jackrabbitGroup.setProperty(
           "description", session.getValueFactory().createValue(description)); // $NON-NLS-1$
     }
   } else {
     throw new NotFoundException(
         Messages.getInstance()
             .getString("AbstractJcrBackedUserRoleDao.ERROR_0002_ROLE_NOT_FOUND"));
   }
 }
 public IPentahoUser createUser(
     Session session,
     final ITenant theTenant,
     final String userName,
     final String password,
     final String description,
     final String[] roles)
     throws AuthorizableExistsException, RepositoryException {
   ITenant tenant = theTenant;
   String user = userName;
   if (tenant == null) {
     tenant = JcrTenantUtils.getTenant(userName, true);
     user = JcrTenantUtils.getPrincipalName(userName, true);
   }
   if (tenant == null || tenant.getId() == null) {
     tenant = JcrTenantUtils.getCurrentTenant();
   }
   if (!TenantUtils.isAccessibleTenant(tenant)) {
     throw new NotFoundException(
         Messages.getInstance()
             .getString(
                 "AbstractJcrBackedUserRoleDao.ERROR_0006_TENANT_NOT_FOUND", theTenant.getId()));
   }
   String userId = tenantedUserNameUtils.getPrincipleId(tenant, user);
   UserManager tenantUserMgr = getUserManager(tenant, session);
   tenantUserMgr.createUser(userId, password, new PrincipalImpl(userId), ""); // $NON-NLS-1$
   session.save();
   /**
    * This call is absolutely necessary. setUserRolesForNewUser will never * inspect what roles
    * this user is a part of. Since this is a new user * it will not be a part of new roles
    */
   setUserRolesForNewUser(session, tenant, user, roles);
   setUserDescription(session, tenant, user, description);
   session.save();
   createUserHomeFolder(tenant, user, session);
   session.save();
   this.userDetailsCache.removeUserFromCache(userName);
   return getUser(session, tenant, userName);
 }
  private void setUserRolesForNewUser(
      Session session, final ITenant theTenant, final String userName, final String[] roles)
      throws RepositoryException, NotFoundException {
    Set<String> roleSet = new HashSet<String>();
    if (roles != null) {
      roleSet.addAll(Arrays.asList(roles));
    }
    roleSet.add(authenticatedRoleName);

    User jackrabbitUser = getJackrabbitUser(theTenant, userName, session);

    if ((jackrabbitUser == null)
        || !TenantUtils.isAccessibleTenant(
            theTenant == null
                ? tenantedUserNameUtils.getTenant(jackrabbitUser.getID())
                : theTenant)) {
      throw new NotFoundException(
          Messages.getInstance()
              .getString("AbstractJcrBackedUserRoleDao.ERROR_0003_USER_NOT_FOUND"));
    }

    HashMap<String, Group> finalCollectionOfAssignedGroups = new HashMap<String, Group>();
    ITenant tenant = theTenant == null ? JcrTenantUtils.getTenant(userName, true) : theTenant;
    for (String role : roleSet) {
      Group jackrabbitGroup = getJackrabbitGroup(tenant, role, session);
      if (jackrabbitGroup != null) {
        finalCollectionOfAssignedGroups.put(
            tenantedRoleNameUtils.getPrincipleId(tenant, role), jackrabbitGroup);
      }
    }

    ArrayList<String> groupsToAdd = new ArrayList<String>(finalCollectionOfAssignedGroups.keySet());

    for (String groupId : groupsToAdd) {
      finalCollectionOfAssignedGroups.get(groupId).addMember(jackrabbitUser);
      // Purge the UserDetails cache
      purgeUserFromCache(userName);
    }
  }
 public List<IPentahoUser> getUsers(
     Session session, final ITenant theTenant, boolean includeSubtenants)
     throws RepositoryException {
   ArrayList<IPentahoUser> users = new ArrayList<IPentahoUser>();
   if (TenantUtils.isAccessibleTenant(theTenant)) {
     UserManager userMgr = getUserManager(theTenant, session);
     pPrincipalName = ((SessionImpl) session).getJCRName(P_PRINCIPAL_NAME);
     Iterator<Authorizable> it =
         userMgr.findAuthorizables(pPrincipalName, null, UserManager.SEARCH_TYPE_USER);
     while (it.hasNext()) {
       User user = (User) it.next();
       IPentahoUser pentahoUser = convertToPentahoUser(user);
       if (includeSubtenants) {
         users.add(pentahoUser);
       } else {
         if (pentahoUser.getTenant() != null && pentahoUser.getTenant().equals(theTenant)) {
           users.add(pentahoUser);
         }
       }
     }
   }
   return users;
 }
  protected void importRoles(List<RoleExport> roles, Map<String, List<String>> roleToUserMap) {
    IUserRoleDao roleDao = PentahoSystem.get(IUserRoleDao.class);
    ITenant tenant = new Tenant("/pentaho/" + TenantUtils.getDefaultTenant(), true);
    IRoleAuthorizationPolicyRoleBindingDao roleBindingDao =
        PentahoSystem.get(IRoleAuthorizationPolicyRoleBindingDao.class);

    Set<String> existingRoles = new HashSet<>();
    if (roles != null) {
      for (RoleExport role : roles) {
        log.debug("Importing role: " + role.getRolename());
        try {
          List<String> users = roleToUserMap.get(role.getRolename());
          String[] userarray = users == null ? new String[] {} : users.toArray(new String[] {});
          IPentahoRole role1 = roleDao.createRole(tenant, role.getRolename(), null, userarray);
        } catch (AlreadyExistsException e) {
          existingRoles.add(role.getRolename());
          // it's ok if the role already exists, it is probably a default role
          log.info(Messages.getInstance().getString("ROLE.Already.Exists", role.getRolename()));
        }
        try {
          if (existingRoles.contains(role.getRolename())) {
            // Only update an existing role if the overwrite flag is set
            if (isOverwriteFile()) {
              roleBindingDao.setRoleBindings(tenant, role.getRolename(), role.getPermissions());
            }
          } else {
            // Always write a roles permissions that were not previously existing
            roleBindingDao.setRoleBindings(tenant, role.getRolename(), role.getPermissions());
          }
        } catch (Exception e) {
          log.info(
              Messages.getInstance().getString("ERROR.SettingRolePermissions", role.getRolename()),
              e);
        }
      }
    }
  }
  public void setRoleMembers(
      Session session,
      final ITenant theTenant,
      final String roleName,
      final String[] memberUserNames)
      throws RepositoryException, NotFoundException {
    List<IPentahoUser> currentRoleMembers = getRoleMembers(session, theTenant, roleName);
    if (tenantAdminRoleName.equals(roleName)
        && (currentRoleMembers != null && currentRoleMembers.size() > 0)
        && memberUserNames.length == 0) {
      throw new RepositoryException(
          Messages.getInstance()
              .getString(
                  "AbstractJcrBackedUserRoleDao.ERROR_0001_LAST_ADMIN_ROLE", tenantAdminRoleName));
    }
    Group jackrabbitGroup = getJackrabbitGroup(theTenant, roleName, session);

    if ((jackrabbitGroup == null)
        || !TenantUtils.isAccessibleTenant(
            theTenant == null
                ? tenantedRoleNameUtils.getTenant(jackrabbitGroup.getID())
                : theTenant)) {
      throw new NotFoundException(
          Messages.getInstance()
              .getString("AbstractJcrBackedUserRoleDao.ERROR_0002_ROLE_NOT_FOUND"));
    }
    HashMap<String, User> currentlyAssignedUsers = new HashMap<String, User>();
    Iterator<Authorizable> currentMembers = jackrabbitGroup.getMembers();
    while (currentMembers.hasNext()) {
      Authorizable member = currentMembers.next();
      if (member instanceof User) {
        currentlyAssignedUsers.put(member.getID(), (User) member);
      }
    }

    HashMap<String, User> finalCollectionOfAssignedUsers = new HashMap<String, User>();
    if (memberUserNames != null) {
      ITenant tenant = theTenant == null ? JcrTenantUtils.getTenant(roleName, false) : theTenant;
      for (String user : memberUserNames) {
        User jackrabbitUser = getJackrabbitUser(tenant, user, session);
        if (jackrabbitUser != null) {
          finalCollectionOfAssignedUsers.put(
              tenantedRoleNameUtils.getPrincipleId(tenant, user), jackrabbitUser);
        }
      }
    }

    ArrayList<String> usersToRemove = new ArrayList<String>(currentlyAssignedUsers.keySet());
    usersToRemove.removeAll(finalCollectionOfAssignedUsers.keySet());

    ArrayList<String> usersToAdd = new ArrayList<String>(finalCollectionOfAssignedUsers.keySet());
    usersToAdd.removeAll(currentlyAssignedUsers.keySet());

    for (String userId : usersToRemove) {
      jackrabbitGroup.removeMember(currentlyAssignedUsers.get(userId));
    }

    for (String userId : usersToAdd) {
      jackrabbitGroup.addMember(finalCollectionOfAssignedUsers.get(userId));

      // Purge the UserDetails cache
      purgeUserFromCache(userId);
    }
  }
  @Override
  public List<String> getBoundLogicalRoleNames(
      Session session, ITenant tenant, List<String> runtimeRoleNames)
      throws NamespaceException, RepositoryException {
    if ((tenant == null) || (tenant.getId() == null)) {
      return getBoundLogicalRoleNames(session, runtimeRoleNames);
    }

    if (!TenantUtils.isAccessibleTenant(tenant)) {
      return new ArrayList<String>();
    }

    final List<String> uncachedRuntimeRoleNames = new ArrayList<String>();
    final Set<String> cachedBoundLogicalRoleNames = new HashSet<String>();
    for (String runtimeRoleName : runtimeRoleNames) {
      String roleName = tenantedRoleNameUtils.getPrincipleName(runtimeRoleName);
      String roleId = tenantedRoleNameUtils.getPrincipleId(tenant, runtimeRoleName);
      Object fromRegionCache =
          cacheManager.getFromRegionCache(LOGICAL_ROLE_BINDINGS_REGION, roleId);
      if (fromRegionCache != null) {
        cachedBoundLogicalRoleNames.addAll((Collection<String>) fromRegionCache);
      } else {
        uncachedRuntimeRoleNames.add(roleName);
      }
    }
    if (uncachedRuntimeRoleNames.isEmpty()) {
      // no need to hit the repo
      return new ArrayList<String>(cachedBoundLogicalRoleNames);
    }

    PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session);
    final String phoNsPrefix =
        session.getNamespacePrefix(PentahoJcrConstants.PHO_NS) + ":"; // $NON-NLS-1$
    final String onlyPentahoPattern = phoNsPrefix + "*"; // $NON-NLS-1$
    HashMultimap<String, String> boundLogicalRoleNames = HashMultimap.create();
    Node runtimeRolesFolderNode = getRuntimeRolesFolderNode(session, tenant);
    NodeIterator runtimeRoleNodes = runtimeRolesFolderNode.getNodes(onlyPentahoPattern);
    if (!runtimeRoleNodes.hasNext()) {
      // no bindings setup yet; fall back on bootstrap bindings
      for (String runtimeRoleName : uncachedRuntimeRoleNames) {
        String roleId = tenantedRoleNameUtils.getPrincipleId(tenant, runtimeRoleName);
        if (bootstrapRoleBindings.containsKey(runtimeRoleName)) {
          boundLogicalRoleNames.putAll(roleId, bootstrapRoleBindings.get(runtimeRoleName));
        }
      }
    } else {
      for (String runtimeRoleName : uncachedRuntimeRoleNames) {
        if (NodeHelper.hasNode(runtimeRolesFolderNode, phoNsPrefix, runtimeRoleName)) {
          Node runtimeRoleFolderNode =
              NodeHelper.getNode(runtimeRolesFolderNode, phoNsPrefix, runtimeRoleName);
          if (runtimeRoleFolderNode.hasProperty(pentahoJcrConstants.getPHO_BOUNDROLES())) {
            Value[] values =
                runtimeRoleFolderNode
                    .getProperty(pentahoJcrConstants.getPHO_BOUNDROLES())
                    .getValues();
            String roleId = tenantedRoleNameUtils.getPrincipleId(tenant, runtimeRoleName);
            for (Value value : values) {
              boundLogicalRoleNames.put(roleId, value.getString());
            }
          }
        }
      }
    }
    // now add in immutable bound logical role names
    for (String runtimeRoleName : uncachedRuntimeRoleNames) {
      if (immutableRoleBindings.containsKey(runtimeRoleName)) {
        String roleId = tenantedRoleNameUtils.getPrincipleId(tenant, runtimeRoleName);
        boundLogicalRoleNames.putAll(roleId, immutableRoleBindingNames.get(runtimeRoleName));
      }
    }

    // update cache
    Map<String, Collection<String>> stringCollectionMap = boundLogicalRoleNames.asMap();
    for (Entry<String, Collection<String>> stringCollectionEntry : stringCollectionMap.entrySet()) {
      cacheManager.putInRegionCache(
          LOGICAL_ROLE_BINDINGS_REGION,
          stringCollectionEntry.getKey(),
          stringCollectionEntry.getValue());
    }

    // now add in those runtime roles that have no bindings to the cache
    for (String runtimeRoleName : uncachedRuntimeRoleNames) {
      String roleId = tenantedRoleNameUtils.getPrincipleId(tenant, runtimeRoleName);

      if (cacheManager.getFromRegionCache(LOGICAL_ROLE_BINDINGS_REGION, roleId) == null) {
        cacheManager.putInRegionCache(
            LOGICAL_ROLE_BINDINGS_REGION, roleId, Collections.emptyList());
      }
    }

    // combine cached findings plus ones from repo
    Set<String> res = new HashSet<String>();
    res.addAll(cachedBoundLogicalRoleNames);
    res.addAll(boundLogicalRoleNames.values());
    return new ArrayList<String>(res);
  }