LDAP/RDS Group Membership Viewer

This utility provides a mechanism to view LDAP (RDS) group membership.
 
With Rational Directory Server, the user and group lists often get truncated and it is almost impossible to inspect group membership from within DOORS.
 
DOORS will only “download” the users and groups that it needs for the current session, so when you open a module and look at the properties, doors downloads just the users and groups that apply to that item.
 
This tool forces the users and groups to be read by doors and then stores them for access later.
 
Group members are cached using configuration files and can be updated on demand.

This can take a few minutes to run, but once you have done that then the user/group membership is readily available for you to browse.

 I do not know why, but during testing this returned different results for different users.


//  View LDAP Group Membership
/*
 Provides a mechanism to view LDAP (RDS) group membership.
 
 With Rational Directory Server, the user and gtroup lists often get truncated and it is
 almost impossible to inspect group membership from within DOORS.
 
 DOORS will only "download" the users and groups that it needs for the current session, so when you open
 a module and look at the properties, doors downloads just the users andd groups that apply to that item.
 
 This tool forces the users and groups to be read by doors and then stores them for access later.
 
 Group members are cached using configuration files and can be updated on demand.

 This can take a long time to run, but once you have done that then the user/group membership is readily available.

 I do not know why, but during testing this returned different results for different users.

 07-AUG-2012  Tony Goodman
 
*/
pragma runLim, 0

#include <SmartDXL/smartDialogs.inc>
// Use these to reduce the seacrhing required for users and groups.
// For example, if you know that your usernames are made up of numbers only,
// then just have numbers in the USER_CHARS variable.
// The following also assumes that all groups used by DOORS begin with "DOORS"
// Note that user and group names are not case sensitive in RDS or LDAP, so you don't need to include
// uppercase letters.

string USER_PREFIX = ""
string GROUP_PREFIX = "DOORS"

string USER_CHARS = "0123456789"
string GROUP_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789_ "
DB  dbMain = null
DBE dbeGroups = null
DBE dbeMembers = null
DBE dbeSplitter = null
DBE dbeReload = null
DBE dbeLastUpdated = null

string CONF_DIR = "ldap_groups"
string LAST_UPDATED = "last_updated"
string dummy[] = {}
 
 
/******************************************************************************
 recordDate
******************************************************************************/
void recordDate()
{
 ConfStream conf = null
 
 conf = confWrite(CONF_DIR "\\" LAST_UPDATED , confUser)
 
 if (!null conf)
 {
  conf << stringOf(dateAndTime(today)) "\n"
  
  close(conf)
 }
}

/******************************************************************************
 recordMembers
******************************************************************************/
void recordMembers(Group g)
{
 ConfStream conf = null
 User u = null
 string groupName = ""
 string userName = ""
 
 Skip skipUsers = createString
 
 if (!confFileExists(CONF_DIR, confUser))
    {
        // add directory
        confMkdir(CONF_DIR, confUser)
    }
 
 groupName = g.name
 
 conf = confWrite(CONF_DIR "\\" groupName, confUser)
 
 if (!null conf)
 {
  for u in g do
  {
   userName = u.name
   
   put(skipUsers, userName, userName)
  }
 
  for userName in skipUsers do
  {
   conf << userName "\n"
  }
  
  close(conf)
 }
}
 
/*********************************
 Returns true if the count is suspicious
**********************************/
bool truncated(int count)
{
 return(count == 499 || count == 500 || count == 999 || count == 1000)
}

/****************************************************************
 Load all LDAP groups beginning with the supplied prefix to the DOORS client.
 Call with empty string parameter for a complete list... and a long wait.
*****************************************************************/
void loadLdapGroups(string prefix)
{
 Group g = null
 int i = 0
 int count = 0
 
 for g in groupList(prefix "*") do
 {
  count++
 }
 
 print(count " groups beginning with " prefix "\n")
 
 if (truncated(count))
 {
  for (i = 0; i < length(GROUP_CHARS); i++)
  {
   loadLdapGroups(prefix GROUP_CHARS[i:i])
  }
 }
}
/********************************************************************
 Load all LDAP users beginning with a digit to the DOORS client.
 Call with empty string parameter for the complete list of users with a numeric id.
*********************************************************************/
void loadLdapUsers(string prefix)
{
 User u = null
 int i = 0
 int count = 0
 
 for (i = 0; i < length(USER_CHARS); i++)
 {
  count = 0
  
  for u in userList(prefix USER_CHARS[i:i] "*") do
  {
   count++
  }
  
  print(count " users beginning with " prefix USER_CHARS[i:i] "\n")
  
  if (truncated(count))
  {
   loadLdapUsers(prefix USER_CHARS[i:i])
  }
 }
}
/******************************
 loadLdapUsersAndGroups
*******************************/
void loadLdapUsersAndGroups()
{
 Group g = null
 
 loadLdapUsers(USER_PREFIX)
 loadLdapGroups(GROUP_PREFIX)
 
 for g in groupList do
 {
  recordMembers(g)
 }
 
 recordDate()
}
/***********************
 initGroupNames
***********************/
void initGroupNames()
{
 ConfStream conf = null
 string s = ""
 string lastUpdated = ""
 
 for s in confDirectory(CONF_DIR, confUser) do
 {
  if (s == "." || s == "..") continue
  
  if (s == LAST_UPDATED) continue

  insert(dbeGroups, noElems(dbeGroups), s, iconGroup)
 }
 
 if (confFileExists(CONF_DIR "\\" LAST_UPDATED, confUser))
    {
  conf = confRead(CONF_DIR "\\" LAST_UPDATED, confUser)
 
  if (!null conf)
  {
   conf >> lastUpdated
   close(conf)
  }
  
  set(dbeLastUpdated, "Last updated: " lastUpdated)
 }
}

/***********************
 doSelect
***********************/
void (DBE dbe, int i)
{
 ConfStream conf = null
 User u = null
 string userName = ""
 string userEmail = ""
 string groupName = ""
 int userCount = 0
 
 
 groupName = get(dbeGroups)
 
 empty(dbeMembers)
 
 conf = confRead(CONF_DIR "\\" groupName, confUser)

 if (!null conf)
 {
  while (true)
  {
   conf >> userName
   
   if (end conf) break
   
   u = find(userName)
   
   if (!null u)
   {
    userEmail = u.email
    insert(dbeMembers, userCount, "", iconUser)
    set(dbeMembers, userCount, 0, userName)
    set(dbeMembers, userCount, 1, userEmail)
    userCount++
   }
  }
  
  close(conf)
 }
}
 
/***********************
 doSelect
***********************/
void doSelect(DBE dbe, int i)
{
 ConfStream conf = null
 User u = null
 string userName = ""
 string userEmail = ""
 string groupName = ""
 int userCount = 0
 
 
 groupName = get(dbeGroups)
 
 empty(dbeMembers)
 
 conf = confRead(CONF_DIR "\\" groupName, confUser)

 if (!null conf)
 {
  while (true)
  {
   conf >> userName
   
   if (end conf) break
   
   u = find(userName)
   
   if (!null u)
   {
    userEmail = u.email
    insert(dbeMembers, userCount, "", iconUser)
    set(dbeMembers, userCount, 0, userName)
    set(dbeMembers, userCount, 1, userEmail)
    userCount++
   }
  }
  
  close(conf)
 }
}

/***********************
 doActivate
***********************/
void doActivate(DBE dbe, int i)
{
 doSelect(dbe, i)
}

/***********************
 doDeselect
***********************/
void doDeselect(DBE dbe, int i)
{
 ;
}

/***********************
 doReload
***********************/
void doReload(DB db)
{
 if (!confirm("Reloading users and groups from LDAP will take several minutes.\n" //-
     "Are you sure you want to continue?"))
 {
  return
 }
 
 loadLdapUsersAndGroups()
 
 initGroupNames()
}
/***********************
 createDialog
***********************/
void createDialog()
{
 dbMain = smartDialog(dbExplorer, "LDAP Group Membership Viewer")
 
 dbeGroups = listView(dbMain, 0, 315, 20, dummy)
 dbeGroups->"right"->"unattached"
 dbeGroups->"bottom"->"unattached"
 dbeGroups->"left"->"form"
 
 dbeMembers = listView(dbMain, 0, 315, 20, dummy)
 dbeMembers->"left"->"unattached"
 dbeMembers->"top"->"aligned"->dbeGroups
 dbeMembers->"bottom"->"unattached"
 dbeMembers->"right"->"form"
 
 dbeSplitter = splitter(dbMain, dbeGroups, dbeMembers, 5)
 dbeSplitter->"top"->"aligned"->dbeGroups
 dbeSplitter->"bottom"->"unattached"
 dbeSplitter->"left"->"unattached"
 dbeSplitter->"right"->"unattached"
 
 dbeLastUpdated = label(dbMain, "Last updated: ")
 dbeLastUpdated->"top"->"flush"->dbeGroups
 dbeLastUpdated->"left"->"form"
 dbeLastUpdated->"right"->"unattached"
 dbeLastUpdated->"bottom"->"form"
 
 
 dbeReload = apply(dbMain, "Reload from LDAP", doReload)
 
 realize(dbMain)
 
 set(dbeGroups, doSelect, doDeselect, doActivate)
 
 insertColumn(dbeGroups, 0, "Group Name", 290, iconNone)
 
 initGroupNames()
 
 insertColumn(dbeMembers, 0, "User Name", 100, iconNone)
 insertColumn(dbeMembers, 1, "Email Address", 200, iconNone)
 
 show(dbMain)
}

/***********************
 MAIN
***********************/
createDialog()