JA-SIG
Home
About uPortal
Documentation
Getting Started
Developers
Implementors
Users
Background
Release
|
The Person Attributes Group Store ("PAGS")
The PAGS makes user attributes retrieved by PersonDirectory
appear to be group memberships. (PersonDirectory
initializes IPersons with attributes retrieved from one or
more sources of directory information, including, for example
LDAP. For more information, see the PersonDirectory documentaton.)
PAGS computes entity memberships by testing the value of selected IPerson
attributes. Like PersonDirectory , the PAGS retrieves
information one user at a time. As a result, it can answer
inquiries about what groups a particular IPerson or group member belongs to, but it
cannot answer inquiries about what entity members are contained by a
given group.
Can do:
contains()
find()
findContainingGroups()
Can't do:
findEntitiesForGroup()
Although PAGS groups cannot answer their entity members, they
are aware of their member groups. So they can also do:
findMemberGroupKeys()
findMemberGroups()
This will usually suffice for authorization, so the PAGS can be thought
of as an authorization-oriented group store. Since PersonDirectory
supplies information about IPersons and not about ChannelDefinitions
or other portal entities, a further limitation is that the PAGS can only
contain memberships associating IPerson group members with IPerson
groups.
Configuring the Store.
The contents of the store is declared in a configuration document, properties/groups/PAGSGroupStoreConfig.xml .
The dtd is as follows:
<!-- A Group-Store is
made up of 0 or more groups. -->
<!ELEMENT Group-Store
(group*)>
<!ELEMENT group
(group-key,group-name,description,selection-test?,members?)>
<!-- A group key must be unique within the document. A
group-name need not be. -->
<!ELEMENT group-key (#PCDATA)>
<!ELEMENT group-name (#PCDATA)>
<!ELEMENT group-description (#PCDATA)>
<!ELEMENT selection-test (test-group+)>
<!--
A selection-test element determines if a person is a
member of a group. It is
composed of one or more test-group elements whose results
are OR-ed together.
If a group does not contain a selection-test, it may have
member groups but not
member entities.
-->
<!ELEMENT test-group (test+)>
<!--
A test-group element is made up of 1 or more test
elements whose results are
AND-ed together.
-->
<!ELEMENT test (attribute-name,tester-class,test-value)>
<!--
A test element contains the name of the attribute whose
value is to be tested
(attribute-name), the class that is to perform the test
(tester-class), and the
value to be compared to the attribute value
(test-value).
-->
<!ELEMENT attribute-name (#PCDATA)>
<!ELEMENT tester-class (#PCDATA)>
<!ELEMENT test-value (#PCDATA)>
<!ELEMENT members (member-key*)>
<!-- The optional members element contains keys of member
groups. -->
<!ELEMENT member-key (#PCDATA)>
The configuration lets you do 2 things: (i) declare IEntityGroups
with key, name, description and member group keys, and (ii) declare the
tests that determine if an IPerson is a member of a
group. Since a group need not contain any member groups, the <members>
element is optional. Since a group need not contain any member entities, the <selector-test>
element is also optional.
Tests. Each of the tests
to be applied to an IPerson is described in a <test>
element, which consists of 3 required sub-elements, the name of the test
class, the name of the attribute to be tested, and the value against
which the attribute is to be tested by the tester class. In the example
below, the test is true if the String value of the attribute "sn" equals
"Jones".
<test>
<attribute-name>sn</attribute-name>
<tester-class>org.jasig.portal.groups.pags.testers.StringEqualsTester</tester-class>
<test-value>Jones</test-value>
</test>
The PAGS currently ships with 8 tester classes, and you can
easily create your own. Each tester class must implement the IPersonTester
interface, which consists of a single method:
public interface IPersonTester {
public boolean test(IPerson person);
}
The following tester classes (all in the package org.jasig.portal.groups.pags.testers )
come with PAGS:
IntegerEQTester
|
Converts attribute and test
value to ints. Attribute must be EQ to the test value. In the
event of a NumberFormatException, the test fails (true for all
Integer testers.)
|
IntegerGETester
|
Attribute must be GE test value.
|
IntegerGTTester
|
Attribute must be GT test value.
|
IntegerLETester
|
Attribute must be LE test value.
|
IntegerLTTester
|
Attribute must be LT test value.
|
RegexTester
|
Attribute must match a regular
expression. Do not include the delimiter. |
StringEqualsIgnoreCaseTester
|
String comparison ignoring case
|
StringEqualsTester
|
String comparison
|
Test Groups. Individual
tests are aggregated into test groups, and their results are AND-ed
together, so all tests in a test group must return true for the test
group to return true. A test group is described by a <test-group>
element. If there is more than 1 <test-group>
element, the results of the test groups are OR-ed together, so if any
one test group returns true, the tests return true. A true result
means that the candidate IPerson is a member of the
group.
The following group element defines an IEntityGroup
whose key is "2". The entity members of group "2" are required to
have a given name that is between 1 and 5 characters long. This
test is performed by comparing the attribute givenName with
a regular expression.
The group has a single member group, whose key is "3". Group "3"
must also be defined in the configuration document. See the sample PAGSGroupStoreConfig.xml
that ships with uPortal for additional examples.
<group>
<group-key>2</group-key>
<group-name>Short First
Names</group-name>
<group-description>Portal users whose first
names are between 1 and 5 characters long</group-description>
<selection-test>
<test-group>
<test>
<attribute-name>givenName</attribute-name>
<tester-class>org.jasig.portal.groups.pags.testers.RegexTester</tester-class>
<test-value>^.{1,5}$</test-value>
</test>
</test-group>
</selection-test>
<members>
<member-key>3</member-key>
</members>
</group>
Multi-valued attributes.
The testers that come with PAGS will OR the
tests of successive values of a multi-valued attribute, so if any value
satisfies the test, the test returns true. You can override this
behavior in a custom tester.
Caching of group store information. Because the groups
structure defined in the PAGS is invarient, an instance of each group,
including the keys of its containing groups, is cached by the store on
start-up. These cached instances are dealt out to satisfy all
requests to the store for groups. As a result, any change to the
store configuration (via PAGSGroupStoreConfig.xml )
requires restarting the group service, which generally means restarting
the portal. By contrast, memberships for an IPerson
group member are cached for the life of the corresponding user's portal
session. As a result, if an IPerson's attributes
change, these new attributes -- and any group memberships they imply --
will be visible on next log in.
Recursive Testing. If
one PAGS group (the child group)
belongs to another PAGS group (the parent
group), then an IPerson member of the child group
must also pass the test(s) required for membership in the parent
group. This is a more restrictive contract than the group system
in general requires, where membership in a group only means that some
relationship exists between a group and its members. Here, when an
entity group member belongs to a group, it means that the underlying
entity has some specific attribute value(s). The PAGS enforces
this by testing the entity for membership in all its parent groups,
which means you can nest the testing of entity members. For
example, assume a group named named "employees" requires status equal
to "employed" and a group named "seniors" requires age GE 65. If
"seniors" is a member of "employees", then any IPerson
member of "seniors" is required to have both age GE 65 and status equal to
"employed".
Checklist for implementing PAGS:
- Configure the store by defining groups and their relationships in
properties/groups/PAGSGroupStoreConfig.xml .
- Comment in the entry for the PAGS group service in
properties/groups/compositeGroupService.xml .
Running in uPortal 2.1.x.
The PAGS has been successfully ported to uPortal 2.1.x by Ken Weiner
with the following steps (thank you Ken):
1. Copy all the source code from the org.jasig.portal.groups.pags
and org.jasig.portal.groups.pags.testers packages.
2. Copy org.jasig.portal.security.IPerson .
3. Copy org.jasig.portal.security.provider.RestrictedPerson .
4. Copy org.jasig.portal.services.PersonDirectory .
Change the constructor of this class from private to public access.
5. Copy org.jasig.portal.security.PersonFactory .
Also copy the following property into portal.properties:
org.jasig.portal.security.PersonFactory.guest_user_name=guest
6. Modify org.jasig.portal.RDBMUserLayoutStore ,
adding the following method to the inner class SystemUser:
public Object[]
getAttributeValues (String key) {return null;}
7. Modify org.jasig.portal.security.provider.PersonImpl ,
adding the method with the following signature:
public Object[]
getAttributeValues (String key)
and replacing the method with the following
signiture:
public Object getAttribute
(String key)
Also add the following supporting import statement:
import java.util.List;
8. Copy properties/groups/PAGSGroupStoreConfig.xml .
9. Copy webpages/dtd/PAGSGroupStore.dtd .
10. Modify compositeGroupServices.xml , adding the PAGS
group store implementation configuration.
last revised: 04/07/2004, d.e.
|