Integrating GUMS and site services

All the main components of GUMS are developed against interfaces with minimal coupling to GUMS itself, allowing a site to rewrite those components to interface their systems. In this article we will describe these interfaces and provide some integration examples. We link to the online GUMS code for examples; if you choose to print this, you might also want to print the code to which the online version of this article links.

GUMS doesn't require integration: it can work fine by itself. But if a site requires integration such that GUMS communicates with the site's information systems, it is easy to do, it just requires a little knowledge of Java. You don't need to know about the internal workings of GUMS. You can write code (external to GUMS) to deal with special mapping circumstances, and write the policy file to tell GUMS when to run it. Here are examples of site-specific needs:

  • Store all the information that GUMS uses for mapping in a separate system that's used for the rest of the site's accounts (e.g., in LDAP, in an Oracle or MySQL database, and so on)
  • Use some pre-existing software to perform the mapping (e.g.,. as part of the user information database, a user was already able to select the grid certificate at the site.) In this case you're using GUMS for its role-based capabilities and for integration with OSG; it's just the glue between grid and local site. This is good for transition situations, for maintaining compatibility with existing systems.
  • Use a different database for group information (e.g.,. the site wants to map his admins in a different way, and wants to take the list of admins directly from its databases or store them in LDAP instead of the GUMS MySQL)
  • Use some other information service to decide which service should use which mapping (i.e. one wants to set on all production machines a particular mapping, and the list of production machines is stored within their own information service)

If you have a use case that is not site-specific, we may be willing to either help in the development or to distribute it as part of GUMS. Go to the GUMS site and use our mailing lists to contact us!

Changing storage for GUMS data

Suppose you already have a user management system that keeps some grid-to-username mapping and you want GUMS to use it. Or suppose that you want to tightly couple the GUMS pool account system with your site LDAP. Or suppose that you want to perform special mapping on a list of users taken directly from some database. How would you do it?

In GUMS there is a PersistenceFactory class which is responsible for creating all the objects that write to/from a specific external storage system (as opposed to MySQL which we'll consider internal). We've implemented this in GUMS in the form of a HibernatePersistanceFactory class which implements the logic of how to write/read to/from the default MySQL implementation. A site can implement its own PersistenceFactory class to define where the data is written to and read from.

The PersistenceFactory is just a factory class used to create the objects that actually implement the persistence layer. There are several different kinds of these objects, e.g.,:

  • UserGroupDB is used by GUMS to cache lists of users so that GUMS doesn't have to contact the VO server every time.
  • ManualAccountMapperDB is used by the ManualAccountMapper to store a mapping table. 

You do not need to implement the all the different kinds of classes, only the kinds you need. For those you do choose not to implement, you can use:

   throw new java.lang.UnsupportedOperationException("...");

This way, when gums tries to use a method that implements it (due to a configuration or usage error), GUMS generates an error. This is also true for any other method you do not want to implement (e.g., you might not want GUMS to modify the information in your site databases).

You can use the HibernatePersistenceFactory as a trace: it has classes for any interface it needs to implement, and when asked to give a persistence object it just creates an instance of the appropriate inner class. You can thus implement a ManualAccountMapperDB that reads the site user management system, an AccountPoolMapperDB that reads account information from the site LDAP, and/or a ManualUserGroupDB that reads the list of users from your database.

Creating a mapping policy

A site can create its own policies for the mapping. For examples, we suggest that you look at the mapping code that comes with GUMS. A mapping is particularly useful for sites that have a pre-existing user management system which already contains some certificate-to-username mapping. Through an extension, GUMS can be made to use that mapping.

All the mappings implement the AccountMapper interface. The only method you're required to implement is mapUser, which returns the username given the user credential.

The GroupAccountMapper interface maps all the users to the same account. The account to which they're mapped is set through the groupName property (notice the getGroupName and setGroupName) in the configuration file. For example:

   <accountMapping className='gov.bnl.gums.GroupAccountMapper' groupName='test' />

sets the groupName to "test". You can create any property you like: while reading the configuration, GUMS looks at your class for a name match [This is actually provided by the Apache Jakarta Commons Digester library].

We suggest you develop and test a new class by itself first, without running it in GUMS. You can have a main method, or a set of unit tests, to simulate some requests using the mapUser method, and see that it behaves correctly. Once you have done that, you can prepare a jar, and put it in the lib directory of the GUMS service. You will have to restart the service, as tomcat creates the list of available jars when the service is started. You can change the policy configuration file, instead, at any time.

 

Creating a group

You can create your own groups. A group is a list of users that get mapped using the same mapping criteria. Suppose, for example, that a site wants to use a new VO server which is not supported by GUMS. Or suppose that the site wants to grant all its admins a different mapping, and wants to get this list directly from their LDAP system, so that there is only one place to keep updated. All of these can be supported by creating a group.

Look at the at the UserGroup class: a group is essentially a function that is able to tell: "is this person in the group?". The isInGroup() function is going to check, by whatever means , if the Grid Identity is within that group.

There is a getMemberList(). This is actually optional: if you have an EveryoneGroup, for example, you can't name everyone. In that case, you should use something like:

   throw new java.lang.UnsupportedOperationException("Group cannot be enumerated.");

The catch is that GUMS won't be able to generate a grid-mapfile for those hosts that make use of this group; you can only use the gatekeeper callout functionality of GUMS with groups.

The updateMembers() function is intended for groups requiring that GUMS access some remote service (e.g., VOMS); this cannot be done on a per request basis. For cases like these, one should implement the updateMembers() function to retrieve and store the data on a site-local service. If you do this, you might want to use a UserGroupDB to store the information, so that it integrates with the rest of persistence. You can look at the VOMSGroup class for an example.