8.2. Integrating Existing Users/Groups

By default, the ERES database provides the persistent storage for users, groups, and their relationships. However, many users already have a set of users and groups, as well as the persistent storage mechanism in place. In these cases, duplicating users and groups in the new reporting environment is inefficient, time-consuming, and requires extra administration overhead.

To prevent these issues, ERES provides three different ways that users can integrate their existing user/group framework into the reporting system. The first option is to retrieve users and groups from an LDAP server. This connection and setup is detailed in Section 1.4.1.4 - LDAP Settings. The second option is to retrieve users and groups from an existing database. The third option is to use the UserSecurityProvider interface which provides an open API allowing users to retrieve/implement users and groups from any source.

8.2.1. Using a Database

If your existing users are in a database, ERES provides a simple implementation of the UserSecurityProvider that can be configured using a properties file. This implementation allows you to supply the connection information for the database as well as SQL statements for all the user/group related actions. Note that this implementation will not work in all circumstances. If your schema cannot retrieve/set the proper information with a single SQL statement, you may need to provide your own implementation of UserSecurityProvider.

The properties file is named user-database.properties, and should be placed in the <ERESInstallDir>/WEB-INF/orguserdb directory. A sample properties file is shown below:

#############################################################
#Whether to use custom database for user/group
custom.user.database=true
#############################################################

#############################################################
#If custom.user.database=true, then use these information to
#connect to the database.
custom.user.database.url=jdbc:hsqldb:C:/ERES/data/quadbasedb
custom.user.database.jdbcDriver=org.hsqldb.jdbcDriver
custom.user.database.login=sa
custom.user.database.password=
#############################################################

#############################################################
#Whether each of the methods in UserSecurityProvider
#is enabled.
#-----------------------------------------------------------
getUsers.enable=true
getUsers.sql=Select username, fullname, email, password, user_role, id, securitylevel From users Order
By username
#-----------------------------------------------------------
getGroups.enable=true
getGroups.sql=Select name, description, id, securitylevel From groups Order By name
#-----------------------------------------------------------
getGroupRelations.enable=true
getGroupRelations.sql=SELECT parent_g.name, child_g.name FROM group_relations r, groups parent_g, groups
child_g WHERE r.parent_id = parent_g.id AND r.child_id = child_g.id
#-----------------------------------------------------------
getGroupUserRelations.enable=true
getGroupUserRelations.sql=Select g.name, u.username From group_user_relations gr, groups g, users u
Where gr.group_id=g.id And gr.user_id=u.id Order By g.name
#-----------------------------------------------------------
getUserParents.enable=true
getUserParents.sql=SELECT r.group_id, g.name FROM group_user_relations r, groups g WHERE r.group_id =
g.id AND r.user_id=?
#-----------------------------------------------------------
getGroupParents.enable=true
getGroupParents.sql=Select parent_id From group_relations Where child_id=?
#-----------------------------------------------------------
deleteUser.enable=true
deleteUser.sql=Delete From users Where username=?
#-----------------------------------------------------------
deleteGroup.enable=true
deleteGroup.sql=Delete From groups Where name=?
#-----------------------------------------------------------
createUser.enable=true
createUser.sql=Insert Into users (id, username, fullname, email, password, user_role, securitylevel)
Values (?, ?, ?, ?, ?, ?, ?)
#-----------------------------------------------------------
createGroup.enable=true
createGroup.sql1=Insert Into groups (id, name, description, securitylevel) Values (?, ?, ?, ?)
createGroup.sql2=Delete From group_relations Where parent_id=?
createGroup.sql3=Delete From group_user_relations Where group_id=?
createGroup.sql4=Insert Into group_relations (parent_id, child_id) Values (?, ?)
#-----------------------------------------------------------
updateUser.enable=true
updateUser.sql=Update users Set username=?, fullname=?, email=?, password=?, user_role=?,
securitylevel=? Where username=?
#-----------------------------------------------------------
updateGroup.enable=true
updateGroup.sql1=Update groups Set name=?, description=?, securitylevel=? Where name=?
updateGroup.sql2=Delete From group_relations Where parent_id=?
updateGroup.sql3=Delete From group_user_relations Where group_id=?
updateGroup.sql4=Insert Into group_relations (parent_id, child_id) Values (?, ?)
#-----------------------------------------------------------
addGroupUserRelation.enable=true
addGroupUserRelation.sql=Insert Into group_user_relations (group_id, user_id) Values (?, ?)
#-----------------------------------------------------------
setSecurityLevels.enable=true
setSecurityLevels.sql1=Update users Set securitylevel=? Where username=?
setSecurityLevels.sql2=Update groups Set securitylevel=? Where name=?
#-----------------------------------------------------------
resetSecurityLevel.enable=true
#-----------------------------------------------------------
getGroupsBySecurityLevel.enable=true
getGroupsBySecurityLevel.sql=Select name From Groups Where securitylevel=?
#-----------------------------------------------------------
getUsersBySecurityLevel.enable=true
getUsersBySecurityLevel.sql=Select username From users Where securitylevel=?
#-----------------------------------------------------------
#############################################################
        

The question marks in the SQL statements will be supplied by the ERES engine when it runs the queries. For any method that isn't enabled, ERES will save that information in the ERES database. Depending on your configuration, saving some information in the ERES database, and some in your own may not be able to work correctly.

8.2.2. Implementing UserSecurityProvider

For maximum flexibility, ERES allows users to provide their own implementation of users and groups. The UserSecurityProvider interface provides open APIs into all the methods that set/retrieve user and group information. Implementing UserSecurityProvider allows you to retrieve user/group information from any source, and allows you to integrate your user database if the schema prevents you from retrieving the correct information with a single query. Below is a sample UserSecurityProvider implementation:

import java.util.*;

import quadbase.reportorganizer.data.*;
import quadbase.reportorganizer.ext.*;

/**
* A sample implementation of UserSecurityProvider that provides hard-coded
* initialized users/groups/security that does not have any data persistent
* mechanism.
*/
public class MyUserSecurityProvider implements UserSecurityProvider {

      User[] users;
      Group[] groups;
      GroupRelation[] gr;
      GroupUserRelation[] gur;

      /**
      * Initializes the provider with dummy users/groups/security
      */
      public MyUserSecurityProvider() {
            users = new User[6];
            users[0] = createUser("admin");
            users[1] = createUser("jason");
            users[2] = createUser("ricky");
            users[3] = createUser("jordan");
            users[4] = createUser("oneal");
            users[5] = createUser("jerry");

            groups = new Group[6];
            groups[0] = createGroup("nba");
            groups[1] = createGroup("sports");
            groups[2] = createGroup("testers");
            groups[3] = createGroup("managers");
            groups[4] = createGroup("marketing");
            groups[5] = createGroup("engineers");

            gr = new GroupRelation[3];
            gr[0] = new GroupRelation("sports","nba");
            gr[1] = new GroupRelation("managers","marketing");
            gr[2] = new GroupRelation("engineers","testers");

            gur = new GroupUserRelation[6];
            gur[0] = new GroupUserRelation("managers", "jason");
            gur[1] = new GroupUserRelation("nba", "jordan");
            gur[2] = new GroupUserRelation("marketing", "ricky");
            gur[3] = new GroupUserRelation("nba", "oneal");
            gur[4] = new GroupUserRelation("testers", "jerry");
            gur[5] = new GroupUserRelation("testers", "jason"); 

      }

      public User[] getUsers() throws Exception {
            return users; }

      public Group[] getGroups() throws Exception {
            return groups; }

      public GroupRelation[] getGroupRelations() throws Exception {
            return gr; }

      public GroupUserRelation[] getGroupUserRelations() throws Exception {
            return gur; }

      public String[] getUserParents(String username) throws Exception {
            Vector v = new Vector();
            for (int i = 0; i < gur.length; i++)
                  if (gur[i].getUserName().equals(username))
                        v.add(gur[i].getGroupName()); return toStringArr(v); }

      public String[] getGroupParents(String groupname) throws Exception {
            Vector v = new Vector();
            for (int i = 0; i < gr.length; i++)
                  if (gr[i].getChildName().equals(groupname))
                        v.add(gr[i].getParentName()); return toStringArr(v); }

      public void deleteUser(String username) throws Exception {
            if (users.length == 0) return;
            User[] users2 = new User[users.length-1];
            int j = 0;
            for (int i = 0; i < users.length; i++) {
                  if (j == users.length-1 && !users[i].getName().equals(username))
                        return; if (!users[i].getName().equals(username)) {
                        users2[j] = users[i];
                        j += 1; } }
            users = users2; }

      /**
      * Delete a Group. Also deletes the group relationships and
      * group-user relationships
      * that references this GROUPNAME.
      * @param groupname the group name
      */
      public void deleteGroup(String groupname) throws Exception {
            if (groups.length == 0) return;
            Group[] groups2 = new Group[groups.length-1];
            int j = 0;
            for (int i = 0; i < groups.length; i++) {
                  if (j == groups.length-1 && !groups[i].getName().equals(groupname))
                        return; if (!groups[i].getName().equals(groupname)) {
                        groups2[j] = groups[i];
                        j += 1; } }
            groups = groups2;

            Vector v = new Vector();
            for (int i = 0; i < gr.length; i++) {
                  if (gr[i].getParentName().equals(groupname) ||
                        gr[i].getChildName().equals(groupname)) continue; v.add(gr[i]); }
            GroupRelation[] gr2 = new GroupRelation[v.size()];
            for (int i = 0; i < gr2.length; i++)
                  gr2[i] = (GroupRelation) v.get(i); gr = gr2;

            v = new Vector();
            for (int i = 0; i < gur.length; i++) {
                  if (gur[i].getGroupName().equals(groupname)) continue;
                  v.add(gur[i]); }
            GroupUserRelation[] gur2 = new GroupUserRelation[v.size()];
            for (int i = 0; i < gur2.length; i++)
                  gur2[i] = (GroupUserRelation) v.get(i); gur = gur2; }

      public void createUser(User user) throws Exception {
            User[] users2 = new User[users.length+1];
            System.arraycopy(users, 0, users2, 0, users.length);
            users2[users2.length-1] = user;
            users = users2; }

      public void updateUser(User user) throws Exception {
            for (int i = 0; i < users.length; i++) {
                  if (users[i].getName().equals(user.getName())) {
                        users[i] = user;
                        return; } } }

      /**
      * Create a new Group.
      * @param parentGroup create this group
      * @param childUsers set the group to have these child users
      * @param childGroups set the group to have these child groups
      */
      public void createGroup(Group parentGroup, User[] childUsers, Group[] childGroups) throws Exception {
            addGroup(parentGroup);

            if (childUsers != null && childUsers.length > 0) {
                  for (int i = 0; i < childUsers.length; i++) {
                        addGroupUserRelation (parentGroup.getName(), childUsers[i].getName()); } }

            if (childGroups != null && childGroups.length > 0) {
                  GroupRelation[] gr2 = new GroupRelation[gr.length+childGroups.length];
                  System.arraycopy(gr, 0, gr2, 0, gr.length);
                  int j = 0;
                  for (int i = gr.length; i < gr2.length; i++) {
                        gr2[i] = new GroupRelation(parentGroup.getName(), childGroups[j].getName());
                        j++; }
                  gr = gr2; } }

      /**
      * Update a Group. This simple implementation simply calls
      * deleteGroup(parentGroup.getName()) and calls
      * createGroup(parentGroup, childUsers, childGroups);
      *
      * @param parentGroup update this group
      * @param childUsers set the group to have these child users
      * @param childGroups set the group to have these child groups
      */
      public void updateGroup(Group parentGroup, User[] childUsers, Group[] childGroups) throws Exception {
            deleteGroup(parentGroup.getName());
            createGroup(parentGroup, childUsers, childGroups); }

      public void addGroupUserRelation(String groupname, String username) throws Exception {
            GroupUserRelation[] gur2 = new GroupUserRelation[gur.length+1];
            System.arraycopy(gur, 0, gur2, 0, gur.length);
            gur2[gur2.length-1] = new GroupUserRelation(groupname, username);
            gur = gur2; }

      // SECURITY LEVEL ///////////////////////////////////////////////////////

      /**
      * Sets the security level(s) for a group or user of the specified name(s)
      * Also sets the security level(s) for group or user that is not in NAME
      * but with the same SECLEVEL to -1 (Can simply call
      * resetSecurityLevel(secLevel) in the first line of this method
      * to achieve this).
      * @param secLevel the result security level number
      * @param name an array of name(s) to change
      * @param isGroup whether the name[i] is a group (isGroup[i]==true)
      * or a user (isGroup[i]==false).
      */
      public void setSecurityLevels(int secLevel, String[] name, boolean[] isGroup) throws Exception {
            resetSecurityLevel(secLevel);
            for (int i = 0; i < name.length; i++) {
                  if (isGroup[i]) {
                        for (int j = 0; j < groups.length; j++)
                              if (groups[j].getName().equals(name[i])) {
                                    groups[j].setSecurityLevel(secLevel);
                                    break; } } else {
                        for (int j = 0; j < users.length; j++)
                              if (users[j].getName().equals(name[i])) {
                                    users[j].setSecurityLevel(secLevel);
                                    break; } } } }

      /**
      * Resets (set to -1) the security level number of all groups
      * and users whose security level number is SECLEVEL.
      * @param secLevel the security level number of the group/user
      */
      public void resetSecurityLevel(int secLevel) throws Exception {
            for (int i = 0; i < users.length; i++)
                  if (users[i].getSecurityLevel() == secLevel)
                        users[i].setSecurityLevel(-1); for (int i = 0; i < groups.length; i++)
                  if (groups[i].getSecurityLevel() == secLevel)
                        groups[i].setSecurityLevel(-1); }

      /**
      * @param secLevel the security level number of the group
      * @return the Group names of all groups with SECLEVEL
      */
      public String[] getGroupsBySecurityLevel(int secLevel) throws Exception {
            Vector v = new Vector();
            for (int i = 0; i < groups.length; i++)
                  if (secLevel == groups[i].getSecurityLevel())
                        v.add(groups[i].getName()); String[] result = new String[v.size()];
            for (int i = 0; i < result.length; i++)
                  result[i] = (String) v.get(i); return result; }

      /**
      * @param secLevel the security level number of the user
      * @return the User names of all users with SECLEVEL
      */
      public String[] getUsersBySecurityLevel(int secLevel) throws Exception {
            Vector v = new Vector();
            for (int i = 0; i < users.length; i++)
                  if (secLevel == users[i].getSecurityLevel())
                        v.add(users[i].getName()); String[] result = new String[v.size()];
            for (int i = 0; i < result.length; i++)
                  result[i] = (String) v.get(i); return result; }

      User createUser(String name) {
            return new User(name, //name
                              name + " full name", //full name
                              name, //password
                              name + "@example.com", //email
                              User.DESIGNER, //role
                              -1); //security level }

      Group createGroup(String name) {
            return new Group(name, //name
                              name + " desc", //description
                              -1); //security level }

      void addGroup(Group g) {
            Group[] g2 = new Group[groups.length+1];
            System.arraycopy(groups, 0, g2, 0, groups.length);
            g2[g2.length-1] = g;
            groups = g2; }

      static String[] toStringArr(Vector v) {
            String[] p = new String[v.size()];
            for (int i = 0; i < p.length; i++)
                  p[i] = (String) v.get(i); return p; } 

}
        

In the previous sample, the users and groups are defined a simple arrays in the code. As with the database properties file, any method that you do not implement in the UserSecurityProvider interface will use the default ERES database as the storage mechanism.

8.2.2.1. Deploying UserSecurityProvider

The UserSecurityProvider class can be set as a server option in ERES. You can set this in one of two places. The first option is the Admin Console. You can specify the class in the Server Options tab. For more information about server configuration options, see Section 1.4.1.3 - Server Options. You can also specify the class by modifying the QB.properties under <ERESInstallDir>/WEB-INF/classes. However, editing configuration files directly is not recommended and should be done only in case when the ERES server cannot be started because incorrect values have been provided through the Admin Console.