Web Services Wiki
Welcome Guest: Login
In order to explain how LDAP Groups is implemented, a foundation needs to be layed outlining how the base Silva Groups functionality works. This document is intended primarily as a description of how the code works, and now how it ties into the Silva UI.
Silva Groups functionality is split into a few components:
This service maintins the mappings of groups to users. It has helper functions which, for example do the follwoing: given a group name will return the list of users in the group, given a user will return the list of groups the user is a member of. The key to understanding how this ties into the overall groups support is the function getGroups. This function returns all of the groups (normal, virtual, and ip) a user is a member of. Drilling down getGroups, the main function of interest is _getNormalGroups.
Group objects are stored somewhere in the Zope hierarchy. They contain functions which tie the group into the Groups Service, by updating the group service when the group settings change (e.g. add a user). Group objects aren't used during the authorization phase, but serve more of a management role in identifying who is a member of the group, and providing UI controls for access rights.
When a group is assigned a role at some location in Silva, a groups mapping object is added to the underlying access control machinery for that object/location (i.e. object.__ac_local_groups__). During the authorization phase, the access control machinery consults this object's groups mapping to determine if the user maps to any groups with additional roles. GroupsMappings use one function to determine this: getRoles. This function, in turn, constuls the groups_service.getGroups function mentioned in the Groups Service section.
In python there are no private attributes. This is a nice feature (but dangerous), as it allows developers to override a programs stock functionality by simply "replacing" a function, object or attribute with something else at runtime. This is known as "Monkey Patching". Silva Groups functionality uses a monkey patch to override the default behavior of two functions in AccessControl.User.BasicUser: getRolesInContext and allowed.
These two functions in the monkey patch start by copying the existing code in BasicUser, and adding the additional functionality needed to tie in groups support. Both functions get down into the access control machinery to lookup the roles a user has in the current context. The default behavior only looks at __ac_local_roles__, a mapping of usernames to roles. The monkey patch also looks at __ac_local_groups__ (which are GroupsMappings, remember?) to determine if the user is a member of any groups with local roles.
LDAP Groups provide specializations of two of the components listed above: the Groups Service and Group Objects.
These objects are basically NormalGroups in disguise. The Groups Service contains a registry of all groups and all ZODB users in those groups. LDAPGroups are registered as NormalGroups in the GroupsService. The GroupsService also contains a mapping of 'NormalGroups' to 'LDAP Groups' (groups that are in ldap, not LDAP Group Objects). LDAP Group Objects update the GroupsService normal to ldap mappings.
This service extends from the base GroupsService. It provides functions to query ldap, manage mappings, and most importantly overrides _getNormalGroups. The ldap query functions call back to PortalUserFolder.PortalAPI to actually query ldap.
The important _getNormalGroups function first calls the inherited GroupsService._getNormalGroups. LDAP Groups masquerade as NormalGroups, but since LDAP Groups contain to ZODB users, they won't be returned from the inherited function. _getNormalGroups then iterates through the list of Normal Groups. If a NormalGroup has a mapping to groups in LDAP, and the user is a member of at least one of those groups in LDAP, the NormalGroup name is added to the list of groups the user has membership in.
That's basically the meat of how Silva Groups works "under the hood", and how LDAP Groups tie into everything.