In 0.9.4 we will need to retrofit KEW to leverage KIM for it's identity management needs. In 0.9.3, KEW has it's own set of classes which it uses for handling the concepts of users and groups.
- #Web Authentication
- #Web Authorization
- #Client APIs
- #Plugging in Custom Implementations
- #Xml Import/Export
- #Gap Summary
In KEW a WorkflowUser represents a user of the system. They can be routed documents and interact with the system when authenticated. Each user has a unique, generated ID which is used to reference that user from all related objects (Action Request, Action Items, Documents, etc.).
While it is possible to manually enter users, it is most often the case that the UserService implementation will be overridden by an institution to plug into services available at that institution. The service for searching for users will typically also be overridden.
The relevant package of KEW where most of the user-related code can be found is edu.iu.uis.eden.user. In KIM, the concept of users is represented by Entity, Principal, and Person.
In KEW there is a single object (WorkflowUser) which encapsulates everything about a user. This includes the user's name, email address, various identifiers, etc. In KIM there is the concept of a Person and there is also the concept of an Entity. In KEW we use the User to represent both real users and "system" types of users so the concept of an Entity could apply in the non-Person cases. Although I suspect in general we are going to be referring to the Principal BO throughout our APIs since most workflow interaction will require an authenticated entity of some type to participate.
There are many services which reference WorkflowUser. This would most likely need to be replaced by references to PrincipalDTO. Authenticated users will be performing the majority of work in workflow so it makes sense to record the principal's ID with user actions and input in the system. Utility classes would probably need to be written to be able to more easily extract Name information, etc. from the Principal's Entity as there will be a certain number of standard attributes which a person will posses.
KEW has a service called the UserService which provides functionality for fetching and searching for users. It also has some methods which are used by the web tier to perform some of it's duties (getBlankUser, save, copy). UserService is overridable via an Institutional Plugin which allows for customization and interfacing with existing user services. KIM has a Principal and Person Services. There are some differences however:
- PrincipalService has no caching
- WorkflowUser has detailed methods
- WorkflowUser has ability to restrict access to name and email
PrincipalService has no caching
Internally, KEW uses UserService.getWorkflowUser all over the place to retrieve information about users. The default implementation of this service is cached for speed. We should ensure that the corresponding services in KIM are also cached. Additionally, if invoking service remotely from a client it would be very useful to have the ability to enable some sort of client-side cache on the service. This would help to improve response times for clients using these services remotely (especially important if that client is running an embedded workflow engine and communicating with KIM remotely!).
WorkflowUser has detailed methods
WorkflowUser has many methods on it which make it easy to fetch various attributes about the user. For example:
The Principal and Person BOs in KIM have none of these types of methods. My assumption is that they would be implemented using Person attributes (but see my notes on IDs later in this document). That means that the APIs will change quite a bit and it might make sense for KEW to keep some sort of wrapper on these (although I thought that's what Person was meant to be originally, perhaps it's not yet implemented?)
WorkflowUser has ability to restrict access to name and email
We implemented this to satisfy FERPA requirements and we did the checking in our IU user service implementation but added the general purpose methods to the API:
KIM certainly doesn't have these. We need to determine how best to handle this (could again be done with Person Attributes?).
We will need to create a script which migrates data from EN_USR_T to the KIM tables for Princial and Entity. Ideally, we can keep the current "workflow id" as the "principal id" in the Principal tables. That way existing Action Requests, Rules, etc. will simply start referencing Principals rather than WorkflowUsers. Attributes on WorkflowUser will be converted into Entity Attributes (or Person Attributes?).
Graphical User Interface
The GUI for users currently consists of the following screens:
- User Lookup
- User Creation
These are fairly simplistic, screenshots below:
Requirements would be:
- Be able to search for users by Name
- Be able to search for users by various IDs
- Be able to create and edit users
I'm not sure what the KIM GUI will look like for person lookups (whether it would include specific searches by name, etc.) but that would certainly be desirable. I'm also not sure exactly how we are going to deal with the different IDs KEW supports moving forward (see section on IDs below) and whether or not those will be searchable. Network ID/Authentication ID is the most important one. I'm fine with getting rid of UUID, EmplID, etc. as first-class ID citizens in Rice (they can be modeled as Person attributes if needed). Is network ID essentially the same thing as Principal name?
A Workgroup in KEW is a collection of Users and/or other Workgroups which is identified by a globally unique name. Workgroups can have types which control what additional attributes might be collected when the group is entered and also might determine how group creation/changes are routed for approval.
An analogous concept exists in KIM which is referred to as a Group. These groups have Principals and other Groups as members and also have the concept of a Group Type. In this respect the data model is similar. There are a few differences though:
- Group IDs
- Active Indicator
- Group Attributes
- Membership Data Model
Workgroups in KEW are versioned. This means that each version of a group is saved. For this reason there is a version number and a current indicator in the table. The primary key of a group in KEW is the combination of it's ID and version number.
We need to decide whether or not we want to preserve the functionality of maintaining Group history. It is not specifically utilized anywhere in KEW (i.e. no functionality exists in the application to roll a group back). But it might be useful to track for the purposes of correlating the membership of a group with an old workflow transaction?
Workgroup IDs in KEW are generated using the Document ID of the first document used to route the group. The KIM group table does not contain a Document ID (this is instead maintained in the KNS tables?).
In fact, in Workflow if the creation of the workgroup was done via the GUI (instead of an XML import) the workgroup ID will become that of the document used to route it. In KIM, the ID is simply generated from a sequence. While this is different than the way group IDs are generated in KEW I would consider the KIM solution to be less confusing. Care will need to be taken in the conversion scripts to handle starting the Group ID sequence at the appropriate number to prevent collision.
Groups in KIM do not contain an Active Indicator as Workgroups in Workflow do. Should this be added? My thought is Yes. Also, the Global remove/replace feature takes advantage of the active indicator. Although it is not currently well-defined in the Workflow documentation what it means for a group to be Inactive.
Custom Attributes for Workgroup Types in workflow are not configured via the GUI as they are in KIM. Instead you must create a Java class (implementing
org.kuali.workflow.attribute.ExtensionAttribute) which defines the Fields. You must then register it as a "Rule Attribute" (EN_RULE_ATTR_T) in order for the Workgroup Type to use it. This also allows for the implementation of custom validation routines which can be written in Java.
In KIM Group Type Attributes are created and defined via a Maintenance document. It's not clear to me how/if custom validation can be attached to these or whether or not there is a provision for plugging that in.
Membership Data Model
In KEW, group membership is represented by a single table with an ID column and a type column (group or user). In KIM there is a table for each type of member (i.e. a table for group members and a table for principal members).
The API for Workgroups in KEW is defined by the WorkgroupService and the WorkgroupRoutingService interfaces. The former includes query methods for Workgroups as well as some other miscellaneous methods related to caching and the web tier. The WorkgroupRoutingService has methods specifically tailored toward implementing the routing-related features of Workgroups. The main business object for Workgroups in KEW is BaseWorkgroup which implements the Workgroup interface.
The API for Groups in KIM is defined by the GroupService interface. The main business object in KIM is called Group.
Here is a list of differences between the APIs in KEW and in KIM:
- Absence of WorkgroupRoutingService
- Group is a POJO
- GroupService has no method for checking membership
- WorkgroupService has web-tier methods
- "Load Workgroup Extensions" in KEW
- ID Types in KEW Workgroups
- XML Ingestion/Export
Absence of WorkgroupRoutingService
There is no equivalent to WorkgroupRoutingService in KIM. In essence, this would be replaced by the implementation of Group in KIM using the KNS. If it would be possible for an institution to override the Document implementation for Group, they would be have routing-related customization capabilities.
KIM does not implement any caching in it's GroupService implementation. In the past we have found this to be crucial for good performance in KEW.
Group is a POJO
The Group Business Object in KIM is more of a POJO than Workgroup in KEW is. In Workgroup we have some convenience methods which include:
Equivalents to the first method is available on the GroupService in KIM. There is no analogous method for checking Group membership in KIM (see next item).
GroupService has no method for checking membership
There is no method for checking Group membership in the KIM APIs. Of course one could manually loop over the list of Group members and analyze membership from that but it is convenient to have a method with that specific purpose (especially when trying to interface with external grouping systems).
Update: I notice now that there is an isMemberOfGroup method on PrincipalService. This is good! Seems like we might want to also have an isMemberOfGroup method on Group Service which checks if a Group is a member of another Group.
WorkgroupService has web-tier methods
The KEW implementation of WorkgroupService has methods related to the web-tier. Since KIM uses KNS these will no longer be needed.
The KEW implementaton of WorkgroupService has a getCapabilities() method which allows for specifying whether or not certain screens in the system should be enabled. For example, if you don't want to use the maintenance screens for Workgroups at all (i.e. you have an complete institutional solution for groups that you want to use) you could disable this portion of the application to prevent it from being used. I doubt KIM has a similar concept but it might be worth adding.
"Load Workgroup Extensions" in KEW
KEW has this concept of loading a workgroup and checking "Workgroup Extensions". The idea behind this is that it would check the groups stored in the database first and then potentially go out to an LDAP or something along those lines. This was primarily put in there for performance reasons when we implemented this at IU (i.e. we only wanted to them to be able to use ADS groups for super user/blanket approve/exception groups). This concept does not exist in KIM and I'm happy to get rid of this distinction. However, see my notes on general performance concerns below.
ID Types in KEW Workgroups
Membership Change Notification
In Workflow, whenever the PostProcessor for a Workgroup executes on it's transition into PROCESSED state, we queue up a WorkgroupMembershipChangeProcessor which handles updating the Action Lists for the added and removed members. For this we will need to add notification to the PostProcessor for the Group document in KIM. Then we will register a service to listen for those messages in KEW.
In KEW there is the concept of a Reporting workgroup which can be specified on a Document Type. The idea here is that a DSS environment might use that column in the database to execute a join and perform row-level security based on that. This is not neccesarily a gap, but since the EN_WRKGRP_T table will be going away we should make sure this gets documented.
General Performance Concerns
I have a couple of general performance concerns related to the implementation of groups in KIM, some of which have been discussed previously:
- There is no caching implemented behind the GroupService
- There is no method to get a list of all Group Names for a Principal (this can be helpful for fast group membership checking on the client)
We will need to create a script which migrates data from the following KEW tables to the appropriate KIM tables:
Some of the potential issues have been mentioned here regarding the differences in the data model between Group attributes in KIM and KEW and also the differences in how group membership is stored. Further analysis will need to be done to determine how to implement the conversion scripts.
Graphical User Interface
The GUI for Workgroups in KEW consists of the following screens:
- Workgroup Lookup
- Workgroup Creation
- Workgroup Type Lookup
These screens implemented in KIM for Group and Group Type are fairly close to what existed in Workflow. In fact, they add the ability to maintain a Group Type via the GUI which wasn't possible in KEW. There is one main missing feature however:
- On Group Lookup, can't search by Group membership
There is a gap in the way that IDs are implemented in KEW vs. how they are handled in KIM. In KEW there is a hierarchy of IDs as follows:
So, in a few places in KEW we pass a reference to Id so that it's possible to pass either a group or a user ID in and the system will handle resolving this. Additionally, we have a parallel set of VO objects which are used in the KEW API. So when you create a document, for example you might pass a NetworkIdVO or an EmplIdVO. At an institution, you might have more than one type of ID that could be used to uniquely identify a users (this is where EmplId came from originally in it's IU incarnation). So it would be nice to be able to preserve this behavior. However, a Principal in KIM does not have a way to designate "custom" ID types. Furthermore, it doesn't appear that a Principal supports custom ID types (maybe that would belong on Entity?).
Even if it were possible to be able to specify custom Principal attributes, we would still need to have some way to specify that when using the KEW API to interact with documents. Potential solutions to this need to be discussed, but might include:
- Get rid of the different types of IDs completely. Instead the KEW API would only accept principal name/ID.
- Add the ability to extend Principals with custom IDs. Modify, the KEW API to accept an ID plus a type indicator for it (i.e. empl id, etc.).
- Leave the KEW API alone and have it handle mapping the given IDs types to the principal via the KIM API (would still need some way to specify additional IDs for a Principal).
Regardless of the above, I would like to be able to remove the concept of Empl ID and UuID in KEW as native ID types since they were really born from IU-specific IDs.
KEW has the concept of a WebAuthenticationService built into it which allows for plugging in of custom Web Authentication implementations (such as CAS, simple form, HTTP auth, etc.). Does KIM have this same concept? I know there was a single sign-on implementation that Larry worked on done with CAS but is this pluggable? This also includes the Backdoor functionality which is utilized throughout Rice. I would like to see all of this moved into KIM.
Also, we maintain a UserSession once the user is authenticated. I believe the KNS does the same thing. It would be nice if we could move all of this into KIM and consolidate it. I don't believe that KIM currently has the concept of a UserSession which is established upon login (could be wrong).
In KEW we have a service called the WebAuthorizationService defined as follows:
This allows for institutions to plug in custom implementations to allow for restricting access to certain pages (i.e. the Workflow Admin screens, Document Search, the Rules screens etc.). We could keep this service in KEW the way it is (depending on what happens with the UserSession object) but ideally this could be handled by defining permissions in KIM.
The KEW WorkflowInfo API class has various methods for retrieving information about Workgroups and Users. These can be replaced by the corresponding KIM APIs. Also, WorkgroupVO and UserVO are objects which get attached to some of our other "VO" objects at the API layer. In these cases we should probably just replace them with the IDs of the Principal or Group. These changes will be impacting for the KEW APIs and will need to be documented as such.
In KEW there is a document which allows for Replacing or Removing a user from Rules and/or Workgroups. The Rule system will remain in KEW but Groups are now part of KIM so it will probably be easiest to split these up as follows:
- Create a "Global" Document for Groups in KIM which allows for Removal/Replacement of Principals across all Groups.
- Create a "Global" Document for Rules in KEW which allows for Removal/Replacement of Principals across all Rules.
Both of these would need to be developed to resolve this gap. The Rule document could be developed as part of the work to retrofit KEW to use KNS.
Plugging in Custom Implementations
In KEW we have the ability to override User, Workgroup, and WebAuthz/Authn services using a concept called an Institutional Plugin. What are the provisions in KIM for allow service overrides? Are there any?
We could extract the KEW plugin framework to the Rice core and use that for service overrides if desired or use a Spring-based mechanism for handling overrides. I think in general we need to decide how we want to support institutional customization. The institutional plugin in KEW was created primarily for the purpose of supporting institutional customizations of user and workgroup services. So if we decide to not use that for service overrides in KIM then we should probably just retire the concept (although the plugin framework itself has value outside of institutional customization so I don't think we would get rid of the whole thing).
Additionally, once we have the ability to override these services, we need to ensure that we can support the kinds of integration with external services that institutions will want to do. I can describe the IU uses cases for both Users and Groups below:
IU User Service customizations
Our IUUserService implementation follows the following steps when a user is requested (via the getWorkflowUser method on UserService):
- Checks cache for the user
- Checks a configured "update" period for the user, if that check indicates a stale user, the user is fetched from our EDS (LDAP) system and then stored in the EN_USR_T table.
- If the user does not need to be updated but either fails the cache expiration check or doesn't exist in the cache, they will be fetched from EN_USR_T, cached and returned
IU Workgroup Service customizations
Our IUWorkgroupService implementation follows the following steps when a Workgroup is requested (via the getWorkgroup method on WorkgroupService):
- Checks cache for the workgroup
- If it's in the cache, return it
- If it's not in the cache, fetch it from EN_WRKGRP_T
- If it's not in EN_WRKGRP_T go to ADS (microsoft active directory) and look for the group
- If the group was fetched from ADS, we store it in EN_WKRGRP_T (because it has to have a workgroup ID!) with a special workgroup type of "A"
- When the members are requested for a workgroup of type "A" we lazily load them from ADS (for performance reasons)
KEW has the ability to import/export Workgroups and Users using XML. We need to decide whether or not to keep this functionality.
- WorkflowUsers have explicit method for access to first name, last name, display name and email address
- There are various typed ID classes in Workflow - Authentication ID/Network ID, Workflow ID, UuID, EmplID
- Principal Service has no caching
- WorkflowUsers have ability to restrict access to name and email (FERPA)
- Lookups for Users allow for searching by last name, first name, and the various IDs
- User creation screen allow for entry of the specific person-related attributes (IDs, Names, email address)
- UserService.getCapabilities() provides way to turn off User-related screens and links
- UserService supports XML export and import
- KEW Workgroups are versioned
- Group name and ID number are stored as subclasses of GroupId
- There is an active indicator on Workgroups
- Group Attributes based on types are configured using Java classes and provide for custom validation written in Java
- KEW has a WorkgroupRoutingService
- Group service has no caching
- WorkgroupService.getCapabilities() provides way to turn off Workgroup-releated screens and links
- WorkgroupService supports XML export and import
- When Workgroup membership changes, Action Lists are updated
- No method for getting a list of all Group Names for a Principal
- No way to search for Groups by membership
- In general IDs for Users and Groups in workflow are implemented differently. KEW has more inherent type (some of which might not be needed anymore). It also uses Interfaces to define the different types of IDs.
- Common superclass for User and Group IDs. Used in RoleAttributes.
- KEW contains an overidable WebAuthenticationService which allows for determining who the authenticated user is
- This services also allows for hooks into establishing an initial UserSession for the authenticated User
- The created UserSession contains functionality for:
- Caching group membership
- Caching other data
- Implementing backdoor functionality
- Implementing "help-desk" functionality for the Action List
- Storing some other KEW-specific objects
- KEW has a UserLoginFilter which handles executing calls to WebAuthenticationService and establishing initial user session
- KEW contains an overidable WebAuthorizationService which allows for restricting access to certain URLs
- KEW client APIs have query methods related to groups and users
- KEW client APIs allow for usage of the various ID types for identifying users
- KEW has a document for Removing and Replacing users in Groups and Roles
- When last user is removed from Group, group is deactivated instead (relates to previously mentioned Gap on active indicator)
Service Override Strategies
- KEW uses Institutional Plugin for handling service overrides for UserService, WorkgroupService, etc.
- What's the relationship between Person and Entity?
- Is Principal name equivalent to AuthenticationUserId/NetworkIdVO?
- Do we want to continue to keep track of all versions of a Group?
- Should all of the main BOs in KIM have an active indicator?
- Is there a framework in the KNS for "Global" documents?
- How should we handle custom ID Types which are currently supported by KEW? (i.e. EmplID, UuId)
- Is there an existing concept of Web Authentication and User Session built into KIM?
- What are the provisions in KIM for allow service overrides?
- Do we want to continue to employ the Institutional Plugin for identity-related service overrides?
- Should we support XML Import/Export capabilities for Principals and Groups?
We worked with our IUIE team (DSS) to do some analysis on the possibility of mapping concepts within that application into KIM. Here are links to documents related to that:
Possible Gaps if using KIM for IUIE
- Need for different "types" of Namespaces
- Need for hierarchical namespaces
- How best to model Data Managers? Fine-grained Roles or Qualified Roles?
- Data Manager is a role that's scoped to a namespace. Should we be able to assign Roles to namespaces or would this just be modeled as a custom attribute on a Role.
- Would be helpful to have support for nested Roles in order to be able to implement IUIE's concept of Collections.
- How might row-security be modeled in the Role permissions? Should that be within the domain of KIM or modeled by the application.
- Might namespaces and roles need different types of routing based on who is responsible for maintaining it?
- How best to model permissions vs. namespaces? For example, when provisioning access to
screens in the application, does it make sense to have a single namespace (i.e. IUIE) with a set
of permissions (canViewManageAccess, canEditManageAccess, canXxxManageAccess, canPublish,
etc.). Or create a separate namespace for each major piece of functionality in the system (i.e. IUIE
Manage Access, IUIE Publish, etc.) and then assign permissions within those.
- Who's allowed to create namespaces? Roles? Can anyone come in and add namespaces or edit
IUIE's namespaces and Roles? Can we restrict that? Can we modify the routing? We need to have
the ability to have more sophisticed permissions in front of KIM (current implementation is based on
a static set of groups who have permsission to initiate these).