Skip to main content

skip to main content

developerWorks  >  Information Management  >

Reuse enterprise user data in DB2 Content Manager

Replicating users and groups to DB2 Content Manager, Version 8, Java API

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


New site feature

Check out our new article design and features. Tell us what you think.


Rate this page

Help us improve this content


Level: Introductory

Gabriela Barowsky (gbarowsky@de.ibm.com), IBM Certified Solution Designer DB2 Content Manager V8, IBM

06 Oct 2005

Get a blueprint for replicating user repositories, like LDAP directories, databases, or simply sets of files, to IBM® DB2® Content Manager, V8, using the Content Manager Java API. This article also provides sample code for handling users and user groups in Content Manager.

Introduction

Content Manager (CM) needs its own built-in user repository to grant users access to text documents, video files, pictures, and whatever else is stored in the system. In most cases, CM needs to be integrated into a complex enterprise environment. It coexists with several other systems that have their own user repositories or use a common one, like an LDAP directory. Reusing such user information in CM is a common requirement. CM provides some tools to manage users and user groups, but in certain cases, these tool are not sufficient.

This article describes how the CM Java API can be used to extend the functionality of CM. It contains sample code that shows how to access an arbitrary, generic back-end user repository and use the CM Java API in order to replicate the managed user information to CM. The generic back-end user repository in the sample code can be adjusted easily in order to access, for example, a company's specific LDAP directory, a proprietary database, or a set of files containing user information. According to the information stored in the back-end user repository, users and user groups will be created, updated, and deleted in CM by the sample program.

Even if you are not interested in the proposed replication program, the article also provides sample code for managing authorization and authentication in CM using the CM Java API. (No sample code for it is shipped with CM.)


Figure 1. Replication of user repositories to CM
Replication of user repositories to CM


Back to top


Users, user groups, and ACLs in CM V8

This section gives a short overview of authentication and authorization concepts of CM V8, as they will be needed to understand the replication process. For more details, please refer to the CM V8 documentation.

Managing users and user groups is mandatory when working with IBM DB2 Content Manager, V8 in a production environment. Without id and password, a user is not granted access to the CM system. Furthermore, the user's access rights (or "privileges") have to be defined appropriately. Not every user should have "super user access," whereas giving users too few privileges may prevent them from doing their jobs. Apart from these authorization aspects, CM users are assigned several other properties.

Following is a list of all user-related attributes in CM V8 and their default values when no explicit values are specified:

  • Name (unique identifier, mandatory)
  • Description (optional, default: blank)
  • User's distinguish name (additional information, optional, default: blank)
  • Password (mandatory)
  • Password expiration (mandatory, default: 180 days)
  • Privilege set (used for authorization, mandatory, default: ClientUserReadOnly)
  • Grant privilege set (mandatory, default: ClientUserReadOnly)
  • Collection name (mandatory, default: first defined in system)
  • Default item ACL name (mandatory, default: PublicReadACL)
  • Resource Manager name (mandatory)
  • Domain name (mandatory, if using administrative domains)

Notice that the default values in the list above are not documented like this, so they may change in future releases.

Often, for example, when users have the same job role, they are joined in a common CM group. It is not necessary to define user groups in CM V8, but it simplifies administration, especially when you define Access Control Lists (ACLs). A CM user group is solely a combination of users; no access rights are stated in a group's definition.

Following is a list of all user group-related attributes in CM V8:

  • Name (unique identifier, mandatory)
  • Description (optional, default: blank)
  • Domain name (mandatory, if using administrative domains)
  • List of users (optional, a group may be empty)

Authorization is handled in CM V8 with Access Control Lists (ACLs). ACLs contain pairs of privilege sets that are assigned to users or user groups. Linking ACLs to stored objects, like item types, define which operation the users or user groups in the ACL may perform on the corresponding objects. (For example, the items.)



Back to top


CM V8 tools for managing users and user groups

CM 8 offers two built-in functions to manage users and user groups:

  • System Administration Client
  • LDAP Import Utility

The System Administration Client provides a GUI with which you can perform most of the CM V8 related administrative tasks. In the authorization and authentication areas of the client, you can add, modify, or delete users, user groups, privilege sets, and ACLs. Each of these objects are modified one by one, meaning that the administrator uses his mouse and keyboard to define the changes. The System Administration Client is intended for minor system changes. It can be a quite time-consuming and fault-prone task when you are handling hundreds of users in a large enterprise.

Since Version 8.3, the System Administration Client also encloses the useful capability XML Export/Import. You can export/import objects to/from an XML file or directly to another CM server. The extracted metadata includes data model objects, such as item types and their attributes, and administration objects, such as user definitions and access control lists. The aim of these functions is to allow a CM repository to be built for a test system, which is then propagated to acceptance and production. It can't be used to import user data from servers other than CM (unless they use the same XML schema as CM does). As the user has to enter some data in the GUI to start the XML import/export, it is not possible to trigger the replication by an automated process.

The LDAP Import Utility allows importing a large number of user definitions from an LDAP directory to CM at one time. However, not all LDAP servers are supported. Moreover, there are several restrictions concerning the directory structure and the user property data being replicated. For example, at replication, every user is assigned exactly the same privilege set, which implies that no fragmentation of access rights in CM is made. Furthermore, no flexible mapping during the replication is possible; the data is just copied as it is stored in LDAP. The definition of replication filters is also quite rudimentary; it isn't possible, for example, to exclude dedicated users from being replicated.



Back to top


Replicating user repositories to CM V8

As you saw in the previous sections, you can't avoid defining users, user groups, privilege sets, and ACLs in order to work with CM V8 in your enterprise in a convenient way. CM does not share these definitions with other systems. (Otherwise it would mean that CM had to access such systems for every authorization check -- a significant performance issue.) The only thing that can be shared is the password with LDAP. (This is only checked when a user logs in to CM. It, therefore, is not performance critical.) This means that although you still might have a large repository with thousands of enterprise users in it, you have to define these users, user groups, and access rights in CM again if you want to let anybody work with it.

You need an automated way to copy user related information into CM V8. But the CM V8 built-in capabilities might not fit the requirements.

The CM System Administration Client is not appropriate for this task because manually entering data is a source of error and requires a great deal of time if there are more than a dozen users to be managed by CM.

The XML Export/Import and LDAP Import Utility, on the other hand, both use the right approach: thousands of users can be replicated to CM at one time, requiring only a minimum of user interaction. However, both utilities are restricted in the supported back-end technologies, which store the user information. They also do not provide access to databases, flat files, third party back-end systems, or non-supported LDAP servers. Another issue might be the way the utilities copy the user data if, for example, you want to assign different privilege sets to the users, use another matching of the groups, or want to synchronously install a personal desk tray (work list) for every user added to CM during replication.

This article includes source code of a fully functioning tool that replicates users and groups to CM similar to the CM V8 LDAP Import Utility. The used approach is generic and, therefore, not restricted to any special back-end user repository system or a company's specific user data structure. The tool is written in Java and can be easily extended to access a large variety of possible back-end systems using JDBC, JNDI, JCA, third party Java APIs, WebSphere Information Integrator, or others.

Nevertheless, like the CM V8 LDAP Import Utility, the tool also automatically copies a large number of user definitions into CM at once. From the functional point of view, you have to adopt it to your individual business requirements. Authentication and authorization concepts have to be carefully designed. Due to the provided flexibility of CM, there exists a large variety of possibilities of how to arrange users, groups, privilege sets, and ACLs. Therefore, it is not possible to cover all facets here. The most important parts of the tool will be explained.

To keep it simple, the sample user repository that will be replicated consists of the four characters: Sherlock Holmes, James Bond, JR Ewing and Luke Skywalker; and three groups: Thriller, Entertainment, and Empty, as depicted in the following picture:


Figure 2. Sample user repository
Sample user repository


Notice that in the example, the relationship between users and groups is directed. That is, the groups "know" their members, but the users don't "know" to which groups they belong. This connection may also be missing for users or groups: The user "Luke Skywalker" doesn't belong to any group, and the group "Empty" has no members.



Back to top


How the generic back-end user repository replication tool works

The "leading" system, from the replication tool's point of view, will be the external back-end user repository. This means that all changes (adding, modifying, or deleting users or groups) have to be applied to the external user repository only. Running the tool will then apply the changes to CM. This also means that all changes that you apply directly to CM will not be replicated to the external user repository by the tool and will, therefore, be lost in CM after the next replication process.

The replication process consists of the following four major steps, as depicted in Figure 3:

Establish a connection to the CM library server, replicate users, replicate user groups, and close the connection to CM.


Figure 3. Activity graph: Replication overview
Replication of user repositories to CM

The chronological order, meaning that users are replicated before user groups, depends on the direction of the users-to-groups relationship in the sample user repository. Since the sample repository groups "know" their members, it is simpler to replicate all users first. The following step -- the replication of the user groups -- is then based on a consistent set of users and has to only care about group memberships.

Step 1: Initialization of a connection to CM

The following code snippet initializes a connection to a CM library server. It also instantiates a DKUserMgmtICM object, which will be used to access user-related management information from CM later in the code.


Listing 1. Initialize connection to CM
				
// Init connection to CM library server
DKDatastoreICM datastore = new DKDatastoreICM();
datastore.connect(cmLibSrv, userIdCM, passwordCM, "");

// Create user management object
DKUserMgmtICM userMgnt = new DKUserMgmtICM( datastore );

Step 2: Replicating users

In the second step, users will be replicated to CM. As mentioned before, the users will be replicated prior to the user groups because of the direction of the user-to-groups relationship. As the groups "know" who their members are (and the users do not know their affiliations), it is much easier to match the user-to-groups relationships during group-replication (step 3), when all user information is already in a consistent state.

The following picture outlines the user replication. It is composed of three major tasks: Determine which users have to be replicated, specify for each repository user the matching CM user and adjust his properties, and, in reverse, check that for all CM users, the corresponding repository user exists.


Figure 4. Activity graph: Replication of users to CM
Activity graph: Replication of users

The first task is to determine which users have to be replicated. For that, you inquire a list of all users in the back-end user repository, as well as a list of all CM users, in order to make them match. The following code snippet shows how to retrieve a list of all users defined in CM:


Listing 2. Retrieve a list of all CM users
				
// Get list of all users in CM
dkCollection cmUserList = userMgnt.listUserDefs();

Often, you do not want to replicate all users. It is rather desired to blind out back-end user repository members, as well as CM users, from replication. This is useful to prevent administrative or test users in the back-end user repository to be copied to CM, and, likewise, prohibit erasing administrative or test users from CM that are solely defined there. For this, you may define specific filters that will customize the lists of retrieved user information. (The provided sample code contains simple filtering methods for both repositories.)

The second task will be to ensure that every back-end repository user has a corresponding user in CM. Doing so will iterate through the (filtered) list of the back-end repository users. For each user, check if a corresponding user in CM exists. Whether a back-end repository user corresponds to a CM user depends on business requirements. In this sample, two users are considered corresponding to each other if the repository user's user identifier is equal, ignoring case to the CM user's name (as both attributes are unique identifiers).

When a corresponding user in CM is found, check if his attributes remained unchanged. Match every repository user's attribute to the corresponding CM user's attribute. Again, the definition of when user attributes are corresponding to each other depends on business needs. In this example, we use the transformation as outlined in the following table:

Table 1. Mapping of user attributes

Back-end user repository Content Manager
First nameDescription
SurnameDescription
User idName
PasswordPassword
RolePrivilege Set

The following code snippet shows how to update user attributes in CM. The user's name can't be updated in CM, as it is the unique identifier. We are not going to replicate passwords because they usually can't be read from a user repository. Instead, it is common practice to use a CM user exit to check a user's password. Or, if LDAP authentication is enabled in the Library Server, users that are replicated into CM are automatically authenticated externally in LDAP. Consult the CM documentation for more detailed information on CM user exits and LDAP authentication.


Listing 3. Update CM user attributes
				
private void adjustCMUserAttributes( RepositoryUser repositoryUser, 
       DKUserDefICM cmUser) throws Exception {

    // Check if user's attribute values have changed
    boolean isChanged = false;

    // Check if the description (derived from the repository user's  
    // first name and last name) has changed
    if ( ! getDescription(repositoryUser).equalsIgnoreCase
        (cmUser.getDescription())) {
        cmUser.setDescription(getDescription(repositoryUser));
        isChanged = true;
    }
     
    // Check if the user's access rights have changed
    if( ! getPrivilegeSet( repositoryUser.getRole()).
        equalsIgnoreCase( cmUser.getPrivSetName()) ) {
        cmUser.setPrivSetName( getPrivilegeSet
        ( repositoryUser.getRole() ));
        isChanged = true;
    }

    // if any attribute value or access rights have changed
    if( isChanged ) {
        // update user information in CM data store
        userMgnt.update( cmUser );
}

The attribute "setter" methods work on the DKUserDefICM object cmUser. Value changes are not made persistent in the CM datastore until the update method is called on cmUser.

As you can see, we used the helper methods getDescription and getPrivilegeSet that "translate" the repository user's surname, first name, and role into a CM description and privilege set.

If no corresponding CM user is found for an existing repository user, you have to create a new user in CM. The assignment of the attributes is still that which is defined in Table 1.


Listing 4. Create a new CM user
				
private void createCMUser( RepositoryUser repositoryUser ) 
    throws Exception {

    // create a (transient) CM user object
    DKUserDefICM newCMuser = ( DKUserDefICM )userMgnt.createUserDef();
        
    // set the user's attributes
    newCMuser.setName( repositoryUser.getUserID() );      
    newCMuser.setDescription( getDescription( repositoryUser ) );
    newCMuser.setUserDN( "Sample user" );
    newCMuser.setUserPWD( repositoryUser.getPassword() );
    newCMuser.setPwdExpire( 0 );
    newCMuser.setPrivSetName( getPrivilegeSet
      ( repositoryUser.getRole() ) );
    newCMuser.setGrantPrivSetName( "NoPrivs" );
    newCMuser.setCollName( "CBR.CLLCTGRA" );
    newCMuser.setDflItemACLName( "DFLT0000" );
    newCMuser.setObjServerName( "RMDB" );

    // add new user to CM datastore
    userMgnt.add( newCMuser );
}

The CM user object newCMuser is transient until it is stored in the CM datastore, calling userMgnt.add( newCMuser ). Most of the CM user attributes do not need to be set here. As you saw in "Users, user groups, and ACLs in CM V8," CM provides default values for most of them.

After you have successfully mapped every repository user to a CM user, you also have to do the same reversely. In the third and last user-related task, you have to ensure that for every CM user a corresponding repository user exists. If not, the repository user was obviously deleted since the last replication. Consequently, you have to delete the CM user as well. No problem at all. Simply call userMgnt.del( cmUser ), and the user will be deleted from the CM datastore and automatically be removed from all groups and ACLs in which he was contained.


Listing 5. Delete a CM user
				
userMgnt.del( cmUser );

Step 3: Replicating user groups

Now, as you have successfully finished the second step, you have a consistent set of users in both user repositories. As depicted in the Figure 3 (the overview activity graph), the next challenge will be to replicate the group assignments of the users.

The following activity graph shows the steps of the user group's replication process. It is quite similar to Figure 4 (the activity graph for user replication).


Figure 5. Activity graph: Replication of user groups to CM
Activity graph: Replication of user groups

Again, first retrieve a (filtered) list of user groups of both repositories. The following code snippet shows how to retrieve a list of all CM user groups:


Listing 6. Retrieve a list of all CM user groups
				
// Get list of all user groups in CM
dkCollection cmUserGroupList = userMgnt.listUserGroupDefs();

Next, match the two directories. Every (filtered) sample repository user group must have a representing group in CM, and, likewise, all CM user groups must have a corresponding group in the sample repository. In the activity graph above, these are the subgraphs below the activities: "findMatchingCMUserGroupForRepositoryUserGroup" and "findMatchingRepositoryUserGroupForCMUserGroup". Again, I'll give a definition of what I mean by "two user groups are corresponding to each other". For groups, you can take the name as the characterizing attribute, as it is the unique identifier for both repositories. As the repository user groups have no other attributes than their names, the attribute mapping is quite trivial.

Table 2. Mapping of User Group Attributes

Back-end user repository Content Manager
NameName

Start by searching CM user groups for each repository user group and then handle the case that found a matching CM user group. While there are no attributes to adjust, you only have to map both sets of contained users. As you saw before, comparing sets implies that you have to check two subset relationships. First, test if the repository user group contains users that are missing in the corresponding CM user group. If this is the case, then they will be added to the CM user group. The user objects themselves do not have to be created in CM because they already exist as a result of the user replication that happens prior to the replication of user groups. For the same reason, the user attributes are already up to date.

The second check is the opposite subset relationship, meaning that you must verify that every user in the CM group has a counterpart in the repository group. If there is none, you will have to remove the user from the CM group, as the relationship was removed in the repository group. The user itself will not be deleted from CM.

Listing 7 contains the relevant code parts for the actions just described. In order to keep the code clear, only the code that accesses and manipulates CM user groups is provided, and some parts are replaced by pseudo code. (The complete executable code is contained in the download section.)

We still have to search CM user groups for each repository user group and find a matching CM user group. Don't worry, this is simple. As you can see in Figure 5 (the activity graph for user group replication), just create the missing CM user group, add all CM users that correspond to the repository group to the CM group, and update the access rights. In this example, we manage access rights on user group level. The following code snippet shows how to create a new CM user group:


Listing 8. Create a new CM user group
				
// Create a new user group in CM
DKUserGroupDefICM newCMuserGroup=(DKUserGroupDefICM)userMgnt.
createUserGroupDef();
newCMuserGroup.setName( repositoryUserGroup.getGroupname() );
newCMuserGroup.setDescription( "Sample group" );
userMgnt.add( newCMuserGroup );

The code for adding users to a CM user group is already contained in Listing 7. It's important to store the newly created group in the CM datastore by calling userMgnt.add( newCMuserGroup ) before adding users to it. Otherwise, the CM Java API will throw an exception.

How you define access rights very much depends on your business needs. CM provides a lot of possibilities for mapping your requirements to privilege sets and access control lists. In this sample, we use a simple approach: Every CM user group will be added to a fixed ACL named "DW_ACL" that was created in the CM datastore before. The privilege set for such an ACL entry will be "ClientUserAllPrivs". Please note that users who don't belong to any repository user group will not be added to the ACL and will, therefore, not be granted access to stored objects that are linked to DW_ACL. Following is the code for creating a new ACL entry in CM:


Listing 9. Update access rights
				
private void updateAccessRights( String cmUserGroupName ) throws  
Exception {
    
    // Load the ACL named 'DW_ACL' from CM
    DKAccessControlListICM acl = (DKAccessControlListICM)
        (this.authorizationMgmt.retrieveAccessControlList( "DW_ACL" ));

    // Retrieve the privilege set named 'ClientUserAllPrivs' from CM
    DKPrivilegeSetICM privSetCUAP =
        (DKPrivilegeSetICM) this.authorizationMgmt.retrievePrivilegeSet(
            "ClientUserAllPrivs");

    // Create a new ACL entry
    DKACLData aclData =
        new DKACLData(privSetCUAP,cmUserGroupName,
        DKConstantICM.DK_CM_USER_KIND_GROUP);

    // Add ACL data to ACL
    acl.addACLData( aclData );

    // Update ACL
    this.authorizationMgmt.update( acl );
}

At this point, you have finished finding a matching CM user group for every sample repository user group, created missing CM user groups and ACL entries, added missing CM users to groups, and removed obsolete users from groups. The last task will be to do the reverse -- find a matching repository user group for every CM user group. You don't need to synchronize the groups themselves anymore, as you have just finished this. Having a group in CM that has no corresponding group in the sample repository means that the group was deleted from the sample repository. Therefore, you have to remove the group from CM as well. This will automatically remove all users from the group, but will fortunately not delete them from CM. The corresponding ACL entry will also be removed automatically from the ACL. So, since CM does a lot of the work for us, all we have left to do is shown in the following listing:


Listing 10. Delete CM user group
				
// Delete a user group from CM datastore
userMgnt.delUserGroup( cmUserGroup.getName() );

Outlook

In "How the replication tool works," a very detailed description of the replication tool is provided. The replication tool is fully functional and replicates users and groups from a quite simple user repository with a CM datastore. In order to use this tool in your enterprise, simply adapt the following details:

  • Provide access methods to read user, user group, and access rights information from your special back-end repository (LDAP, relational database).
  • Define a transformation of user attributes.
  • Define a transformation of user group attributes.
  • Define a transformation of access rights (ACLs, privilege sets).
  • Provide filtering methods for users and user groups (if appropriate).
After these five simple customization steps, you obtain a powerful tool to keep your CM user data in sync with your enterprise user data. Additionally, you could install the replication tool as an automatically started service or cron job and, from there on, have to do nothing on user synchronization. If only everything could be so easy!



Back to top


Acknowledgements

Many thanks to Sven Hapke and Phil Morris for reviewing the article and providing helpful feedback.




Back to top


Download

DescriptionNameSizeDownload method
Source codeDwSource.zip8KBFTP|HTTP
Information about download methods


Resources



About the author

Gabriela Barowsky (gbarowsky@de.ibm.com) graduated from the Christian Albrechts University Kiel, Germany with a degree in computer science. She has been involved in several object-oriented projects as an Application Architect and Application Developer since 1996. Gabriela is an IBM Certified Solution Designer DB2 Content Manager V8, working for the Content and Knowledge Management Department of IBM Global Services in customer projects.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top


This is a trademark statement. This is another trademark statement. Other company, product, or service names may be trademarks or service marks of others.