Implements a set of classes that manage a hierarchy of directory
objects and provide retrieval and editing capabilities for the objects
and their attributes.
Author(s)
|
Nick Saxon
Sergey Yevtushenko
Greg Shah
|
Date
|
November 18, 2010
|
Access Control
|
CONFIDENTIAL
|
Contents
Introduction
Primitive Directory Data Types
Directory Object Classes
Accessing Directory Objects
Editing
Directory Objects
Safe Directory Reloading
Safe Directory Backup
Meta
Objects
Front-End Implementation
Schema Definition File Format
Directory Schema Loading
Back-End Implementation
LDAP Back-End
Directory
Resource Plugin
API Summary
Predefined Object Classes
Appendix A. LDAP Schema Draft
Appendix B. LdapMapGen
Utility
Appendix C. DirectoryEdit Utility
Appendix D. Directory Utilities
Introduction
The Directory Service is a package that runs on P2J servers. It
exposes a
set of APIs as public methods through its front-end. The
front-end is
how the rest of P2J perceives the P2J directory. A back-end is
what
implements the persistent storage using one of many possible
approaches. The back-end is hidden inside the Directory Service
package and
is of no interest to the rest of the P2J environment.
Participants
Clients of Directory Service
are various P2J server components. P2J applications are
legitimate
clients of the Directory Service as long as they communicate
locally.
There is no direct access via the network to the Directory Service or
the back-end storage server. The directory service API is
available via method call from local server application code.
These APIs will be exported for remote access by authenticated P2J
nodes via the com.goldencode.P2J.net
package. Each client is identified by its security context by the means of the
SecurityManager. Further text of document uses terms client and security context as synonyms.
Directory Service Front-End is
the portion of the package responsible for the logical view of the P2J
directory. It includes the API implementation the clients use to
talk
to the Directory Service.
Directory Service Back-End is
the portion of the package that maps the logical view of the directory
into some kind of persistent storage and maintains the semantics of P2J
directory objects.
Definitions
A directory is a hierarchy of typed objects. There is only
one
instance of a directory. Directory objects form a tree. A node
in the tree can be a parent of the same type or another type of
node.
Siblings do
not have to be of the same type.
Types of directory objects
are
predefined. Object types have names. Types define what
information can
be stored in an instance of the type, what it is made of, what is
mandatory or optional and whether nodes of a type may have children or
should always remain leaves.
A directory object is a named
set of
attributes, each with
associated value(s). All
attributes have
unique
names which
serve as the keys to values
and are of predefined primitive data
types. Attribute values
may be
single or multiple. There is also a type
of object without any attributes. For attributes which support
multiple values, values consist a set, so each value is unique.
The order of the values in the set is undefined.
Every directory object is a node in the directory tree and as such, has
an ID. Every node can be
identified by a string which describes how to find the object in the
tree from its root. The path
is made of links separated by
'/'
character like in file system directories. Every link names
a node in the subtree of its parent. Sibling objects all have
unique names, although the same names can be reused at different levels
of the tree. The root
object has the ID of "". Here are few examples.
/security
/security/type3/data-abc
/security/account_x
Link
names are
case-insensitive. That means that
object names must differ in more than just string case.
Link names can be up to 256 characters in length. Link names may
only consist of alpha-numeric characters, dashes, periods
and underscores.
Requirements
The design of the Directory Service should meet the following
requirements:
- the logical view of the directory should be completely separate
from the backing storage;
- the architecture of the directory does not have to match any
existing directory implementation, but rather provide a required level
of functionality to P2J;
- the interface between the front-end and the back-end should allow
a relatively easy replacement of a back-end implementation;
- meta information about objects and attributes should be available
programmatically for reading as a set of directory objects;
- directory objects are accessible for:
- enumerations;
- creation;
- deletion;
- renaming.
- object attributes are accessible for:
- enumerations;
- reading;
- writing;
- creation;
- deletion;
- cloning.
- directory may contain sensitive information and has to be
protected as a hierarchical resource;
- bulk loading of the back-end configuration through a stand-alone
utility should be provided;
- bulk loading of the directory information through a stand-alone
utility should be provided;
- bulk export of the directory into a flat file format (XML) should
be provided.
Primitive Directory Data Types
The following table lists primitive data types defined in the Directory
Service.
Primitive Data Type
|
Java Data Type
|
String Representation
|
Type Name String
|
integer
ATTR_INTEGER
|
int |
decimal number
|
INTEGER
|
boolean
ATTR_BOOLEAN
|
boolean |
"true" and
"false"
|
BOOLEAN
|
string
ATTR_STRING
|
String |
character string
|
STRING
|
double
ATTR_DOUBLE
|
double |
decimal number with a "floating"
decimal point
|
DOUBLE
|
bytearray
ATTR_BYTEARRAY
|
byte[] |
hexadecimal string
|
BYTEARRAY
|
bitfield
ATTR_BITFIELD
|
BitField, a subclass of BitSet
which forbids dynamic set growth
|
string of 0s and 1s, enclosed in
single quotes followed by 'B' suffix
|
BITFIELD
|
bitselector
ATTR_BITSELECTOR
|
BitSelector, a subclass of BitField
which allows only one bit set to 1 at a
time
|
string of 0s and 1s, enclosed in
single quotes followed by 'B' suffix |
BITSELECTOR
|
date
ATTR_DATE
|
DateValue , a class
which can be converted to and from java.util.Date , with
time part ignored and set to 0
|
string formatted as yyyy-mm-dd
|
DATE
|
time
ATTR_TIME
|
TimeValue ,
a class which can be converted to and from java.util.Date ,
with date part ignored and set to 0 |
string formatted as hh:mm:ss
|
TIME
|
Directory Object Classes
A directory object class is a named collection of records, one record
per attribute, plus some properties defined for the class. An attribute
record specifies:
- primitive type of attribute;
- name of attribute;
- mandatory vs optional flag;
- single vs multiple values flag.
Class properties are:
- class name;
- leaf vs any node flag.
Class information of objects forms a meta
description. A meta description is a directory object which has
the
following attributes:
- string class; mandatory; single; // class name
- boolean terminal mandatory; single; // leaf (terminal=true) or
node
- string attrname; mandatory; multiple; // attribute names
- integer attrtype; mandatory; multiple; // attribute types
- boolean attropt; mandatory; multiple; // mandatory or optional
flags
- boolean attrmult; mandatory; multiple; // single or multiple flags
Instances of this meta description all have the same number of values
in all multiple type attributes which can be indexed. For
example, a
meta description of a class is also a class and as such it has its own
object with the following attribute values:
- class=metaclass
- terminal=no
- attrname={class terminal attrname attrtype attropt attrmult}
- attrtype={string boolean string integer boolean boolean}
- attropt={true true true true true true}
- attrmult={true true false false false false}
The definition of all known object classes recognized by the directory
establish directory schema.
Directory object classes cannot be defined dynamically. The
reason for
excluding this feature is that clients of the Directory Service work
only with well known objects. For this reason, the clients must be
recompiled to take advantage of such changes. This eliminates the
value of dynamic schema changes.
The implementation of the
directory
package will use an XML file as a source for all object class
definitions. See Predefined
Object Classes for the list of all currently defined classes and Schema Definition File Format
for detailed description of the XML schema file.
Accessing Directory
Objects
It is anticipated that the P2J directory is mostly used for information
lookups. This section discusses how it can be done.
Enumerating Objects
Any object in the directory can be a parent for zero or more other
objects. Enumerating allows for getting an array of children for
a
given directory object. It is a simple API:
public String[] enumerateNodes(String nodeId);
This call may return null
, which means the specified
object is either a leaf node or does not exist, or an array of object
IDs, which are relative to
the parent object ID. An absolute ID can be produced by
concatenating
the original nodeID with the '/' character and a relative ID.
Relative
IDs are just link names.
Security policy may limit visibility of objects. Enumeration
always
returns only those objects that are visible to the caller according to
the current security context.
Searching Directory
Arbitrary directory search is not provided, due to a belief it is of no
value in P2J environment where the directory tree structure is well
defined.
Enumerating Attributes
For any given directory object, it is possible to enumerate all
attributes by a single API:
public NodeAttribute[] enumerateNodeAttributes(String nodeId);
This call may return null
, which means the specified
object does not exist, or an array of node attributes. Node
attributes
are just copies of the attribute records as described in Directory
Object Classes, one per existing
attribute, completed with the number of values.
Security policy may limit visibility
of attributes. Enumeration always
returns only those attributes that are visible to the caller according
to
the current security context.
Retrieving Attribute
Values
There is a set of APIs to retrieve a value of an attribute, one per
primitive data type of the attribute. They all differ only in the
returned data type. Here are sample APIs to retrieve an integer
value:
public Integer getNodeInteger(String nodeId, String name, int index);
public Integer[] getNodeIntegers(String nodeId, String name);
public Integer getNodeInteger(String nodeId, String name);
As can be seen, the first API returns a single value by its index,
whereas the second API returns the whole set as an array. Both
may
return null
, which means the specified object or
attribute does not exist. Third method is a convenience method
for first one with index
parameter set to 0.
There is also a single API that returns all attributes with their
values in one call:
public Attribute[] getNodeAttributes(String nodeId);
This method returns null
if the referenced object does
not exist or has no attributes. Otherwise it returns an array of Attribute
objects, which provide the following methods:
public NodeAttribute getDefinition();
public int getCount();
public Object getValue(int index);
With these methods one can query the attribute name and type, find out
the number of values and query any particular value of the
attribute.
The value is returned as a generic object but the application can cast
it to its primitive data type.
Editing Directory Objects
There are few things to keep in mind when using the Directory Service
for editing the directory:
- editing operations should be issued within an editing session;
- only one editing session can be opened per security context at a
time;
- by opening an editing session, the calling client locks a
specified branch of the directory tree;
- multiple clients can do simultaneous editing as long as they work
with different branches of the directory tree;
- all queries on the locked directory branches are possible;
- simultaneous editing is synchronized by the Directory Service;
- the back-end implementation may pose some limitations on the
availability of an operation against a particular object;
- the calling code should be prepared to face two kinds of error
returns:
- errors due to restricted access to specific directory objects;
- errors due to back-end limitations like, for instance,
read-only objects.
The following sections introduce the methods available for doing
elementary edits (which cannot be executed outside of a batch
session). The final section of this chapter discusses the
batch edit feature.
Modifying Attribute Values
There is a set of APIs to set a value of an attribute, one per
primitive data type of the attribute. They all differ only in the
parameter data type. Here are sample APIs to add and set an
integer
attribute value:
public boolean setNodeInteger(String nodeId, String name, int index, int value);
public boolean addNodeInteger(String nodeId, String name, int value);
public boolean setNodeIntegers(String nodeId, String name, int[] value);
The first API sets a single value by its index. The third API is
a
variation that replaces all existing values with those specified in
array. The second API just adds a new value to the existing
set. All
return
true
if operation succeeds. The attribute name
should be
one of the defined ones for this directory object class.
There is also a single API that replaces all existing attributes with a
new set of attributes with their values in one call:
public boolean setNodeAttributes(String nodeId, Attribute[] data);
The array of attributes for this call can be either obtained by calling
getNodeAttributes
or constructed as in the sample code below illustrating
object creation. The new set of attributes should meet the requirements
of the object class, namely, all mandatory attributes must be present
in the array or the call fails.
To delete a single value of an attribute or the whole attribute, there
are type-independent APIs:
public boolean deleteNodeAttributeValue(String nodeId, String name, int index);
public boolean deleteNodeAttribute(String nodeId, String name);
If an attribute only has one value, the deletion of that sole value
deletes the whole
attribute. Both calls fail if they would cause a mandatory
attribute
to be
deleted, which is not allowed.
Modifying Objects
To create an object, application calls an API and provides:
- absolute object ID;
- object class name;
- array of
Attribute
s.
The requirements is to provide all mandatory attributes with their
values. The
call fails if it is not met. This is the API:
public boolean addNode(String nodeId, String class, Attribute[] data);
For instance, to create an object of a class "namelist" that has
attributes:
- time from, mandatory, single;
- string list, mandatory, multiple;
under the name "/groups/group_A", the application could do the
following:
// Let's assume NodeAttribute na1 and na2 were obtained previously
// na1 describes the ATTR_TIME attribute named "from"
// na2 describes the ATTR_STRING attribute named "list"
// create the 1st attribute
Attribute attr1 = new Attribute(na1, new Time());
// create the 2nd attribute
Attribute attr2 = new Attribute(na2, new String[] {"a", "b", "c"});
// create an array of attributes
Attribute[] data = new Attribute[2];
// put attributes into the array
data[0] = attr1;
data[1] = attr2;
// create a new directory object
boolean result = addNode("/groups/group_A", "namelist", data);
The code above creates a new object which can be referenced as
"/groups/group_A", having an attribute of type time named "from" with a
single value, and an attribute of type string named "list" with 3
values: "a", "b", and "c".
To delete an object, use this API:
public boolean deleteNode(String nodeId);
This call fails if the referenced object has children objects.
Those
have to be deleted first.
Batch Editing Feature
Batch editing feature implemented in the Directory Service protects the
users of the P2J directory from seeing partial updates being made to
the directory. This feature enforces some discipline when editing the
directory.
First of all, the application should open an editing session by calling:
public boolean openBatch(String nodeId);
This call specifies a branch of the directory that should be considered
busy for the lifetime of the editing session. The Directory Service
uses internal batch editing lock manager to lock the specified branch
and refuses request if it tries to lock a branch which is already
locked by other client.
The lock only blocks parallel attempts to edit the same subtree. All
regular queries of attributes are possible. Once the lock has been
obtained and an editing session opened, the application is allowed to
call editing methods discussed in previous sections. These calls do not
have any immediate effect on the back-end, though. The Directory
Service simply batches
them internally. Therefore, the client which opened particular editing
session sees
changes as if they are already committed while other clients see
unchanged directory.
Eventually, the application is done with editing. It calls:
public boolean closeBatch(boolean disposition
);
The disposition can be either commit the session, or discard all
changes. Discarding changes is as easy as simply destroying the batch.
Committing the session is done as follows:
- a backup copy of all objects/attributes that are about to
be changed is made;
- a boolean attribute of the lock object is set to indicate the
backup is
available;
- a string attribute of the lock object is set to object ID of
the backup;
- batched changes are applied to the directory objects; this is the
only period of time when the subtree is not available for queries and
the application would block until the update is done;
- the lock object is deleted from the directory.
This method provides collision detection and crash protection. At
startup, the Directory Service scans the directory and discovers all
existing lock objects created by the same server. The only
explanation of their existence is the system crash. The locked branch
of the directory may need to be backed out. This is the logic:
- the "backup available" attribute is checked;
- if it is set, then the system crashed while applying
changes and definitely needs backing out:
- back out is made using the existing backup;
- the lock object is deleted from the directory;
- the backup information is deleted.
- if it is not set, the system crashed while making
backup;
- no backing out is necessary;
- the lock object is deleted from the directory;
- the partial backup information that might have been created
is deleted.
The implementation locates
the backup by retrieving string attribute of the lock object.
Also, multiple simultaneous locks put on
different tree branches, require that multiple backup sets coexist.
Safe Directory Reloading
This API is designed to allow dynamic directory reloading from the
backing XML file and, therefore, is available only for configurations
with the XML back-end. This API is useful for quick manual directory
file edits without the need to recycle the running server.
This is how it works:
- lockForRereadDir() API is called first to place a lock for the directory for the specified amount of time
- since that moment the directory updates are locked; any attempt is blocked till the reread is done or the lock expires
- this time window can be used to apply manual edits to the directory XML file
- once edits are applied, refresh() API is called
- refresh() rereads the directory file and reloads the internal directory cache
- once the directory is reread, the lock is released
- any blocked directory edits can now proceed, which makes the whole procedure safe
If for any reason the function has to be cancelled, cancelRefresh() API
can be called to release the lock and the internal cache remains
unchanged.
Safe Directory Backup
This API is designed to allow safe directory backups into another XML file and, therefore, is available only for configurations
with the XML back-end. This API is useful for backing up the directory without the need to recycle the running server.
This is how it works:
- a single API is called, backupDirectory(), which specifies the file namee for the back up
- if the backup file exists, the API returns an error indication; otherwise it places a lock for the directory
- since that moment the directory updates are locked; any attempt is blocked till the reread is done or the lock expires
- a backup copy of the directory file is then created
- the lock is released
- any blocked directory edits can now proceed, which makes the whole procedure safe
Meta Objects
Meta objects are directory objects that describe the directory.
They
are there to allow applications query various pieces of information
about directory objects in a regular directory way: by getting values
of object attributes.
The meta objects are for reading only.
Class definitions are NOT meta
objects, although they are very closely related.
Meta objects are dynamically created at runtime based on the current
schema.
All meta objects stem from the "/meta" container (see Container
for the definition). The children of the "/meta" object are:
This is the parent for all objects of
class "metaclass" describing all known directory object classes (see
Directory
Object Classes). Every predefined class has the associated
object
in this container.
- "/meta/class/classname/attribute-name" terminal container
There is a terminal container object
for every
attribute name for every object class. Being a read only
terminal container, it
is not very useful in general. The purpose of their existence is
to be able to specify
directory security at the attribute level (in a directory access
control list or ACL). For instance, there is
a
"lock" object class having a "backed-up" attribute.
The corresponding meta object would be referenced as
"/meta/class/lock/backed-up".
- other meta objects may appear during the future development
The following API returns the object ID of the metaclass object for the
given directory object:
public String getNodeClass(String nodeId);
For instance, the call to getNodeClass("/meta")
returns "/meta/class/container". The latter
object ID
can be further used to query defined attributes and their properties.
Front-End Implementation
Front-ends define the logical view of data and manage the back-ends.
There are few different implementations of the front-end:
- the
DirectoryService
class
- the
DirectoryCopy
class
In a given P2J environment, there can be only one of the given
implementation's of the front-end in use. The DirectoryService
class is the main implementation of the front-end for the production
environment. The DirectoryCopy
class is a
stand-alone utility that is used to perform backup and recovery
functions.
Schema
Definition File Format
The directory schema is stored in one or more XML files. The structure of the XML
file assumes that for each object class there exists exactly one record
which may contain zero or more object class attribute definition
records. The structure of the XML file follows:
- the root element
<schema-root>
- zero or more elements
<object-class name="classname" leaf="classisleaf" immutable="classimmutable">
- zero or more elements
<class-attribute name="name" type="type" mandatory="mandatory" multiple="multiple" immutable="immutable"/>
</object-class>
</schema-root>
Notes:
classisleaf
is a class property (see Directory Object Classes) which
is represented as strings true
or false (case is ignored).
classismutable
is reserved and must be
present as string false.
- Class attribute
name
, mandatory
,
multiple
and immutable
are
appropriate attribute properties (see see Directory Object Classes
for details) which are represented as strings true or false (case is ignored).
- Class attribute
type
represented as string
(see Primitive Directory Data Types
table for list of recognized "Type Name Strings").
Directory Schema Loading
The Java class SchemaLoad is used to initialize the directory schema using one or more XML resources loaded at runtime.
The main schema (which defines the standard object classes that must always exist for P2J) will be loaded from SchemaLoad.SYS_SCHEMA_NAME which is "dir_schema.xml". The J2SE ClassLoader.getSystemResource()
will be used to search the classpath and load the first instance of
this file. The file should be found in the jar for P2J and it
should not be modified since the P2J code has heavy dependencies upon
those definitions.
Applications may optionally add their own extensions to the directory
schema. This is done for such purposes as supporting custom
security plugins using data stored in the directory. Application
schema extensions are loaded from SchemaLoad.EXT_SCHEMA_NAME which is "dir_schema_ext.xml" using ClassLoader.getSystemResources()
which will return the list of all found resources. There can be
more than one, if there are enough jar files in the classpath that each
contain that file. It is valid for this file to be missing, it is completely optional.
Since there is no pathing information in either resource name, the
associated files must be present in the root directory of the jar files
being searched OR in the topmost directory of a path in the CLASSPATH.
This search process occurs regardless of any other runtime
configuration. The core P2J schema will be read first and then
any application extensions will be read. This is done very early
in the initialization of the runtime environment, before the directory
itself is active. The reason loading from resources is a
reasonable approach is that the source code for P2J (and optionally for
applications that have their own directory schema extensions) is
already hard coded to the specific schema. For that reason, the
schema upon which the code is dependent should be included with the
code and there should be no need to require configuration in order to
find it.
The format for both files is the same (see above),
but the contents should generally not overlap. If the application
extension specifies an object class name that is the same as one that
is already defined, it will replace that object class. Please note that
this is VERY DANGEROUS unless you know exactly what you are doing.
Back-End Implementation
The logical view of the directory does not define how the objects are
stored. In general, any storage can be used, but some storage
types are
more convenient then others, because they allow tree structures to be
handled easier. Reasonable implementation choices are:
Pros: easy to implement;
very good read performance
Cons: the directory
cannot be easily distributed to another system; update of the large
directory may be time consuming
Pros: integration with
existing directory; update performance depends only on amount of
changes, not on size of the directory
Cons: due to a high
variety of LDAP structures, requires a mapping layer; average read
performance
Integration with an existing directory or the ability to integrate
later,
is a key feature of this design.
Remapper Interface
The front-end communicates with the back-end using the Remapper
interface, which has to be implemented by a back-end class. The Remapper
interface defines
methods that the front-end delegates to the back-end for
execution. There are important differences, however:
- no requests referring to meta objects are passed down to the
back-end
All meta objects related requests are
processed in the front-end, but this processing may cause translated
requests to the real objects to be generated and passed down to the
back-end for execution.
- back-ends do not perform set operations
The front-end performs set operations
by calling appropriate methods in a loop.
- back-ends do not bother with the P2J directory access right checks
This task is carried out by the
front-end.
- the front-end maintains per client bind/unbind state and issues
bind() and unbind() calls to the back-end
These conventions make the back-end methods focus primarily on their
storage and retrieval functions.
Classes implementing back-ends should allow multiple back-ends (but no
more than one of each type) to be instantiated at the same time. This
enables creation of directory copy/conversion utilities. One of the
implemented classes is assigned as the back-end of choice through the
bootstrap configuration.
Instantiation and
Initialization
The front-end instantiates a back-end using one of the two defined
techniques, both based on configuration variables.
The first technique uses short identifiers which allow front-end to
choose
one of the predefined back-ends. Given short identifier is converted to
so called camel case (first
character converted to the upper case, rest - to lower case). Then to
identifier added suffix Remapper
and prefix com.goldencode.p2j.directory.
Resulting name is used to instantiate class using the Java reflection
API.
The second technique uses full class name specified in configuration
variable which is used to create instance of the back-end class using
Java Reflection.
Regardless of the used technique, the back-end class implements the Remapper
interface and has a constructor which accepts a single parameter - the
instance
of BootstrapConfig
.
The rest of the sections describe the methods of the Remapper
interface.
Querying Object Classes
This group of methods is used at startup to get the descriptions of the
P2J directory object classes.
Method Signature
|
Description |
String[] getClassNames();
|
Returns an array with names
of all
defined classes.
|
boolean isClassLeaf(String classname);
|
Class is leaf if no other
object can be created under objects of the class. Also known as
terminal.
|
boolean isClassImmutable(String classname);
|
Class is immutable if the
back-end does not allow any change to its state. |
AttributeDefinition[] getClassDefinition(String classname);
|
Returns an array of objects
describing class attributes.
|
The array of AttributeDefinition
s returned from getClassDefinition
method call is different from the array of NodeAttribute
s
which is part of the API. The following table lists methods of the AttributeDefinition
class.
Method Signature
|
Description |
String getName();
|
Returns the name of attribute.
|
int getType();
|
Returns the primitive data
type
of the attribute encoded as an integer value ATTR_* (see Primitive
Directory Data Types) |
boolean isMandatory();
|
Returns true if
attribute is mandatory. |
boolean isMultiple();
|
Returns true if
attribute can have multiple values. |
boolean isImmutable();
|
Returns true if
attribute is readonly.
|
int getSize(); |
Returns exact size for fixed
size attributes and 0 for unlimited size strings. The returned value is
either the number of bytes for binary attributes, or the number of
characters.
|
All methods listed so far should be made available for the front-end
unconditionally. They are designed to be static in the following sense.
The back-end is allowed to query the related information from its
backing storage once at startup and then keep it in a memory cache.
These methods do not have to be used within bind() and unbind()
brackets.
Back-ends are free to chose a convenient storage method for all this
information, but they have to provide a conversion tool that takes a
XML file and creates the appropriate internal representation.
Working with
Objects and Attributes
Methods listed below require a session delimited with a pair of calls
to bind() and unbind().
Method Signature
|
Description |
boolean bind ();
|
Delegated calls
|
boolean unbind ();
|
String[] enumerateNodes(String nodeId);
|
AttributeDefinition[] enumerateNodeAttributes(String nodeId);
|
Triggered
by the API call
|
boolean
deleteNodeAttributeValue(String nodeId, String name, int index); |
Delegated calls |
boolean
deleteNodeAttribute(String nodeId, String name); |
boolean addNode(String
nodeId, String class, String[] names, Object[] values); |
boolean
deleteNode(String nodeId); |
boolean moveNode(String
sourceId, String destinationId); |
public Integer getNodeInteger(String nodeId, String name, int index);
|
public Boolean getNodeBoolean(String nodeId, String name, int index);
|
public String getNodeString(String nodeId, String name, int index);
|
public Double getNodeDouble(String nodeId, String name, int index);
|
public byte[] getNodeByteArray(String nodeId, String name, int index);
|
public BitField getNodeBitField(String nodeId, String name, int index);
|
public BitSelector getNodeBitSelector(String nodeId, String name, int index);
|
public Date getNodeDate(String nodeId, String name, int index);
|
public Time getNodeTime(String nodeId, String name, int index);
|
boolean setNodeInteger(String nodeId, String name, int index, int value);
|
boolean setNodeBoolean(String nodeId, String name, int index, boolean value);
|
boolean setNodeString(String nodeId, String name, int index, String value);
|
boolean setNodeDouble(String nodeId, String name, int index, double value);
|
boolean setNodeByteArray(String nodeId, String name, int index, byte[] value);
|
boolean setNodeBitField(String nodeId, String name, int index, BitField value);
|
boolean setNodeBitSelector(String nodeId, String name, int index, BitSelector value);
|
boolean setNodeDate(String nodeId, String name, int index, Date value);
|
boolean setNodeTime(String nodeId, String name, int index, Time value);
|
boolean addNodeInteger(String nodeId, String name, int value);
|
boolean addNodeBoolean(String nodeId, String name, boolean value);
|
boolean addNodeString(String nodeId, String name, String value);
|
boolean addNodeDouble(String nodeId, String name, double value);
|
boolean addNodeByteArray(String nodeId, String name, byte[] value);
|
boolean addNodeBitField(String nodeId, String name, BitField value);
|
boolean addNodeBitSelector(String nodeId, String name, BitSelector value);
|
boolean addNodeDate(String nodeId, String name, Date value);
|
boolean addNodeTime(String nodeId, String name, Time value);
|
Approach to Mapping
Mapping is a procedure of determination of a set of the backing storage
identifiers, allowing retrieval and modification of a given P2J
object's attribute. Mapping of P2J objects and attributes is the
function of:
This is the most obvious
dependency. The back-end implementation would try to find the
closest match from its pool of resources to represent objects of
specific class and they most likely would be different.
Even similar P2J attributes may belong
to different object classes in the backing storage.
This is the least obvious dependency.
Instances of some class under one tree branch in P2J directory may
require a different representation in the backing storage from the
instances of the same class under another tree branch. There will be
three distinctive cases:
Object names or paths do not matter.
- P2J path: specific name (like /x/y/z)
Mapping is specific to this instance.
- P2J path: specific path (like /x/y/ with the terminating slash)
All instances of this class under this
node.
This structure of the mapping information makes it a convenient
attachment to the class definitions. Every class/attribute record gets
associated with one (path:*) or more (other cases) of mapping records.
Although it may not be obvious, the structure of the mapping
information also specifies the allowed paths where objects of a given
class are allowed to be placed. Path:* acts as no limitation.
Otherwise, the instances of the class the entry describes are allowed
under specified path. Thus, multiple mappings may exist referring to
the same back-end information, but specifying different paths where
objects of the class can be placed.
Configuration XML
The configuration is kept in a XML file. This file is structured in a
way that allows a separate utility class to provide the parsing of the
file and calling the back-end's configure
method to
process the configuration information. Configuration information
that is
specific to multiple back-ends can be put there.
The XML file has the following elements and attributes (please note
that back-ends may add extra attributes to any element):
- the root element
<directory>
- zero or more elements
<configuration
type="backendname"/>
- zero or more elements
<configuration class="backendclassname"/>
- multiple elements
<class name="classname">
- zero or more elements
<attribute name="attributename">
- one or more elements
<path value="path">
- zero or more elements
<mapping
type="backendname"/>
</path>
</attribute>
</class>
</directory>
Notes
- backendname specifies
the back-end. Multiple back-ends may put their elements using their
distinctive names.
type
and class
specify two possible
approaches to define back-end names (see Instantiation and
Initialization for details).
configuration
element is a convenient way of putting
some generic back-end configuration information using XML attributes.
- Mapping information is put under
class, attribute, path
elements using back-end specific XML attributes.
LDAP Back-End
LDAP is defined in RFC3377.
LDAP is also about a hierarchy of objects of various classes, standard
and
customized. In theory, that makes a LDAP back-end
implementation
relatively straightforward. However, there are additional
considerations, that complicate the task:
- A P2J object does not necessarily map into a single LDAP object,
but
may require mapping to multiple objects of different classes;
- LDAP objects of the same or similar class may reside under
multiple paths in the LDAP directory and may have to be represented as
a logical union;
- not all P2J objects have to be mapped the same way; some objects
may remain purely virtual, like meta objects, others have to be
represented by LDAP objects.
A reasonable LDAP back-end implementation should address all listed
issues.
Mapping Directory
Operations
LDAP clients use sessions to query or modify directory entries.
P2J Directory Operation
|
Description
|
LDAP
Operation
|
bind()
|
Authenticates the client to the server and
creates a session
|
bind |
unbind()
|
Terminates the session
|
unbind |
The Directory Service maintains no more than one open session per
security context
through SecurityManager token management methods. All clients of
the Directory
Service are
authenticated to LDAP as the Directory Service.
P2J Directory Operation
|
Description
|
LDAP
Operation
|
enumerate...()
get...()
|
Makes an LDAP server search a portion of
the directory and return the requested results
|
search |
n/a
|
Checks whether a specific
attribute value exists
|
compare |
P2J Directory Operation
|
Description
|
LDAP
Operation
|
addNode()
|
Creates new objects in the directory.
|
add |
deleteNode()
|
Deletes existing objects from
the directory.
|
delete |
addNode...()
setNode...()
deleteNodeAttribute...()
|
Changes the attributes and
values contained within an existing entry. New attributes can be
added
and existing attributes can be deleted.
|
modify
modify DN
|
Mapping Directory Objects
Following mapping approaches are possible:
First approach assumes
that some kind of correspondence between LDAP schema and P2J schema is
established and mapping information of the directory objects can be of
two distinct
types:
- Mapping between object classes or schema-level mapping;
- Mapping between nodes or node-level
mapping;
The schema-level mapping defines how P2J and LDAP object classes map
into each other, i.e. establish correspondence between P2J and LDAP
object classes and their attributes. This is static information and
can't be changed without restarting directory service.
The node-level mapping defines which P2J node corresponds to particular
LDAP node. This is dynamic information which may change at run time as
directory is updated.
This approach is rather simple, its performance is limited only by LDAP
server and it allows implementation of the general purpose LDAP
back-end which will support full set of directory operations:
adding/removing/moving nodes, adding/removing/updating attributes. But
this approach is not flexible enough to cover all possible mapping
cases, because it does not allow to map one P2J object class into
several P2J classes.
Second approach
assumes that mapping should be done for each individual
attribute of the each particular node. This approach does not have
limitations on correspondence between object classes ans is more
flexible but does not allow implementation of all directory operations
because in general case there is no source of the information how to
map new node into existing LDAP nodes and attributes or where to create
new LDAP nodes and how to fill attributes unused by the P2J. Another
problem is high resource consumption and questionable performance: each
operation in may request data from several LDAP nodes and mapping
information for the
large directory may have significant size.
Third approach is
similar to second one except it assumes that custom back-end is written
for each particular existing LDAP directory and information required
for creation nodes is obtained in some way which is also specific to
this particular directory. Also, this approach may allow significantly
reduce amount of mapping information by establishing some kind of rules
which would allow to calculate mapping for each node and/or attribute
instead of maintaining full mapping . This does allow to create fully
functional directory but high resource consumption and questionable
performance is still present.
Current implementation uses first approach.
Schema-level mapping
For the schema-level mapping there are two distinctive cases: an
existing LDAP directory that needs
mapping so that the P2J directory can reuse existing data, and an LDAP
directory designed specifically to support P2J. In both cases P2J
can rely on presence of the LDAP schema which can be considered
P2J-friendly, i.e. can be mapped into P2J schema relatively
straightforward. For case of existing LDAP directory P2J-friendly
schema
is created by deriving new LDAP classes and attributes from existing
ones. For case of specifically designed LDAP directory, appropriate
LDAP schema can be automatically generated using LdapMapGen
utility.
When LDAP directory is specifically designed for P2J then it is
possible to map all non-meta P2J directory objects
into real LDAP directory objects. All functionality of the
logical
directory tree is available. Every object class of the P2J
directory
maps into a specifically defined custom object class. Thus, every
P2J
attribute can have the exact match in the LDAP directory, which makes
the task of mapping objects straight forward. The root of
the P2J
directory maps into a specified path on the LDAP directory, and the
rest is a one-for-one correspondence.
The process of mapping consists of the following steps:
- a new LDAP schema is created with object classes modeled after
the P2J directory; it can be written manually (see Appendix A for
a proposed draft of such a schema) or automatically generated from the
P2J schema definition file using LdapMapGen
utility;
- Schema-level mapping data is written into LDAP directory using LdapMapGen utility;
See RFC3703
for an example of a similar mapping.
When using existing LDAP directory then new schema should be written
using one provides in Appendix
A as a starting point. Each object class and attribute from the
sample schema should be reviewed and derived from existing object
classes and attributes to get as much information mapped into P2J as
possible. Finally schema-level mapping information should be put into
appropriate part of the LdapMapGen
utility configuration file. Later this information will be used to
generate complete mapping data for use by LDAP back-end.
Node-level mapping
For the node-level mapping situation is more complicated. There are
three possible situations:
- Directory structure designed specifically for P2J
- Directory which contains all required data but has different
structure
- Directory which does not contain all required data
In first case mapping is straightforward and can be done automatically
at startup of the LDAP back-end. Since there is one-to-one
correspondence between P2J and LDAP nodes resulting directory is
completely functional for reading and writing.
In second case mapping data generation can automated with LdapMapGen utility and then
maintained by LDAP back-end. In this case some P2J nodes have
appropriate counterparts in the LDAP directory, but some intermediate
(i.e. non-leaf) nodes will be artificial and have no corresponding LDAP
nodes. Modification of such an artificial nodes can't be mapped into
LDAP directory and therefore is not allowed. Otherwise resulting P2J
directory is completely functional for reading and writing.
In third case mapping data can be partially generated with LdapMapGen utility and then missing
parts should be added manually. In resulting P2J directory can be
changed only nodes which have corresponding nodes in the LDAP,
remaining nodes are read-only.
Configuration
All configuration information that the LDAP back-end needs is made of
two sorts of data:
- configuration that allows getting to the LDAP server;
- configuration that can be made persistent using LDAP directory as
a storage.package.html
The LDAP access (bootstrap)
configuration is part of the P2J server
bootstrap configuration. It consists of the bare minimum of
information
that would allow the Directory Service startup code to bind to the LDAP
server using JNDI, and query the directory entries with the rest of the
configuration information. The
bootstrap information should include
details needed for initial authentication of the back-end by LDAP:
- back-end assignment information, specifying LDAP back-end;
- LDAP URL, which includes connection type (TLS or regular) host,
optional port (if it does not matches standard one), and initial bind
point;
- LDAP principal and credentials (if TLS certificate authentication
is not used)
- LDAP authentication type (simple, SASL EXTERNAL, utilizing TLS);
- server's certificate and private key for TLS
All configuration data that is not part of the bootstrap configuration,
is part of the configuration which can be stored in the LDAP directory
itself. This
should
be no problem even for an existing LDAP directory, as all it takes is
apackage.htmlnother custom object class for storing P2J directory configuration.
The P2J directory object class definitions is the core of the
persistent configuration. LDAP mapping information extends the
class
definitions with details of mapping, possibly down to the attribute
level. See Appendix B for an example of such mapping.
Bulk Loading Configuration
The original definition of all pieces of persistent configuration
information is kept in a XML file. To be useful, this information
has
to be translated into a set of LDAP entries and attribute values.
This
is done using a stand-alone utility LdapMapGen.
The existing persistent configuration in LDAP directory is replaced
completely. This also means, that the XML configuration file can
be considered
a
backup file for persistent configuration data.
Importing/Exporting The Directory
DirectoryCopy
is a stand-alone utility that instantiates
two back-ends
simultaneously. The source back-end has the full access to the
directory information. The target back-end is an empty directory
(besides the class description information).
The utility makes calls as defined by the Remapper
interface and traverses the tree copying the objects with their
attributes from the source to the target. At the end, the target
directory contains a full copy of the source.
Although DirectoryCopy allows any back-end to be copied to any other
back-end, the most obvious use for this tool allows using the XML
back-end file format as a persistence mechanism for the production
directory. In this case, one can easily import an entire
directory using the source back-end as XML and the target back-end as
LDAP. Likewise, using a source back-end of LDAP and target
back-end of XML allows an easy export of the current production
directory into the standard XML back-end format.
Directory Resource Plugin
All Directory Service APIs are subject to access rights checks.
There
is an abstract resource type named "directory" and a class that is the
resource plugin.
The resource plugin considers these actions as the basis for the
security decisions:
Action
|
Meaning for Nodes
|
Meaning for Attributes
|
no
access
|
access is denied without further checks
|
enumerate
|
this node is visible when
enumerating children of its parent node
|
this attribute is visible
when enumerating all attributes of this node
|
create
|
this node can be created
|
a value can be set for the
previously non-existent attribute
|
delete
|
this node can be deleted
|
the last (or the only) value
of this attribute can be deleted
|
add
|
a child node can be added to
this node
|
another value can be added to
the existing attribute
|
read
|
meta class of this node can
be read
|
attribute value can be read
|
write
|
this node is not readonly
(can change state)
|
attribute value can be
modified
|
The "directory" resource comes with a simple structure of access
rights,
made of two fields. Here comes the description.
The field 1 describes the access rights which are mapped bitwise to the
actions, plus a negation bit:
Field's primitive data type |
bitfield
|
Is it optional or mandatory? |
mandatory
|
Is it variable or fixed size? |
fixed
|
Field's size |
7 bits
|
Field's displayable label |
"permissions"
|
Field's descriptive text |
Allowed actions
|
Bitfield's array of bit names |
"No
access"
"Create"
"Delete"
"Add"
"Enumerate"
"Read"
"Write"
|
Bitfield's BitSet
of unused bits |
"0000000"; all bits are used
|
The field 2 describes a generic condition which is optional:
Field's primitive data type |
string
|
Is it optional or mandatory? |
optional
|
Is it variable or fixed size? |
variable
|
Field's size |
unlimited
|
Field's displayable label |
"condition"
|
Field's descriptive text |
an arbitrary logical expression
that, if present and evaluates to "false", denies access like "No
access" permission.
|
Bitfield's array of bit names |
n/a
|
Bitfield's BitSet
of unused bits |
n/a
|
The directory resource is hierarchical. Permissions explicitly
given to
an object, are propagated down the tree for all objects having no
explicitly set permissions.
The role of meta objects in the access rights checks is special.
They
allow selective access by object class, besides the usual hierarchical
system. The rights,
assigned
to a metaclass object, determine the additional checks bound to all
objects of that class. Similarly, the rights assigned to attribute
containers under "/meta/class/..." objects, determine
the additional checks bound to all instances of that attribute.
Together, the regular hierarchy of objects under the "/security"
branch (and others), and the meta hierarchy of objects under the
"/meta" branch make a very powerful and flexible access control
system.
API Summary
NodeAttribute Class
This class represents attribute enumeration results. This class does
not provide public constructors. Objects of this class can only be
obtained through a method call. This limitation corresponds to the
static nature of the P2J directory schema.
Method Signature
|
Description |
public String getName();
|
Returns the name of attribute.
|
public int getType();
|
Returns the primitive data
type
of the attribute encoded as an integer value ATTR_* (see Primitive
Directory Data Types) |
public boolean isMandatory();
|
Returns true if
attribute is mandatory. |
public boolean isMultiple();
|
Returns true if
attribute can have multiple values. |
public int getCount();
|
Returns the number of values
assigned to the attribute.
|
Attribute Class
This class represents an attribute with values. Objects of this class
can be
instantiated or obtained through a method call. They are used as data
keepers and as the source of data when creating new nodes, allowing for
an easy object cloning. A constructor should be provided that
takes an existing Attribute instance.
Method Signature
|
Description |
public NodeAttribute getDefinition();
|
Returns the NodeAttribute
object which describes this attribute.
|
public Object getValue(int index);
|
Returns the indexed value of
the attribute as a generic object, that can be cast into its primitive
data type, or null if requested value doesn't exist. |
public boolean addValue(Object value);
|
Adds new value to the
set. The attribute should either allow multiple values or
currently have no value. Returns true
if
successful. |
public boolean setValue(int index, Object value);
|
Replaces the indexed
value. Returns true if
successful. |
public boolean deleteValue(int index);
|
Deletes the indexed value. If
it is the only value, the attribute should be optional. Returns true
if
successful. |
public int getCount();
|
Returns the number of values
currently assigned to the attribute.
|
DirectoryService Class
This class is a singleton. It provides the Directory Service
APIs. They
are listed below by category.
Initialization
Method Signature
|
Description
|
public static DirectoryService
createInstance(BootstrapConfig); |
Creates and returns an
instance of
DirectoryService class. |
public static DirectoryService
getInstance();
|
Returns an existing instance of
DirectoryService class.
|
public boolean bind (); |
Opens a session with the
Directory Service. Only one session can be open per client at a
time.
|
public String
getServerId();
|
Returns the server
identification string from the bootstrap configuration.
|
public boolean unbind (); |
Closes the currently open
session with the Directory Service.
|
Enumerations
Method Signature
|
Description |
public String[]
enumerateNodes(String nodeId); |
Returns an array of object IDs
for all children of nodeId object.
|
public NodeAttribute[] enumerateNodeAttributes(String nodeId);
|
Returns an array of attribute
definitions for all existing attributes of nodeId object.
|
Getting Attributes
Method Signature |
Description |
public Integer getNodeInteger(String nodeId, String name, int index);
public Integer getNodeInteger(String nodeId, String name);
|
These methods
take the object ID, attribute name and attribute value index and return
an object that represents the selected value of the attribute, or null
if query fails. Single valued attributes should be queried as
index
0.
|
public Boolean getNodeBoolean(String nodeId, String name, int index);
public Boolean getNodeBoolean(String nodeId, String name);
|
public String getNodeString(String nodeId, String name, int index);
public String getNodeString(String nodeId, String name);
|
public Double getNodeDouble(String nodeId, String name, int index);
public Double getNodeDouble(String nodeId, String name);
|
public byte[] getNodeByteArray(String nodeId, String name, int index);
public byte[] getNodeByteArray(String nodeId, String name);
|
public BitField getNodeBitField(String nodeId, String name, int index);
public BitField getNodeBitField(String nodeId, String name);
|
public BitSelector getNodeBitSelector(String nodeId, String name, int index);
public BitSelector getNodeBitSelector(String nodeId, String name);
|
public Date getNodeDate(String nodeId, String name, int index);
public Date getNodeDate(String nodeId, String name);
|
public Time getNodeTime(String nodeId, String name, int index);
public Time getNodeTime(String nodeId, String name);
|
public Integer[] getNodeIntegers(String nodeId, String name);
|
These methods
take the object ID and attribute name ad return an array of objects
representing all existing values of the attribute, or null
if query fails. |
public Boolean[] getNodeBooleans(String nodeId, String name);
|
public String[] getNodeStrings(String nodeId, String name);
|
public Double[] getNodeDoubles(String nodeId, String name);
|
public byte[][] getNodeByteArrays(String nodeId, String name);
|
public BitField[] getNodeBitFields(String nodeId, String name);
|
public BitSelector[] getNodeBitSelectors(String nodeId, String name);
|
public Date[] getNodeDates(String nodeId, String name);
|
public Time[] getNodeTimes(String nodeId, String name);
|
public Attribute[] getNodeAttributes(String nodeId);
|
Returns the entire set of
attributes with all their values, or null
if query fails. |
Setting Attributes
Method Signature |
Description |
public boolean setNodeInteger(String nodeId, String name, int index, int value);
|
These methods
take an object ID, attribute name, attribute value index and a value
and change the indexed value of the attribute.
|
public boolean setNodeBoolean(String nodeId, String name, int index, boolean value);
|
public boolean setNodeString(String nodeId, String name, int index, String value);
|
public boolean setNodeDouble(String nodeId, String name, int index, double value);
|
public boolean setNodeByteArray(String nodeId, String name, int index, byte[] value);
|
public boolean setNodeBitField(String nodeId, String name, int index, BitField value);
|
public boolean setNodeBitSelector(String nodeId, String name, int index, BitSelector value);
|
public boolean setNodeDate(String nodeId, String name, int index, Date value);
|
public boolean setNodeTime(String nodeId, String name, int index, Time value);
|
public boolean addNodeInteger(String nodeId, String name, int value);
|
These methods
take an object ID, attribute name, and a new value and the value to the
existing set. |
public boolean addNodeBoolean(String nodeId, String name, boolean value);
|
public boolean addNodeString(String nodeId, String name, String value);
|
public boolean addNodeDouble(String nodeId, String name, double value);
|
public boolean addNodeByteArray(String nodeId, String name, byte[] value);
|
public boolean addNodeBitField(String nodeId, String name, BitField value);
|
public boolean addNodeBitSelector(String nodeId, String name, BitSelector value);
|
public boolean addNodeDate(String nodeId, String name, Date value);
|
public boolean addNodeTime(String nodeId, String name, Time value);
|
public boolean setNodeIntegers(String nodeId, String name, int[] value);
|
These methods
take an object ID, attribute name, and an array of new values and
replace the existing values with the new ones.
|
public boolean setNodeBooleans(String nodeId, String name, boolean[] value);
|
public boolean setNodeStrings(String nodeId, String name, String[] value);
|
public boolean setNodeDoubles(String nodeId, String name, double[] value);
|
public boolean setNodeByteArrays(String nodeId, String name, byte[][] value);
|
public boolean setNodeBitFields(String nodeId, String name, BitField[] value);
|
public boolean setNodeBitSelectors(String nodeId, String name, BitSelector[] value);
|
public boolean setNodeDates(String nodeId, String name, Date[] value);
|
public boolean setNodeTimes(String nodeId, String name, Time[] value);
|
public setNodeAttributes(String nodeId, Attribute[] data);
|
Replaces all attributes with
a new set at once. Operation fails if
the new set of attributes does not include all mandatory ones. |
Deleting Attributes
Method Signature
|
Description |
public boolean deleteNodeAttributeValue(String nodeId, String name, int index);
|
Takes an object ID, attribute
name, and value index and deletes the indexed attribute value.
|
public boolean deleteNodeAttribute(String nodeId, String name);
|
Takes an object ID and attribute
name and deletes the whole attribute.
|
Working with Objects
Method Signature
|
Description |
public boolean addNode(String nodeId, String class, Attribute[] data);
|
Takes an object ID of a parent
object, object class name, and arrays of attribute names and values and
creates a new object. Operation fails if
the set of attributes does not include all mandatory ones.
|
public boolean deleteNode(String nodeId);
|
Takes an object ID and deletes
the specified object.
|
public boolean moveNode(String nodeId, String newId);
|
Moves or renames the existing
object, specified by nodeId. The parent object of the newId should
exist and allow for children creation.
|
Working with Meta Objects
Method Signature
|
Description |
public String getNodeClass(String nodeId);
|
Takes an object ID and returns
the object ID of the metaclass object. |
Batch Editing
Method Signature
|
Description
|
public
boolean openBatch(String nodeId) ;
|
Returns true
if an editing batch has been opened. Fails if another batch is
open for
the calling security context or if the specified branch is already busy.
|
public
boolean isEditing() ;
|
Returns true
if an editing batch is currently open.
|
public boolean
closeBatch(boolean disposition); |
Closes the currently open
editing batch. The disposition parameter tells what to do with
the
closed batch:
true means apply changes to the directory;
false means discard the batch.
Returns true
if the requested disposition has been successfully applied.
|
Predefined Object
Classes
Internal classes
Class Name
|
Terminal
|
Attribute Name
|
Primitive Type
|
Mandatory
|
Multivalued
|
Comments
|
"container"
|
|
The simplest directory object class. The
only function of containers is to be a parent to its children
objects.
Class defines no attributes.
|
"terminal"
|
+
|
The simplest directory object class. The
only function of terminals is to represent a valid object
ID. Class defines no attributes. |
"metaclass"
|
|
This class describes directory object classes |
attrname
|
string
|
+
|
+
|
attribute names
|
attrtype
|
integer
|
+
|
+
|
encoded attribute types
|
attropt
|
boolean
|
+
|
+
|
mandatory/optional
|
attrmult
|
boolean
|
+
|
+
|
multiple/single valued
|
Mandatory single
valued
Class Name
|
Terminal
|
Attribute Name
|
Primitive Type
|
Mandatory
|
Multivalued
|
Comments
|
"integer"
|
|
Named integer value class
|
value
|
integer
|
+
|
|
value
|
"boolean"
|
|
Named boolean value class
|
value
|
boolean
|
+
|
|
value
|
"string"
|
|
Named string value class
|
value
|
string
|
+
|
|
value
|
"bytes"
|
|
Named bytearray value class
|
value
|
bytearray
|
+
|
|
value
|
Optional single
valued
Class Name
|
Terminal
|
Attribute Name
|
Primitive Type
|
Mandatory
|
Multivalued
|
Comments
|
"integerOption"
|
|
Named integer value class
|
option
|
integer
|
|
|
value
|
"booleanOption"
|
|
Named boolean value class
|
option |
boolean
|
|
|
value
|
"stringOption"
|
|
Named string value class
|
option |
string
|
|
|
value
|
"bytesOption"
|
|
Named bytearray value class
|
option |
bytearray
|
|
|
value
|
Optional
multiple valued
Class Name
|
Terminal
|
Attribute Name
|
Primitive Type
|
Mandatory
|
Multivalued
|
Comments
|
"integers"
|
|
Named integer value class
|
values
|
integer
|
|
+
|
values
|
"booleans"
|
|
Named boolean value class
|
values
|
boolean
|
|
+
|
values
|
"strings"
|
|
Named string value class
|
values |
string
|
|
+
|
valuess
|
"bytess"
|
|
Named bytearray value class
|
values |
bytearray
|
|
+
|
values
|
Security Accounts Classes
Class Name
|
Terminal
|
Attribute Name
|
Primitive Type
|
Mandatory
|
Multivalued
|
Comments
|
"user"
|
+
|
Defines a user account. Object name is the
user ID.
|
person
|
string
|
|
|
user name
|
alias
|
string
|
|
|
associates this account with
X.509 certificate |
password
|
bytearray
|
|
|
hashed password
|
pwsetdate |
date
|
|
|
date
password was set; may be used for aging |
pwsettime |
time
|
|
|
time
password was set; may be used for aging |
groups |
string
|
|
+
|
groups
this user is assigned to |
mode
|
integer
|
|
|
authentication mode override
|
"group"
|
+
|
Defines a group account. Object name is
the group ID.
|
description
|
string
|
|
|
group description
|
"process"
|
+
|
Defines a process account. Object name is
the process ID.
|
description
|
string
|
|
|
description
|
server |
boolean
|
|
|
defines process role as server
(true) or application (false or
omitted) |
master
|
boolean
|
|
|
if
set to true for a server, the server is a master server |
alias
|
string
|
|
|
associates this account with
X.509 certificate and, optionally,
PKCS#8 private key |
secret |
bytearray
|
|
|
secret
key servers use to access keystore |
Security Audit Classes
Class Name
|
Terminal
|
Attribute Name
|
Primitive Type
|
Mandatory
|
Multivalued
|
Comments
|
"auditDecision"
|
+
|
Defines audit modes for security decisions
|
success
|
boolean
|
|
|
if set to
true, audits granted accesses |
failure
|
boolean
|
|
|
if set
to true, audits denied accesses |
"auditResource"
|
+
|
Defines auditing per resource instance |
instances |
string
|
|
+
|
optional resource
instance names |
requests |
integer
|
|
+
|
optional requested
rights |
ACL Classes
Class Name
|
Terminal
|
Attribute Name
|
Primitive Type
|
Mandatory
|
Multivalued
|
Comments
|
"binding"
|
+
|
Defines an association between multiple
subjects and resource instances. Object names are sequential.
|
subjects
|
string
|
+
|
+
|
list of subject
names (object names for user, group and process) |
reftype
|
boolean
|
+
|
+
|
one flag per reference;
true - the reference refers to a specific resource instance
false - the reference refers to a match string
|
reference
|
string
|
+
|
+
|
list of references to
resource instance names or match strings (regular expressions) that
specify a match to multiple resource instance names
|
"systemRights"
|
|
Defines access rights object for the "system" resource
type. Object names are
sequential. |
check
|
string
|
+
|
|
user-defined logical expression
that must evaluate true for access to be granted
|
"directoryRights"
|
|
Defines access rights object for the "directory" resource
type. Object names are
sequential. |
permissions
|
bitfield
|
+
|
|
7-bit bitfield, NCDAERW
|
condition
|
string
|
|
|
optional logical expression that
must evaluate true for the access defined in the attribute named
"permissions" to be granted
|
"netRights"
|
|
Defines access rights object for the "net" resource
type. Object names are
sequential. |
permissions |
bitfield |
+
|
|
4-bit bitfield, NRWX
|
"adminRights"
|
|
Defines access rights object for the "net" resource
type. Object names are
sequential. |
type
|
integer
|
+
|
|
type defines the meaning of the permissions
|
permissions
|
bitfield
|
+
|
|
type ADMT_PATH: 2-bit bitfield NU
|
type ADMT_USER: 8-bit bitfield NEPGRWCD
|
Miscellaneous
Security Classes
Class Name
|
Terminal
|
Attribute Name
|
Primitive Type
|
Mandatory
|
Multivalued
|
Comments
|
"authMode"
|
+
|
Defines authorization mode details |
anonymous |
string
|
|
|
name for anonymous
account; if omitted, no anonymous connection allowed |
mode
|
integer
|
+
|
|
authorization mode |
plugin
|
string
|
|
|
optional authorization hook name
|
option
|
string
|
|
|
optional authorization hook
parameters |
retries
|
integer
|
|
|
optional authrntication retries
mode
|
"lock"
|
+
|
Defines a directory lock object. Object
name is the process ID of the
server who
created this object. |
backed-up |
boolean
|
|
|
if present and set to
true, backup is available |
backupId
|
string
|
|
|
the location of the backup
created before applying changes
|
Appendix A. LDAP Schema Draft
The following schema definition is experimental and can be considered a
starting point in the implementation of LDAP back-end. The object
identifiers used are those taken from the special dead space, which is good for
experiments. A real implementation must be based on the IANA assigned
object IDs. As of this writing, the IANA application has not yet
been processed to obtain a Golden Code unique object ID.
Another note is about the back-end specific objects that keep the class
definition information. They are not part of this schema, because it is
up to the implementors of the LDAP back-end to chose what is the most
convenient for them. As that piece is encapsulated in the back-end, no
other part of the design is affected.
Having
said that, this is a working implementation that can
be used with OpenLDAP.
###########################################################################
# #
# GCD P2J Directory Schema #
# #
###########################################################################
# Macros ------------------------------------------------------------------
objectidentifier GCD 1.1
objectidentifier GCD.P2J GCD:2
objectidentifier GCD.P2J.OC GCD.P2J:1
objectidentifier GCD.P2J.At GCD.P2J:2
#---- attributes ----------------------------------------------------------
#---- basic attribute types -----------------
attributetype ( GCD.P2J.At:1 NAME 'gcdInteger'
DESC 'P2J directory integers attribute'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
attributetype ( GCD.P2J.At:2 NAME 'gcdIntegers'
DESC 'P2J directory integers attribute'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27)
attributetype ( GCD.P2J.At:3 NAME 'gcdBoolean'
DESC 'P2J directory boolean attribute'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
attributetype ( GCD.P2J.At:4 NAME 'gcdBooleans'
DESC 'P2J directory booleans attribute'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7)
attributetype ( GCD.P2J.At:5 NAME 'gcdString'
DESC 'P2J directory string attribute'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
attributetype ( GCD.P2J.At:6 NAME 'gcdStrings'
DESC 'P2J directory strings attribute'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( GCD.P2J.At:7 NAME 'gcdByteArray'
DESC 'P2J directory bytearray attribute'
EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
SINGLE-VALUE )
attributetype ( GCD.P2J.At:8 NAME 'gcdByteArrays'
DESC 'P2J directory bytearrays attribute'
EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40)
attributetype ( GCD.P2J.At:9 NAME 'gcdBitField'
DESC 'P2J directory bitfield attribute'
EQUALITY bitStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.6
SINGLE-VALUE )
attributetype ( GCD.P2J.At:10 NAME 'gcdBitFields'
DESC 'P2J directory bitfields attribute'
EQUALITY bitStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.6)
attributetype ( GCD.P2J.At:11 NAME 'gcdBitSelector'
DESC 'P2J directory bitselector attribute'
EQUALITY bitStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.6
SINGLE-VALUE )
attributetype ( GCD.P2J.At:12 NAME 'gcdBitSelectors'
DESC 'P2J directory bitselectors attribute'
EQUALITY bitStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.6)
attributetype ( GCD.P2J.At:13 NAME 'gcdDate'
DESC 'P2J directory date attribute'
EQUALITY caseExactMatch
SUBSTR caseExactSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
attributetype ( GCD.P2J.At:14 NAME 'gcdDates'
DESC 'P2J directory dates attribute'
EQUALITY caseExactMatch
SUBSTR caseExactSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( GCD.P2J.At:15 NAME 'gcdTime'
DESC 'P2J directory time attribute'
EQUALITY caseExactMatch
SUBSTR caseExactSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
attributetype ( GCD.P2J.At:16 NAME 'gcdTimes'
DESC 'P2J directory times attribute'
EQUALITY caseExactMatch
SUBSTR caseExactSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
# No replacement for the Double.
#---- derived attribute types -----------------
attributetype ( GCD.P2J.At:100 NAME 'gcdAuditDecisionSuccess' SUP gcdBoolean)
attributetype ( GCD.P2J.At:101 NAME 'gcdAuditDecisionFailure' SUP gcdBoolean)
attributetype ( GCD.P2J.At:102 NAME 'gcdAuditResourceType' SUP gcdString)
attributetype ( GCD.P2J.At:103 NAME 'gcdAuditResourceInstances' SUP gcdStrings)
attributetype ( GCD.P2J.At:104 NAME 'gcdAuditResourceRequests' SUP gcdIntegers)
attributetype ( GCD.P2J.At:105 NAME 'gcdAuthModeAnonymous' SUP gcdString)
attributetype ( GCD.P2J.At:106 NAME 'gcdAuthModeMode' SUP gcdInteger)
attributetype ( GCD.P2J.At:107 NAME 'gcdAuthModePlugin' SUP gcdString)
attributetype ( GCD.P2J.At:108 NAME 'gcdAuthModeOption' SUP gcdString)
attributetype ( GCD.P2J.At:109 NAME 'gcdBindingReftype' SUP gcdBoolean)
attributetype ( GCD.P2J.At:110 NAME 'gcdBindingReference' SUP gcdString)
attributetype ( GCD.P2J.At:111 NAME 'gcdBooleanValue' SUP gcdBoolean)
attributetype ( GCD.P2J.At:112 NAME 'gcdBooleanOptionOption' SUP gcdBoolean)
attributetype ( GCD.P2J.At:113 NAME 'gcdBooleansValues' SUP gcdBooleans)
attributetype ( GCD.P2J.At:114 NAME 'gcdBytesValue' SUP gcdByteArray)
attributetype ( GCD.P2J.At:115 NAME 'gcdBytesOptionOption' SUP gcdByteArray)
attributetype ( GCD.P2J.At:116 NAME 'gcdBytessValues' SUP gcdByteArrays)
attributetype ( GCD.P2J.At:117 NAME 'gcdDateOptionOption' SUP gcdDate)
attributetype ( GCD.P2J.At:118 NAME 'gcdDatesValues' SUP gcdDates)
attributetype ( GCD.P2J.At:119 NAME 'gcdDirectoryRightsPermissions' SUP gcdBitField)
attributetype ( GCD.P2J.At:120 NAME 'gcdDirectoryRightsCondition' SUP gcdString)
attributetype ( GCD.P2J.At:121 NAME 'gcdGroupDescription' SUP gcdString)
attributetype ( GCD.P2J.At:122 NAME 'gcdIntegerValue' SUP gcdInteger)
attributetype ( GCD.P2J.At:123 NAME 'gcdIntegerOptionOption' SUP gcdInteger)
attributetype ( GCD.P2J.At:124 NAME 'gcdIntegersValues' SUP gcdIntegers)
attributetype ( GCD.P2J.At:125 NAME 'gcdLockBackedUp' SUP gcdBoolean)
attributetype ( GCD.P2J.At:126 NAME 'gcdLockBackupId' SUP gcdString)
attributetype ( GCD.P2J.At:127 NAME 'gcdNetRightsPermissions' SUP gcdBitField)
attributetype ( GCD.P2J.At:128 NAME 'gcdProcessDescription' SUP gcdString)
attributetype ( GCD.P2J.At:129 NAME 'gcdProcessServer' SUP gcdBoolean)
attributetype ( GCD.P2J.At:130 NAME 'gcdProcessMaster' SUP gcdBoolean)
attributetype ( GCD.P2J.At:131 NAME 'gcdProcessAlias' SUP gcdString)
attributetype ( GCD.P2J.At:132 NAME 'gcdProcessSecret' SUP gcdByteArray)
attributetype ( GCD.P2J.At:133 NAME 'gcdStringValue' SUP gcdString)
attributetype ( GCD.P2J.At:134 NAME 'gcdStringOptionOption' SUP gcdString)
attributetype ( GCD.P2J.At:135 NAME 'gcdStringsValues' SUP gcdStrings)
attributetype ( GCD.P2J.At:136 NAME 'gcdSystemRightsCheck' SUP gcdString)
attributetype ( GCD.P2J.At:137 NAME 'gcdUserPerson' SUP gcdString)
attributetype ( GCD.P2J.At:138 NAME 'gcdUserAlias' SUP gcdString)
attributetype ( GCD.P2J.At:139 NAME 'gcdUserPassword' SUP gcdByteArray)
attributetype ( GCD.P2J.At:140 NAME 'gcdUserPwsetdate' SUP gcdDate)
attributetype ( GCD.P2J.At:141 NAME 'gcdUserPwsettime' SUP gcdTime)
attributetype ( GCD.P2J.At:142 NAME 'gcdUserGroups' SUP gcdStrings)
attributetype ( GCD.P2J.At:143 NAME 'gcdUserMode' SUP gcdInteger)
#---- object classes --------------------------------------------------------
# auditDecision
objectclass ( GCD.P2J.OC:1 NAME 'gcdAuditDecision'
DESC 'P2J auditDecision class'
SUP top STRUCTURAL
MUST cn
MAY (gcdAuditDecisionSuccess $ gcdAuditDecisionFailure))
# auditResource
objectclass ( GCD.P2J.OC:2 NAME 'gcdAuditResource'
DESC 'P2J auditResource class'
SUP top STRUCTURAL
MUST (cn $ gcdAuditResourceType)
MAY (gcdAuditResourceInstances $ gcdAuditResourceRequests))
# authMode
objectclass ( GCD.P2J.OC:3 NAME 'gcdAuthMode'
DESC 'P2J authMode class'
SUP top STRUCTURAL
MUST (cn $ gcdAuthModeMode)
MAY (gcdAuthModeAnonymous $ gcdAuthModePlugin $ gcdAuthModeOption))
# binding
objectclass ( GCD.P2J.OC:4 NAME 'gcdBinding'
DESC 'P2J binding class'
SUP top STRUCTURAL
MUST (cn $ gcdBindingReftype $ gcdBindingReference))
# boolean
objectclass ( GCD.P2J.OC:5 NAME 'gcdBoolean'
DESC 'P2J boolean class'
SUP top STRUCTURAL
MUST (cn $ gcdBooleanValue))
# booleanOption
objectclass ( GCD.P2J.OC:6 NAME 'gcdBooleanOption'
DESC 'P2J booleanOption class'
SUP top STRUCTURAL
MUST cn
MAY gcdBooleanOptionOption)
# booleans
objectclass ( GCD.P2J.OC:7 NAME 'gcdBooleans'
DESC 'P2J booleans class'
SUP top STRUCTURAL
MUST cn
MAY gcdBooleansValues)
# bytes
objectclass ( GCD.P2J.OC:8 NAME 'gcdBytes'
DESC 'P2J bytes class'
SUP top STRUCTURAL
MUST (cn $ gcdBytesValue))
# bytesOption
objectclass ( GCD.P2J.OC:9 NAME 'gcdBytesOption'
DESC 'P2J bytesOption class'
SUP top STRUCTURAL
MUST cn
MAY gcdBytesOptionOption)
# bytess
objectclass ( GCD.P2J.OC:10 NAME 'gcdBytess'
DESC 'P2J bytess class'
SUP top STRUCTURAL
MUST cn
MAY gcdBytessValues)
# container
objectclass ( GCD.P2J.OC:11 NAME 'gcdContainer'
DESC 'P2J container class'
SUP top STRUCTURAL
MUST cn)
# dateOption
objectclass ( GCD.P2J.OC:12 NAME 'gcdDateOption'
DESC 'P2J dateOption class'
SUP top STRUCTURAL
MUST cn
MAY gcdDateOptionOption)
# dates
objectclass ( GCD.P2J.OC:13 NAME 'gcdDates'
DESC 'P2J dates class'
SUP top STRUCTURAL
MUST cn
MAY gcdDatesValues)
# directoryRights
objectclass ( GCD.P2J.OC:14 NAME 'gcdDirectoryRights'
DESC 'P2J directoryRights class'
SUP top STRUCTURAL
MUST (cn $ gcdDirectoryRightsPermissions)
MAY gcdDirectoryRightsCondition)
# group
objectclass ( GCD.P2J.OC:15 NAME 'gcdGroup'
DESC 'P2J group class'
SUP top STRUCTURAL
MUST cn
MAY gcdGroupDescription)
# integer
objectclass ( GCD.P2J.OC:16 NAME 'gcdInteger'
DESC 'P2J integer class'
SUP top STRUCTURAL
MUST (cn $ gcdIntegerValue))
# integerOption
objectclass ( GCD.P2J.OC:17 NAME 'gcdIntegerOption'
DESC 'P2J integerOption class'
SUP top STRUCTURAL
MUST cn
MAY gcdIntegerOptionOption)
# integers
objectclass ( GCD.P2J.OC:18 NAME 'gcdIntegers'
DESC 'P2J integers class'
SUP top STRUCTURAL
MUST cn
MAY gcdIntegersValues)
# lock
objectclass ( GCD.P2J.OC:19 NAME 'gcdLock'
DESC 'P2J lock class'
SUP top STRUCTURAL
MUST cn
MAY (gcdLockBackedUp $ gcdLockBackupId))
# netRights
objectclass ( GCD.P2J.OC:20 NAME 'gcdNetRights'
DESC 'P2J netRights class'
SUP top STRUCTURAL
MUST (cn $ gcdNetRightsPermissions))
# process
objectclass ( GCD.P2J.OC:21 NAME 'gcdProcess'
DESC 'P2J process class'
SUP top STRUCTURAL
MUST cn
MAY (gcdProcessDescription $ gcdProcessServer $ gcdProcessMaster $ gcdProcessAlias $ gcdProcessSecret))
# string
objectclass ( GCD.P2J.OC:22 NAME 'gcdString'
DESC 'P2J string class'
SUP top STRUCTURAL
MUST (cn $ gcdStringValue))
# stringOption
objectclass ( GCD.P2J.OC:23 NAME 'gcdStringOption'
DESC 'P2J stringOption class'
SUP top STRUCTURAL
MUST cn
MAY gcdStringOptionOption)
# strings
objectclass ( GCD.P2J.OC:24 NAME 'gcdStrings'
DESC 'P2J strings class'
SUP top STRUCTURAL
MUST cn
MAY gcdStringsValues)
# systemRights
objectclass ( GCD.P2J.OC:25 NAME 'gcdSystemRights'
DESC 'P2J systemRights class'
SUP top STRUCTURAL
MUST (cn $ gcdSystemRightsCheck))
# terminal
objectclass ( GCD.P2J.OC:26 NAME 'gcdTerminal'
DESC 'P2J terminal class'
SUP top STRUCTURAL
MUST cn)
# user
objectclass ( GCD.P2J.OC:27 NAME 'gcdUser'
DESC 'P2J user class'
SUP top STRUCTURAL
MUST uid
MAY (gcdUserPerson $ gcdUserAlias $ gcdUserPassword $ gcdUserPwsetdate $ gcdUserPwsettime $ gcdUserGroups $ gcdUserMode))
## end of schema
Appendix B.
LdapMapGen Utility
General Description
The design of the LDAP back-end allows different modes of operation but
all of them based on the mapping information collected in some
way. The
mapping information (or just 'mapping')
tells LDAP back-end how to represent LDAP server to P2J
DirectoryService users. The mapping contains two main parts: schema-level mapping and node-level mapping. The schema-level mapping defines how
particular LDAP object class and its attributes corresponds to P2J
object classes and attributes. The node-level
mapping defines which LDAP node represents particular node in P2J
directory.
The LDAP back-end supports two major modes of operation: when only
schema-level mapping is defined and when both schema-level and
node-level mapping are provided. The difference between them is
that
first one assumes that LDAP server already provides hierarchy suitable
for use by P2J and LDAP back-end just uses it as is. In second
mode
there is no need to have such a hierarchy, each P2J node can be
individually mapped into LDAP node and some nodes may not have
corresponding LDAP node at all. Since writing mapping information
manually is complicated and error prone procedure, LdapMapGen utility
is provided to simplify it.
The main purpose of the LdapMapGen utility is to generate mapping
information required for use of P2J DirectoryService subsystem with
LDAP server. The resulting mapping information can be stored in
the map
file in XML format recognized by LDAP back-end or at the LDAP
server in specified location. Beside that, utility in some cases
can
generate schema file suitable for use with LDAP server. This
function
has limitations explained below.
At startup utility reads the configuration file and parses it.
Then
using configuration data and command line parameters it produces output
files or updates mapping information on the LDAP server. The
configuration file contains two different kinds of information: the
configuration data (such as LDAP connection details, location of schema
file, etc.) and mapping rules. Mapping rules are split into two
parts:
schema-level mapping and node-level mapping. The utility can in
some
cases generate proper mapping information without mapping data at all
or with partial mapping data in the configuration file.
Modes of Operation
The utility supports two modes of operation: direct (or subtree) and node-to-node. First mode
assumes
that LDAP directory structure should be mapped as is into P2J
directory. Second mode requires node to node mapping data.
To simplify
writing mapping data in configuration file for second mode LdapMapGen
utility supports mapping of subtrees (see below
description of
configuration file format).
Beside these common modes there is a special case of first mode, when
no mapping information is provided at all. In this case necessary
mapping data generated automatically from the P2J schema definition
file. Also, for this situation LdapMapGen can generate LDAP
schema file
which exactly corresponds to the generated mapping.
Configuration File Format
Configuration file is an XML file of following format:
<?xml
version="1.0"?>
<!-- LdapMapGen configuration file
-->
<configuration-root>
<config .../>
<class-mapping>
<class .. >
<attribute .../>
...
</class>
...
</class-mapping>
<node-mapping>
<node .../>
</node-mapping>
</configuration-root>
Recognized attributes
Node config. This node holds
configuration information.
Attribute
|
Description
|
mapping-mode
|
Mode of the operation: perform
schema-level mapping only or both, schema-mapping and node-level
mappings.
|
ulr
|
LDAP server URL. URL format is
dictated by the JNDI interface and looks so:
protocol://host-name[:port]/ldap-root
Where:
protocol |
either ldap or ldaps. ldap is for ordinary connections and
ldaps for the TLS
connections.
|
host-name |
name of the host where
LDAP server is running. |
port |
optional port name. Unless
LDAP server is configured for non-standard ports, it uses port 389 for
regular connections and port 636 for TLS connections. |
ldap-root |
distinguished name in the
LDAP directory for initial bind. |
|
principal
|
The identity information used to
authenticate to the LDAP server.
|
credentials
|
The password.
|
mapping-destination
|
The LDAP node where resulting
mapping can be stored. If node does not exists it will be created.
|
mapping-attribute
|
The attribute name where mapping
will be stored.
|
mapping-object-class
|
Object class name of the LDAP
node where mapping will be stored.
|
ldap-schema-header
|
The content of this attribute is
used during generation of LDAP schema file. The content is
written at the beginning of the generated files as is, without changes.
The main purpose is to provide definition of LDAP attributes used by
rest of the generated schema.
|
Note:
- The mapping destination node, node object class and node
attribute name parameters are necessary only if saving mapping in the
LDAP is required. If specified node does not exists, it will be
created. The desired object class for the node should not have other
mandatory attributes except common name. The destination attribute
where mapping will be stored should support of storing of multiple
values of directory string or compatible type.
- Schema header attribute is optional.
Node class. This node holds
description for single P2J to LDAP class mapping. Configuration file
should contain separate class
node for each class to class mapping.
Attribute
|
Description |
ldap
|
LDAP object class name.
|
p2j
|
P2J object class name.
|
Node attribute. This
node holds description for single P2J to LDAP attribute mapping.
Configuration file should contain separate attribute node for each LDAP
attribute to P2J attribute mapping.
Attribute
|
Description |
ldap
|
LDAP object class attribute name.
|
p2j
|
P2J object class attribute name.
|
Note: For
each class at least one special attribute mapping must be defined:
special P2J attribute objectName
should be mapped into LDAP common name attribute. For example if some
LDAP object class uses cn as
its name, it should be mapped into objectName.
Node node. This node holds
definition for single P2J to LDAP node. Configuration file should
contain separate node node for
each node to node mapping.
Attribute
|
Description |
ldap
|
LDAP node full name. The name
may contain asterisk (*) at the
end. In this case entire subtree will be scanned recursively and mapped
into appropriate P2J subtree automatically.
|
p2j
|
P2J node name.
|
Note: if
class and node mapping information is omitted that mapping is generated
automatically from the P2J schema file specified in the configuration.
Command Line Format
Utility accepts following command line:
java LdapMapGen <source_map.xml> [-o <output_map.xml>
| -u] [-s <ldap.schema>]
Parameter
|
Description
|
<source_map.xml> |
Source configuration/mapping file
|
-o <output_map.xml> |
File name of the output file
where generated mapping will be stored
|
-u |
Write mapping into LDAP
directory instead of file name
|
-s <ldap.schema> |
Generate LDAP schema file
|
Note:
Options -o <output_map.xml> and -u are mutually exclusive.
Known Limitations
- Utility can connect LDAP server only using ordinary connection,
TLS connection is not supported.
- LDAP schema can be generated only if mapping is generated from
P2J schema.xml file. Also, see note.
- Storing mapping in the LDAP supports storing only schema-level
mapping.
Appendix C.
DirectoryEdit Utility
General Description
The DirectoryEdit utility is a simple text mode interactive menu driven
tool which allows to browse and edit P2J directory. The utility
presents a set of menus and user enters commands with optional
parametpackage.htmlers to perform operations. When this is necessary utility may
request additional input from the user.
Menu Description
Utility starts its work in Main Menu (Top Level Menu) :
Menu
item key and parameters
|
Menu
item text
|
Detailed description
|
.
|
Print menu |
Just print menu.
|
b node
|
Open batch for node |
This command opens batch editing
session for node node. If
after space no node name is provided then batch is opened for root
node. Upon successful start of batch editing session utility
automatically opens Node Level Menu for the node node.
|
b
|
Back to batch node |
This command can be used to
switch back to node level menu if batch editing session is already open.
|
c
|
Commit batch |
This command commits active
editing session and updates directory with collected changes.
Regardless from the result (success or failure) current batch editing
session is closed.
|
r
|
Rollback batch |
This command rollbacks active
editing session and throws out collected changes. Regardless from the
result of the operation current batch editing session is closed.
|
q
|
Quit
|
Quit application. If there is
active editing session then quit is not allowed, changes must be
committed or rolled back.
|
Successful opening of the batch editing session or manual switching
back to node level menu (see description of b command above) opens Node Level
Menu:
Menu
item key and parameters
|
Menu
item text
|
Detailed description
|
.
|
Print menu |
Just print menu. |
l
|
List attributes and nodes |
Print detailed list of node
attributes and child nodes.
|
t
|
List attribute definitions |
Print definitions of all
attributes defined for the current node object class.
|
E node
|
Edit node |
Open Node Level Menu for child node node. New node path is set to
current node path with appended node.
This does allow to go deeper through hierarchy of the nodes.
|
C node [class]
|
Create child node |
Create child node node of class class. If class is omitted it is requested
separately. If object class defines attributes then interaction with
the user is started. For all mandatory attributes values are requested.
Then user can add values to the attributes (both, mandatory and
ordinary).
|
D node
|
Delete child node |
Remove node node.
|
M node1 node2
|
Move node |
Move node1 to node2. Parameter node1 always assumes node relative
to the current location. Parameter node2 can represent absolute node
name or node name relative to current location. If first character of
node2 is slash then absolute path is assumed.
|
e attribute
|
Edit node attribute |
This command opens Attribute Level Menu for the
attribute attribute of current
node.
|
c attribute |
Create node attribute |
This command creates attribute
or adds new value to the existing multi-valued attribute.
|
d attribute |
Delete node attribute |
This command removes attribute attribute.
|
q
|
Quit |
Return to previous menu. If
current menu was entered from Top Level Menu then control is
returned to Top Level Menu. If
current menu was entered from Node
Level Menu of parent node then control is returned to that menu.
|
Attribute editing command opens Attribute Level Menu:
Menu item key and parameters |
Menu item text |
Detailed description |
.
|
Print menu
|
Just print menu. |
l
|
List values |
List all values of the attribute.
|
e n
|
Edit value n |
Change value n of the attribute.
|
d n
|
Delete value n |
Delete value n from the attribute.
|
a
|
Add new value |
Add new value to the attribute.
|
q
|
Quit |
Return to Node Level
Menu.
|
Appendix D.
Directory Utilities
The directory package offers a few command line utilities:
- diff - to compare two directory files or branches of the same or different directories
- copy - to copy the input directory or a branch to a copy point of the output directory
- remove - to remove a directory branch recursively
- clear - to remove, conditionally or unconditionally a value from a specific attribute or the whole attribute
- set - to add or to set a value to the specified attribute
WARNING! Except
the diff, all other utilities change the specified directory file.
Please make it a rule to create a backup copy of the file before
applying any of the utilities.
Using diff
Use diff to
compare the two directory files or branches of the directory files. The
output can be redirected to a file for analysis. The diff utility
compares the contents of the directories, which does not depend on the
order of sections in the xml file.
How to run diff
java com.goldencode.p2j.directory.DirectoryDiff
Parameters
left-dir.xml right-dir.xml [ path | left-path [ right-path] ]
You
have to specify two directory files. With no other parameters, the
whole directories will be compared. You can also give a path. Then this
directory path will specify a branch of the directories to compare. You
can also specify different paths for the first and the second directory
and only those branches will be compared.
The output will be
self-explainable. The first directory is referred to as the Left
directory, The second directory is referred to as the Right directory.
Using copy
Use
copy to copy a branch of the input directory to the specified copy
point of the output directory. Copy utility does not synchronize
directory nodes, however. If the output file contains something, it
will be preserved, not removed.
How to run copy
java com.goldencode.p2j.directory.DirectoryCopy copy
Parameters
<source-xml> <source-path> <target-xml> <target-path>
All four parameters are required. The target-xml may specify the same file as the source-xml, but be careful to specify the non-overlappping branches in this case!
The target file will be created if it doesn't exist.
Using remove
Use remove to remove a branch from a directory.
How to run remove
java com.goldencode.p2j.directory.DirectoryCopy remove
Parameters
<target-xml> <target-path>
The meaning of the parameters is obvious.
Using clear
Use
clear to scan the specified branch of a directory file for all nodes of
a specified directory class, and then remove either the whole attribute
specified by its name or a matching value of the attribute.
How to run clear
java com.goldencode.p2j.directory.DirectoryCopy clear
Parameters
<target-xml> <target-path> node-class attr-name [attr-value]
The target-xml directory file gets scanned recursively starting from the target-path. All nodes of the node-class are inspected. If attr-value is not specified, the attribute attr-name is removed unconditionally regardless of its current value or values. If the attr-value
is specified, then only that value will be removed. If the attrbute is
multivalued, the other values remain untouched; otherwise the attribute
is removed.
Examples
To clear the protected="false" attribute from all user accounts in test-directory.xml, type:
java com.goldencode.p2j.directory.DirectoryCopy clear test-directory.xml /security/accounts/users user protected false
To clear account bogus from all ACLs of the same directory file, type:
java com.goldencode.p2j.directory.DirectoryCopy clear test-directory.xml /security/acl strings values bogus
To clear all user accounts from the alias attribute, type:
java com.goldencode.p2j.directory.DirectoryCopy clear test-directory.xml /security/accounts/users user alias
Using set
Use
set to add a value for an attribute or set the existing value to a
given one for all nodes of the specified directory class in a branch of
a directory file. When setting the existing atrribute, you can specify
the index at which the value will be set. This is a conditional
operation and it will be a no-op if there are less values than the
index implies (index n is valid if there are at least n values).
How to run set
java com.goldencode.p2j.directory.DirectoryCopy set
Parameters
<target-xml> <target-path> node-class attr-name attr-value [value-index]
The target-xml directory file gets scanned recursively starting from the target-path. All nodes of the node-class are inspected. If value-index is not specified, the attribute attr-name gets the attr-value added. If the value-index
is specified, then that value will be replaced if there are enough values. If the attrbute is
multivalued, the other values remain untouched.
Examples
To set the enabled="true" attribute for all process accounts, type:
java com.goldencode.p2j.directory.DirectoryCopy clear test-directory.xml /security/accounts/processes process enabled true
Copyright (c) 2005-2010, Golden Code
Development Corporation.
ALL RIGHTS RESERVED. Use is subject to license terms.