Security
This chapter describes the security mechanisms provided by the Content Platform Engine to secure the resources under its management against unauthorized access and to ensure that authorized users are given only sufficient access to carry out the tasks assigned to them, referred to as access control. In addition, it provides a series of recommendations for how best to employ those mechanisms to achieve the desired access control goals.
We discuss the following topics in the chapter:
5.1 Access control
Access control can be thought of as being the answer to the question of who is allowed to do what. There are two parts to that question, the who and the what, and correspondingly two phases of the overall access control process. The who part concerns identifying the entity, usually a person but also potentially an autonomous process, that is making a request of the Content Platform Engine. This is the authentication phase. The what part concerns deciding what level of access that entity needs to be given to the content objects targeted by the request. This is the authorization phase.
The Content Platform Engine supports standard mechanisms for authentication and a rich set of authorization features, as described in the remaining sections of this chapter.
5.2 Authentication
All requests submitted to the Content Platform Engine are subject to authentication, meaning that they must carry within them a verifiable (authentic) identity of the entity making the request. The Content Platform Engine itself does not define or implement authentication; rather, it delegates that to a standard service of the application server environment in which it executes - the Java Authentication and Authorization Service (JAAS).
The outcome of JAAS authentication is required to be an identity that the Content Platform Engine can resolve to a user in a directory service containing configured users and groups, from which a security context can be built and delivered into the authorization phase of access control. These elements of authentication are described in detail.
5.2.1 Use of JAAS
The traditional authentication model of a user providing a user ID and password is tried-and-true and has been in widespread use for decades. It is easy to implement and conceptually simple, but it does have some drawbacks:
Software systems built to rigidly expect user ID and password credentials are difficult to adapt in the face of other forms of credentials. Examples of other forms of credentials, which can be used with or without a password, are fingerprint scans and hardware security tokens. It is not possible for a software system built today to anticipate all of the forms of credentials that might be used in the future.
In an environment where users must interact with several applications, either the user must repeatedly enter credentials when crossing application boundaries, or the credentials must be passed from one application to another. The first choice represents a usability annoyance, and the second choice represents an information security hazard, because it gives more opportunities for the credentials to be discovered or exploited by an attacker.
For the first of these problems, the software industry has evolved to a model of pluggable authentication. Components for verifying different credential types can be developed independently of the framework into which they fit. The output of a pluggable authentication framework is often a token affirming that valid credentials were presented and verified. That is typically enough information for most authentication consumers, although some systems also provide information about the types of credentials that were presented.
Pluggable authentication also works toward solving the second problem, because the token produced can be more securely passed between applications than the raw credentials. There are more factors involved in single sign-on (SSO) solutions than pluggable authentication. There must be additional conventions or APIs for the applications to communicate with each other or at least with the SSO framework. A full discussion of SSO frameworks is beyond the scope of this book. Most application server vendors provide at least some SSO capabilities, and there are many vendor solutions available. For example, see Single Sign-on Solutions for IBM FileNet P8 Using IBM Tivoli and WebSphere Security Technology, SG24-7675.
In the Java environment, the pluggable authentication framework is JAAS. The Content Platform Engine fully delegates authentication to JAAS (but does not use JAAS for authorization purposes). Virtually all modern SSO solutions also work in concert with JAAS, so the Content Platform Engine server will almost always automatically participate in any SSO solution that might be employed.
The net outcome of JAAS authentication is that the Content Platform Engine server receives a Java artifact called a Subject, containing unimpeachable information concerning the authenticated user. The Content Platform Engine requires that this Subject contain identifying information for a user in a configured directory service.
5.2.2 Directory service users and groups
It is a requirement that organizations using P8 define the users of its systems in a directory service. P8 supports the following directory service types:
Microsoft Active Directory
Microsoft Active Directory Lightweight Directory Services (AD LDS)
Novell eDirectory
Oracle Internet Directory
Oracle Directory Server Enterprise Edition (formerly known as Sun Java System Directory Server)
CA Directory
IBM Tivoli Directory Server
In addition, support is provided for IBM WebSphere Virtual Member Manager (VMM), which is a directory service aggregator, capable of presenting a collection of directory services of heterogeneous types as a single unified virtual directory.
Alongside users, the directory service can (and usually will) define a number of groups. A group is a container of users and possibly of other groups, although not all directory services support nesting of groups. The contained users and groups are said to be members of the containing group. A group provides a convenient way to grant or deny access to the group members in a way that adapts automatically to changes to membership in the group.
Users and groups are referred to collectively as security principals and the authorization mechanisms described next are expressed exclusively in terms of security principals, mostly without regard for whether a particular principal is a user or group.
For each security principal, the directory service is required to provide an immutable identifier, which unambiguously resolves to that principal. This identifier is unique within that directory service and can be used to retrieve the directory service object having that ID. The form this unique identifier takes varies according to the directory service type and on configuration choices made by the owning organization. No matter what form it has in the underlying directory service, the Content Platform Engine transforms it to a universal format when it is presented in the API. This universal format is referred to as a security identifier (SID). SIDs are what the Content Platform Engine stores in its internal authorization data structures.
A security principal also has a distinguished name, a principal name, and a short name. The distinguished name (DN) is unique, and the principal name and short name can be also (particularly the former).
In addition to SIDs obtained from directory service principals, the Content Platform Engine acknowledges two special SID values, which have particular purposes described later. These SIDs have an associated predefined display name and do not resolve to a directory service object. They must be treated specially by API consumers, including administration tools.
There are two special SID values:
#AUTHENTICATED-USERS
This SID (often abbreviated as #A-U) notionally identifies a group, to which all valid users belong (but for which there is no concrete representation). #A-U is automatically added to the security context for any authenticated user. #A-U can appear as the grantee of an access control entry (ACE) in order to grant or deny access to all users (that is, to everyone).
#CREATOR-OWNER
This SID (#C-O), which is notionally of a user, plays no role in access checking (it does not appear in the security context). Its purpose is to act as an alias for the creator or current owner of an object during the application of default security, inheritable ACEs, and security templates. It is substituted by the actual creator or owner SID.
5.2.3 Security context
The security context (also sometimes referred to as the user access token) provides the identity information upon which authorization checks are based. It contains the SIDs of every security principal via which a calling user can be granted or denied access:
The SID of the authenticated requesting user
The SIDs of any groups of which the user is an immediate member
The SIDs of any groups within which those groups are nested, and so on (an exhaustive flattening of group nesting)
The SID for #AUTHENTICATED-USERS
The SID of the requesting user is determined by extracting the login name from the incoming JAAS Subject and searching the directory service to locate the corresponding user object. The group SID list (apart from #A-U) is obtained by further searches of the directory service.
Searching the directory service is a relatively expensive operation, so to avoid repeating it for each incoming request, the Content Platform Engine maintains a cache of fully constructed security contexts keyed by login name. Management of this cache, called the user token cache, is described in “User token cache” on page 189.
5.3 Authorization
Authorization is the second phase of access control, and is the phase in which a determination is made of the operations the caller is permitted to carry out on a particular object.
5.3.1 Access rights
Authorization determines a set of effective access rights that a caller is granted for a particular object. These in turn determine what operations can be performed on the object. Access rights are also the way grants and denials of access to a particular principal are expressed.
Concretely, access rights are represented by bit values, which are combined into an access mask - a 32-bit value in which distinct bit positions represent different access rights.
Some access rights have nearly universal meaning for all objects. For example, READ always implies permission to read an object and DELETE always implies permission to delete it. Others have meaning only for particular types of objects. Access rights that do not have meaning for a particular type of object can nevertheless appear in its effective access mask (this can occur for a variety of reasons) but play no role in determining what operations are permitted.
Table 5-1 gives a list of the access right names, a description of their meaning, and the types of objects to which they are applicable.
Table 5-1 Access rights
Right
Applies to
Description
READ
All types
Confers permission to retrieve the object.
WRITE
All types
Allows modification, and also (where relevant) the API Lock, Unlock, ChangeClass, and MoveContent actions.
LINK
Folder, Document, a few others
Grants permission to file into a folder or to annotate a document, and other similar things.
UNLINK
Folder
Grants permission to unfile from the folder by deleting a referential containment relationship.
MINOR_VERSION
Document
Allows checking out and checking in as a minor version.
MAJOR_VERSION
Document
Allows checking out and checking in as or promoting to be a major version.
CREATE_
INSTANCE
Class Definition
Permission to create an instance of the defined class, specify the class as the target of a ChangeClass API action, and for custom event classes, allows the class to be used in a RaiseEvent API action.
CREATE_CHILD
Domain, Folder, and Class Definition
Allows creation of new domain level (global configuration database (GCD)) objects, or subfolders of a folder, or subclasses of a class definition.
CHANGE_STATE
Document, Task
Allows document lifecycle methods and task state changes.
PUBLISH
Document
Permits the document to be submitted for publication.
DELETE
All types
Allows the object to be deleted or marked for deletion.
READ_ACL
All types
Permits read access to the Permissions list.
WRITE_ACL
All types
Allows modifications to the Permissions list and the API Freeze, ApplySecurityTemplate, and TakeFederatedOwnership actions.
WRITE_OWNER
All types
Allows ownership to be taken of the object.
CONNECT
Object Store
Allows access to objects in the object store for read.
STORE_
OBJECTS
Object Store
Permits new objects to be created in the object store.
MODIFY_
OBJECTS
Object Store
Allows objects in the object store to be modified.
REMOVE_
OBJECTS
Object Store
Allows objects in the object store to be deleted.
WRITE_
ANY_OWNER
Object Store
Permits any object in the object store to be retrieved and the Owner property to be modified.
ADD_MARKING
Marking
Allows the marking value to be applied to objects.
REMOVE_
MARKING
Marking
Allows the marking value to be removed from objects.
USE_MARKING
Marking
Permits objects having the marking value to be accessed without constraint of the marking.
PRIVILEGED_
WRITE
Object Store
Allows modification of certain properties that are normally treated as read-only for any object in the object store.
MODIFY_
RETENTION
Object Store
Permits the retention date to be modified for objects in the object store.
VIEW_
RECOVERABLE_OBJECTS
Object Store
Allows reading of objects that have been marked for deletion and thus rendered invisible to general users.
5.3.2 Security descriptor
The security descriptor (SD) is the primary mechanism through which access to an object is controlled, although it can be augmented by other means. The majority of independently persistable objects have a security descriptor, although some do not and so are subject to a different access check, as described later.
The SD is an internal construct maintained by the server and not exposed directly in the API. Instead, the two elements of the SD - the Owner and the Permissions list - are exposed as independently editable properties, combined in storage as the SD.
For objects stored in an object store (repository objects), the server implements a single-instance mechanism for SDs, so that if two objects have the same owner and permissions and therefore identical SDs, only one copy of the SD is stored, referenced by both objects. This, along with other details of how SDs are managed, makes them highly amenable to caching. The server maintains a security descriptor cache, which ensures that it is frequently possible to evaluate access to an object without a separate database access to retrieve the security descriptor.
Owner
The Owner field stores the identity (SID) of the security principal that is considered to “own” the object and is granted certain rights that cannot be revoked by the permissions list. The owner is usually a user and in the majority of cases will be the user who created the object, but there is nothing (other than the rules) which requires that to be the case. In particular, it is allowed for the owner to be a group (in which case, any member of that group is considered to own the object).
Every SD has a slot for the owner but it is not always populated. There are a couple of reasons why this can be the case:
For some objects, the concept of an owner is not considered meaningful, so no mechanism is provided to set or retrieve the Owner field and there is no default value initialized in it. This applies to all GCD objects and to a small subset of repository objects.
The owner might have been explicitly set to null (or defaulted so) deliberately so that no one has the additional access rights conferred by ownership.
In cases where there is an exposed mechanism to modify the Owner field (which for the majority of repository objects there is, through the Onwer property), doing so is subject to the following rules:
If the user has WRITE_ANY_OWNER access to the object store in which the object resides, the Owner can be set to any valid real SID or to null. (It might not be set to one of the special SIDs).
If the user has WRITE_OWNER access to the object in question (but not WRITE_ANY_OWNER access), the Owner might only be set to the user’s own SID (which is also known as “take ownership”) or to null.
Otherwise, the Owner cannot be modified.
Permission list
The permission list, referred to as the access control list (ACL) is a collection of permissions or access control entries (ACEs), each of which grants or denies a set of access rights to a security principal.
The order of the ACEs in the ACL has no particular significance, although when the ACL is exposed in the API as a collection of permission objects, it is ordered by source and type to match the order of precedence applied by the access check. The ACEs in the ACL are generally a mix of automatically assigned entries and entries applied “manually” through the API. See the Source field described next.
Each ACE has the following fields:
Grantee
The SID of a security principal to which the ACE grants or denies access rights, which can be either a real SID or one of the special SIDs. In the API, the SID is exposed as the name of the security principal (GranteeName property).
Type
Either Allow or Deny. An Allow ACE grants permissions, and a Deny ACE revokes them.
Access Mask
A bitmask of access rights granted or denied by this ACE.
Inheritable Depth
An integer value determining the extent to which this ACE can be inherited by security (grand)child objects.
Source
An automatically populated (read-only) enumerated type indicating the origin of the ACE:
 – Direct - indicates an ACE that either was added manually through the API or is a modified Default-sourced ACE.
 – Default - an ACE that was added by default (described in 5.3.3, “Default security descriptor” on page 161) and has not yet been modified.
 – Template - an ACE that was added as the result of applying a security template (described in 5.3.4, “Security templates” on page 161).
 – Parent - indicates an ACE that was inherited from a security parent (described in “Inheritance proxies” on page 165).
 – Proxy - indicates an ACE that originates from a full security proxy (described in “Full proxies” on page 164).
ACEs with a source of Template, Parent, or Proxy can neither be removed from the ACL nor modified in any fashion through the API. ACEs with source Direct or Default can be removed through the API and allow modifications to the Type, Access Mask, and Inheritable Depth fields (Grantee cannot be changed). If an ACE with source Default is modified, the source is updated to Direct. (Default is purely presentational; functionally, it is treated no differently than Direct). ACEs with source Parent do not form part of the stored security descriptor but will appear in the API representation of the effective ACL of an object. ACEs with the source Proxy are similar.
5.3.3 Default security descriptor
For repository object classes, a mechanism is provided to allow the administrator to define the ACL and Owner that will be set by default on a new instance of the class. This is accomplished through an additional security descriptor, the default instance SD, attached to the Class Definition for the class, and edited via the Default Instance Permissions and Default Instance Owner properties.
Although they are stored together in the default instance SD, the default ACL and default Owner are applied separately, depending on which (if either) of the Permissions and Owner properties were modified before saving the new object. For both, the default value is copied into the new object (with modifications described next). If the defaults are edited, the changes take effect only for subsequently created instances. There is no retrospective effect on instances that already exist.
The #CREATOR-OWNER SID is given special treatment when forming the instance security from the default:
If the default Owner is #C-O, the instance Owner is set to the SID of the user issuing the creation request (that is, the user SID from the security context).
If an ACE in the default ACL has grantee #C-O:
 – An ACE is added to the instance ACL with grantee set to the requesting user SID and inheritable depth zero, but all other fields are copied from the default ACE.
 – If the inheritable depth of the default ACE is non-zero, in addition, an exact copy (no grantee substitution) of the default ACE is added to the instance ACL.
ACEs with a grantee other than #C-O are copied exactly, with no modifications except that the source is set to be Default.
When a new object store is created, the default security descriptors for system classes are initialized based on two lists of security principals given in the object store creation request, the administrators and general users. The administrators are given powerful default rights over all objects, although the exact set of rights varies by object type. General users are given read-only access to the majority of objects. In all cases, the default owner is set to #C-O.
5.3.4 Security templates
The security template mechanism provides a way to automate updating of an object’s ACL as it transitions between versioning, document lifecycle, or application-defined states. The objective is to bring the object’s effective access rights to an appropriate state without “manual” intervention from the user initiating the state change.
Object model
A security template is essentially just an ACL tied to an identifier that determines the object state in which that template is applied.
Security templates come in three types with different packaging:
VersioningSecurityTemplates and ApplicationSecurityTemplates are fully fledged dependent objects exposing a TemplatePermissions collection (accessing the underlying template ACL), a GUID property ApplyStateID, which identifies the state to which the template is applicable, and a boolean property IsEnabled, which allows application of this template to be disabled. For a versioning template, the ApplyStateID property is constrained to one of four well-known values representing the four versioning states: Reservation, In Progress, Released, and Superseded. For an application template, it might have any (application-determined) value except those four well-known values.
A document lifecycle template is not a separate type of object. The template ACL is simply part of the DocumentState definition object (again, exposed as TemplatePermissions property), with the applicable state being implicitly that of the DocumentState object. A boolean property ApplyTemplatePermissions determines whether the template ACL is applicable during transition to this state.
A group of Versioning and Application security templates representing all that are applicable to a particular object or set of objects are collected together in a SecurityPolicy object, which is associated to the relevant objects via their SecurityPolicy property (which is often defaulted). Folders, documents, and customer objects (collectively Containables) have the SecurityPolicy property and participate in the template mechanism, although Versioning templates are only relevant for Documents.
DocumentState objects, with their attendant template ACLs, are collected together into a DocumentLifecyclePolicy, associated with relevant Document objects through their DocumentLifecyclePolicy property.
Both SecurityPolicy and DocumentLifecyclePolicy have an additional Boolean property PreserveDirectPermissions, which affects the manner in which templates from that policy object are applied.
Template application
A template is applied to an object under the following circumstances and subject to the noted constraints:
During a versioning state change (for example: Checkin, Promote, or Demote), if the document has a non-null value for its SecurityPolicy property and if that policy contains an enabled (IsEnabled is set to true) VersioningSecurityTemplate with ApplyStateID corresponding to the new versioning state. If those conditions are not met, the object’s ACL is not modified at all.
During a lifecycle state change, if the DocumentState for the new state has ApplyTemplatePermissions set to true. (If ApplyTemplatePermissions is false, no ACL change is made.)
During an ExecuteChanges operation that requests the ApplySecurityTemplate action, if the object has a non-null SecurityPolicy containing an enabled ApplicationSecurityTemplate with ApplyStateID equal to that given as the parameter to the ApplySecurityTemplate action. (An error is given if those conditions are not met.)
In all these cases, the template ACL is applied to the object’s stored ACL in the same way:
Any existing ACEs with source Template in the object’s ACL are removed.
In addition, if the policy object from which the template is drawn has PreserveDirectPermissions set to false, any ACE with source Default or Direct ACEs are also removed. The purpose is to allow the administrator to configure things so that the template completely controls access to the object without the possibility of being overridden by ACEs applied manually.
ACEs from the template ACL are copied into the target ACL. This is done the same way that default ACEs are applied (including the special treatment for #C-O ACEs) except that the copies are given source Template rather than Default.
It is permissible for the template ACL to be empty, in which case the last step is skipped (but only the last step).
Also, as described above, template ACEs are copied into the ACLs of the objects to which they are applied. Therefore, changes made to the template ACL have no effect on objects to which that template has already been applied.
5.3.5 Proxies
Proxying is a mechanism by which the security descriptor of one object (the proxied object) can be replaced by or augmented by the security descriptor of another object (the proxy object). Replacement is referred to as full proxying. Augmentation is referred to as inheritance or partial proxying. In both cases, the relationship between the proxied object and a proxy is represented by a singleton object-valued proxy-defining property of the proxied object. Setting a value for the property establishes (activates) proxying and removing the value severs the proxy relationship. The proxy-defining nature of a property is specified as its Property Definition, as either None (ordinary non-proxy defining property), Full, or Inheritance.
Proxying is transitive. That is, if object A has a proxy-defining property referring to object B, and B has a proxy-defining property referring to C, A’s security (as well as B’s) is influenced by that of C. The server prevents proxying loops (where a chain of proxy relationships leads back to the object from which one started), producing an error at the point the attempt is made to set the property that closes the loop.
Proxying is only available for repository classes; both the proxied and proxy objects must reside in an object store. Proxy-defining properties are often custom properties but there are a number of built-in system proxy-defining properties, in some cases with additional special behavior.
There is no restriction on proxying between different types of objects. For example, a Folder can act as a proxy for a Document or a Document for a Link. A consequence is it might be necessary to assign access rights to a proxy object that have no meaning for that type of object, in order for those rights to apply to proxied objects.
When a proxied object is retrieved or accessed for update, the server evaluates an effective security descriptor for the object by traversing each active proxy relationship, evaluating the effective security descriptor for each proxy object (a recursive process) and then applying those to replace or augment the stored security descriptor for the object. This process can involve fetching a number of additional objects, and to mitigate the cost, the server maintains a cache of recently fetched proxy objects. This object-security cache is particularly effective when retrieving a set of objects sharing the same proxy, as is typical for subfolders and relationship objects.
Full proxies
Assigning a value to a proxy-defining property of type Full results in the effective security descriptor (and active markings) of the proxied object being completely replaced by that of the proxy. In this case, the Permissions collection presented in the API for the proxied object will reflect exactly the ACEs in the effective security descriptor for the proxy, but with the special source type Proxy. The Permissions collection and the Owner property will both be read-only.
A class can define multiple proxy-defining properties of any mix of types, but among those of type Full only one can have a value at a time. (An attempt to set a value for a second full proxy-defining property will incur a “constraint-violated” error.) This places some limits on the usefulness of the feature, since if two applications want to full proxy a particular object in two ways, they can only do so cooperatively. No restriction is placed on setting or modifying inheritance proxy-defining properties when a full proxy is in effect, but those will have no influence on the effective security for the object.
When a full proxy is in effect, the object’s own stored security descriptor is rendered invisible and inaccessible for direct modification. However, if a security template is applied to a fully proxied object, the changes are made to the stored security descriptor in the normal way and will become visible and effective if the full proxy relationship is severed.
There are a few system properties that are full proxy-defining and in all cases these require a value. This reflects the fact that for the objects in question, there is no value in them having independently controllable security. As a consequence, none of these objects have the Permissions or Owner property. Table 5-2 lists the classes and properties to which this applies.
Table 5-2 Proxy classes and properties
Proxied class
Property defining full proxy
Proxy object class
Referential Containment Relationship
Tail
Folder
Component Relationship
Parent Component
Document
Hold Relationship
Hold
Hold
Sweep Relationship
Sweep
Policy Controlled Sweep
Job Sweep Result
Controlling Object
Sweep Job
Policy Sweep Result
Controlling Object
Sweep Policy
Thumbnail
Input Document
Document
Inheritance proxies
Security inheritance, like its genetic counterpart, is the passing of inheritable traits - in these cases, ACEs rather than genes - from a parent (the proxy) to a child (the proxied object). This analogy (and a certain amount of history) is the reason behind the use of the ACE source designation Parent. The analogy becomes a bit stretched when considering that a proxied object can have any number of “parents”, represented by values in an arbitrary number of inheritance type proxy-defining properties.
The effective security descriptor for an object with active inheritance proxy relationships is constructed by combining the stored SD with copies of the inheritable ACEs from the effective security descriptor of each proxy. ACEs from different proxies are combined on an equal footing and all are given source Parent, regardless of the source for the ACE from which the copy was made.
Inheritability of an ACE is determined by its Inheritable Depth setting, with the following rules:
A value of 0 means that the ACE is not inheritable and will not appear in the ACL of the proxied object.
A value of 1 indicates that the ACE will be inherited through one level of proxying only (the administrative UI refers to this as “Immediate children”). When such an ACE is copied to an inheriting object, the copy has Inheritable Depth 0 as a reflection of not inheriting further.
Other positive values similarly specify inheritance through a maximum number of levels, with the value being decremented as a copy is made for each inheritance step.
A value of -1 allows the ACE to be inherited to arbitrary depth, through any number of transitive proxy relationships.
Other negative values have a subtle effect, because these ACEs (which are referred to as inherit-only) are not considered when evaluating access for the object on which they appear. They can be inherited, with their inheritable depth being transformed as follows on the first inheritance step:
 – -2 becomes -1, thus it means “inherit-only to any depth”
 – -3 becomes 0, thus meaning “inherit-only to immediate children”
 – -4 becomes 1, -5 becomes 2, and so on.
As well as ACEs that are directly applied, those that appear in a default instance ACL or template ACL can also be marked as inheritable. Thus, for example, a security template can apply inheritable ACEs. A number of system classes have built-in inheritance proxy-defining properties, as shown in Table 5-3.
Table 5-3 System classes and their properties
Proxied class
Property defining inheritance proxy
Proxy object class
Folder
Parent
Folder
Document
Security Folder
Folder
Custom Object
Security Folder
Folder
Annotation
Annotated Object
Containable
Task
Coordinator
Containable
Class Definition
Superclass Definition
Class Definition
Recovery Item
Recovery Bin
Recovery Bin
Of particular note are the first three. A folder can inherit from its parent folder, and it from its parent, and so on, all the way to the root folder. Documents and custom objects can inherit from a folder, which is usually a folder in which the object is filed, although that is not required. Thus, by combining these two features, it is possible to manage security for the entire folder tree or for a subtree and all its contents from the root of that tree/subtree.
The properties with names in italics in Table 5-3 on page 166 all require a value. It appears impossible to have, for example, a folder that does not inherit from its parent. (In contrast, the security folder property does not require a value, so inheritance is always optional.) To overcome this deficiency, in three of the cases in Table 5-3 on page 166, a companion Boolean property is defined that disables this apparently required inheritance, shown in Table 5-4.
Table 5-4 Proxied class and inheritance
Proxied class
Inheritance disabling property
Folder
Inherit Parent Permissions
Task
Inherit Coordinator Permissions
Recovery Item
Inherit Recovery Bin Permissions
The default value for each of these properties is True, which means that inheritance is enabled. Setting the value to False disables inheritance. The effect applies solely to inheritance through the system property from the preceding table; any additional custom proxy-defining properties are unaffected.
 
Note: To date, no use case disables inheritance for class definitions or annotations.
5.3.6 Markings
The origin of this mechanism is the military and intelligence notion of document classifications and clearance levels:
Each person is assigned a clearance level indicating the maximum sensitivity of documents they are allowed to see.
Each document is labeled with a classification indicating its sensitivity.
A person is allowed to see only documents that are classified at or below their clearance level. For example, someone with Top Secret clearance level can see Top Secret, Secret, and Unclassified documents. Someone with only Secret clearance level cannot see Top Secret documents.
Furthermore, a person who is responsible for classifying new documents can do so only up to their own clearance level. Therefore, a person with only Secret clearance cannot classify a new document as Top Secret.
This approach is sometimes referred to as labeling or as mandatory access control (in contrast to the features described earlier that can be categorized as discretionary access control).
The Content Platform Engine manifestation of this type of access control is via marking-controlled properties. A marking-controlled property is in every respect an ordinary string property (single-valued or multi-valued), except that its permitted values (called markings) are drawn from an administratively defined set called a marking set. Its current values influence the access granted to the object in a manner that is detailed next.
This approach generalizes upon the basic classification/clearance mechanism in several dimensions:
An object can have multiple marking-controlled properties, drawn from multiple marking sets, combining in their influence on the access granted. For example, there might be a Classification property drawing from the Clearance Levels marking set, and a Project property, designating a project from the Projects marking set. The combined effect depends on the clearance levels assigned to different users and the projects on which they are permitted to work.
A marking set can be defined as imposing a hierarchical order of precedence on the markings defined within it (for example, in the clearance levels example, where Top Secret > Secret > Unclassified. Or, it can define the markings as unrelated (likely be the case in the projects example).
In the classification/clearance scheme, failing to have sufficiently high clearance with respect to a particular document acts as a blanket “off switch” - you are not allowed to see or in any way manipulate that document. In contrast, markings offer fine-grained control by way of an access mask that can revoke any or all of the rights granted to the object via its security descriptor.
The right to apply and remove a particular marking can be assigned independently of the right to use objects to which that marking has been applied. (Compare with the statement regarding “classifying new documents”.) Therefore, someone might, in principle, be given the right to classify objects as Top Secret even though that person only has clearance to see Secret documents. More likely, that person be allowed to designate objects as belonging to a particular project even though that person is not a member of that project team.
Rights to use, apply, or remove markings can be assigned to both individuals (users) and groups.
This approach operates in the following manner:
A MarkingSet object, defined at the domain level, has a name, a type of Hierarchical or List, and a list of dependent marking objects. In a hierarchical marking set, the marking objects must appear in order, highest precedence first. For a list type, the order has no significance.
Each marking object specifies a value (string) for the marking and defines the usage and access control effect of that marking value via the following fields:
 – An ACL (exposed in the API as a Permissions collection). The ACEs in this ACL grant or deny some combination of UseMarking, AddMarking, and RemoveMarking access rights. (Other bits can be set, but have no effect.) The ACL is evaluated during the access check on an object that either has this marking value applied to it, or to which an attempt is being made to apply it. That evaluation depends on the type of the marking set, as described in 5.3.7, “The access check” on page 169.
 – A constraint mask, a bitmask of access rights representing the rights that are revoked if a user with insufficient rights to the marking attempts to access an object to which that marking has been applied. (Therefore, markings only subtract rights, they do not add them.)
A custom PropertyDefinitionString can optionally reference a MarkingSet, turning the defined property into one that is controlled by that marking set. This establishes the marking values in that marking set as the permitted values for the property, and activates the access control effect of the marking value for instances of the class to which the defined property is added.
The access control effect of markings applied to an object acting as a full proxy also affect the proxied object, completely supplanting the effect of any markings on that object.
5.3.7 The access check
The access check is the process of evaluating the access control measures that apply to a particular object for a particular user in order to determine the set of access rights that are in effect for that object and user combination.
The following sections describe the circumstances and manner in which the access check is carried out.
When and how
All independent objects are subject to an access check during retrieval and update. In most cases, that access check is based on evaluating the effective access granted by the object’s effective security descriptor and markings. However, a number of object types diverge from this general rule:
The overall effective access for an object store is determined by augmenting that resulting from evaluating the object store’s own ACL with additional rights determined from the Domain’s ACL (Table 5-5).
Table 5-5 Domain ACL
Domain ACL grants
Added to object store effective access
READ
READ + READ_ACL
WRITE
WRITE + READ_ACL + WRITE_ACL
DELETE
DELETE
The effective access to other independent GCD objects (besides object stores) is determined by evaluating the Domain’s ACL. (No other GCD objects have their own ACL.)
Access to class descriptions, for which READ is the only relevant right, is controlled by the scope from which the class description is drawn. To access a class description from an object store scope requires CONNECT rights to that object store. To access a class description from domain scope requires READ rights to that domain.
For all repository objects, the result of the ACL check is augmented with the WRITE_OWNER right if the user has WRITE_ANY_OWNER access to the object store in which the object resides.
Queue Items (SecurityPropagation/Event/DocumentClassification), Index Requests, Replication Journal Entries, and Sweep Queue Entries do not have instance security. Instead, access to these types of objects is determined by evaluating the default instance ACL for the object’s class.
There are no access checks for realm, user, and group objects. (It is sufficient for the user to be authenticated in order to be able to see these objects, which are immutable.)
Object retrieval
This form of access check takes place during a GetObjects operation (or equivalent) and during the refresh phase of an ExecuteChanges operation, with the purpose of determining whether the caller is allowed to see the object and whether it needs to form part of the response.
For GCD objects and ClassDescriptions, being allowed to see the object is simply based on the presence of the READ access right in the effective access for the object, evaluated from an ACL as described next.
For repository objects, the access check is in two parts, both of which must be satisfied:
The effective access evaluated from the ACL of the object store in which the object resides must include CONNECT right.
The effective access evaluated from the object’s effective security descriptor and markings must include either READ or WRITE_OWNER permission (or both). The rationale for the inclusion of the latter is that it allows the owner of an object or someone with WRITE_ANY_OWNER access to the object store to retrieve the object regardless of the state of the ACL. Therefore, it provides an escape mechanism by which the ACL can be repaired if it has been put into a state that grants no access to anyone.
In the event that the access check fails, the intent is that the system behaves exactly as though the object did not exist. Therefore, the following actions occur:
If the object is being retrieved directly, a “not found” error is returned.
If the object forms part of a collection, it is simply dropped from that collection.
If the object will be returned as the value of a singleton property, a null value is substituted.
If the access check succeeds, the object is returned with values for all the properties dictated by the property filter included, except for these properties:
Any values that are independently persistable objects reached through recursion are subject to an independent access check and handling as described earlier.
The Permissions collection and the Owner property are returned as empty/null unless the effective access mask that was used for the primary access check also includes either READ_ACL, WRITE_ACL, or WRITE_OWNER.
If the property filter demands that content be returned, an additional check is made for VIEW_CONTENT access in the primary effective access mask.
ExecuteChanges
ExecuteChanges is the name of the underlying server request type through which creation, updates, and deletions are performed.
Access checking during ExecuteChanges is for determining whether the creation, update, or deletion operations in the batch are allowed. Each object in the batch is access-checked individually, but any failure causes the entire batch to be abandoned (rolled back).
For GCD objects, the access check operates on the effective access determined from the Domain’s ACL, or in the case of an object store, the combination of the Domain and object store ACLs. The following checks are made:
 – When creating an object, the effective access mask must include CREATE_CHILD right.
 – When updating an object, WRITE right is required, and in addition, if the object has an ACL and that ACL is modified, WRITE_ACL right.
 – Deleting an object requires DELETE right.
For repository objects, the checking is more complicated and differs depending on the basic operation performed - create, update, or delete:
Create
The access check is in three parts:
 – First, the effective access to the object store in which the object is to be created must include STORE_OBJECTS right.
 – Second, the effective access evaluated from the ACL of the ClassDefinition for the class of object being created must grant CREATE_INSTANCE right.
 – Finally, a provisional security descriptor is formed for the object from the default defined by the object’s class, then the effective access granted by that SD is combined with WRITE, MINOR_VERSION, and MAJOR_VERSION to form an overall effective access mask that is fed into a property access check for any properties for which values are given in the creation request.
Update
Again, the access check is in three parts:
 – First, the effective access to the object store in which the object resides must include MODIFY_OBJECTS right.
 – Second, the effective access evaluated from the object itself is checked for specific rights according to the actions requested, as described in Table 5-1 on page 156:
Special case: Checkout creates a reservation document and is subject to the normal creation checks for that object, in addition to the checks applied to the checked-out document.
Special case: InstallAddOn is an action (treated as an update) on an ObjectStore and is therefore subject to the previously described access checking rules for GCD objects. However, in addition, all the operations performed as part of installing the add-on (typically creating classes and properties) are subject to normal access checks, as though they were performed through the API directly.
 – Last, the effective access of the object is fed into a property access check. A simple Update action involves no second phase access check, only the property access check.
Delete
The access check is in two parts:
 – First, the effective access to the object store in which the object is to be created must include REMOVE_OBJECTS right.
 – Last, the effective access for the object itself must include DELETE right.
Special case: The deletion of the system class, ReferentialContainmentRelationship (RCR), is permitted if the effective access (which is evaluated from the tail folder) includes either DELETE or UNLINK right.
Special case: The deletion of a reservation Document (also known as a “cancel checkout”) is permitted if its effective access includes either DELETE or MAJOR_VERSION or MINOR_VERSION right.
Handling of compound actions
A change request can apply multiple actions to a single object (for example, Create + Checkin or Checkout + Lock), which is referred to as a compound action.
Each action in a compound action is subject to separate access checking according to the rules stated. However, the object’s individual effective access rights are evaluated only once, prior to the first action (that is, before any changes are made). Those effective access rights are used in the access check for all the subsequent actions. Thus, security changes made by one action do not affect the access check for subsequent actions (because the effective access is not reevaluated to take account of those changes).
Property access check
The third phase of a creation or update operation access check validates that the caller is allowed to set or modify properties presented in the request (the “dirty” properties). The input to this check is the effective access mask determined during the second phase, and that is compared with the metadata-defined or implicit modification access required (MAR) for the property. The rule is that the operation is permitted if all the rights present in the MAR are also present in the effective access mask. This rule must be satisfied for every newly set or modified property; otherwise, the whole operation will fail.
For most system properties, there is no explicitly defined MAR, and for those system properties, an implicit mask consisting of just WRITE right is used. For most properties, setting or modifying them simply requires WRITE permission to the object to which the properties belong. A number of system properties do however have an explicit MAR (Table 5-6).
Table 5-6 Properties that explicitly define modification access
Property
Modification access required
Permissions
WRITE_ACL
Owner
WRITE_OWNER
ReplicationGroup
WRITE_ACL
SecurityPolicy
WRITE_ACL
CmRetentionDate
WRITE_ACL
SecurityFolder
WRITE_ACL
DefaultRetentionPeriod
WRITE_ACL
Inherit Parent Permissions
WRITE_ACL
Inherit Coordinator Permissions
WRITE_ACL
Inherit Recovery Item Permissions
WRITE_ACL
Special rules apply to setting Owner, depending on how the WRITE_OWNER effective access comes about, as described in “Owner” on page 159.
The MAR for custom properties can be defined by the property definition author, with again WRITE being the de facto value. Proxy-defining properties need to be given a MAR of WRITE_ACL because modifying the property value affects the effective ACL for the object.
In addition to the MAR check, certain property types are subject to further checks:
Singleton object-valued properties (OVP)
Setting a value for a singleton OVP is subject to an additional access check on the object specified as the value. This check evaluates the caller’s effective access to the specified object (as determined by that object’s effective ACL and markings) and tests it against the metadata-defined or implicit target access required (TAR) for the property, allowing the operation to proceed if all the rights present in the TAR are also present in the effective access. The default (implicit) TAR is READ, but many system properties have more stringent requirements.
For example, the TAR for the RCR.Tail is LINK. Therefore, it is necessary to have LINK permission to a folder in order to file things into it.
As with the MAR, for custom properties, the TAR is controlled by the property definition author.
There is no additional access check for unsetting (nullifying) a singleton OVP. Only the MAR check applies.
Marking-controlled properties
Values placed into or removed from a marking-controlled property (MCP) are subject to access checks on the marking objects corresponding to those values:
 – If setting a value of a singleton MCP where previously there was no value, the caller must have ADD_MARKING effective access to the corresponding marking object.
 – If nullifying a singleton MCP, which previously had a value, the caller must have REMOVE_MARKING access to the marking object.
 – Changing the value of a singleton MCP from one non-null value to another non-null value is treated as a remove followed by an add. Therefore, it requires REMOVE_MARKING access to the initial value’s marking and ADD_MARKING access to the new value’s marking.
 – For updates to a list MCP, the server computes the net deltas - additions and removals - and demands ADD_MARKING or REMOVE_MARKING access to the corresponding marking objects.
The manner in which the effective access to a marking is determined is described in “Markings check” on page 177.
Search execution
Search applies an access check to any object contributing columns to a result row. (In a joined query, each From class is considered as contributing to the row, even if no properties of that class appear in the SELECT list.) This access check is the same as for object retrieval - READ or WRITE_OWNER rights are required - except that if the query includes a CBR clause, VIEW_CONTENT is also required. A failure is handled in the same way that it is handled for collection retrieval, that is, the row is simply dropped from the result set.
The access check is accomplished by adding columns to the SELECT list specified by the caller as needed to determine the security descriptor and the values of any proxy-defining and marking-controlled properties for each contributing object, from which can be determined the effective access to the object.
Effective access
Key is the calculation of effective access to an object, determined from the effective security descriptor and markings applicable to the object. The overall effective access is, in general, the result of combining three bitmasks, produced by evaluation of the owner, ACL, and markings against the security context of the caller, in the following way:
effective-mask = (owner-mask | ACL-mask) & ~markings-constraint-mask
The owner mask and ACL mask are combined, and then any rights constrained by markings are subtracted. Note a couple of key points:
Denial ACEs in the ACL do not (cannot) revoke rights granted through ownership.
Markings do not grant additional rights, they only revoke rights, and that revocation is absolute (cannot be overcome via the ACL or ownership).
For an object without markings, the markings check is skipped and zero is used for markings-constraint-mask.
Owner check
Subject to the following caveat, the Owner check returns a bitmask of either all zeros or of READ_ACL+WRITE_ACL+WRITE_OWNER, depending on whether the caller is determined to be an owner of the object. That determination is made by comparing the Owner SID from the security descriptor with the SIDs in the security context. If there is a match with any of those SIDs (user or group), the caller is an owner and receives the non-zero owner mask. If there is no match (or if the Owner SID is null), the owner mask is returned as zero.
The caveat is that when evaluating access to a repository object, possession of the WRITE_ANY_OWNER right to the object store in which that object resides causes WRITE_OWNER right to be added to the owner mask. (This obviously only has impact if zero is otherwise returned.)
ACL check
The ACL evaluation phase combines the access masks from the ACEs in the ACL according to the following rules:
Only ACEs whose grantee SID is present among the SIDs in the security context are considered, while all others are ignored. The only relevant ACEs are those whose grantee is the calling user or a group of which that user is a member.
Inherit-only ACEs are ignored.
ACEs with source Direct/Default take precedence over those with source Template, which in turn take precedence over those with source Parent.
Within each source category (so as a second-level order of precedence), Deny ACEs (which remove rights) take priority over Allow ACEs (which add rights).
So, logically, we calculate six separate bitmasks, one for each (source, type) permutation (treating Default and Direct as one). Each of those bitmasks is the result of ORing together the access masks from the all relevant ACEs belonging to that permutation (or is zero if there are no such ACEs). The six bitmasks are then combined according to the following algorithm:
ACL-mask = parent-allow-mask
ACL-mask = ACL-mask & ~parent-deny-mask
ACL-mask = ACL-mask | template-allow-mask
ACL-mask = ACL-mask & ~template-deny-mask
ACL-mask = ACL-mask | direct-allow-mask
ACL-mask = ACL-mask & ~direct-deny-mask
An important point is that denials (Deny ACEs) override grants (Allow ACEs) with an equal or lower precedence source (for example: Template Deny overrides Template or Parent Allow) but are themselves overridden by grants with a higher precedence source (example: Direct).
Markings check
This phase returns a bitmask of rights that are unconditionally revoked from the caller - the constraint mask - as a result of insufficient access to markings applied to the object. This is determined by forming a list of the marking objects corresponding to all the values of all marking-controlled properties of the object, evaluating the caller’s effective ask to each of those markings, and ORing together the constraint masks of any for which the effective access fails to include USE_MARKING right.
The key part is how effective access to a marking object is evaluated, which has relevance both here and to the additional property access check for marking-controlled properties described in “Property access check” on page 173. This evaluation varies according to the type of marking set to which the marking belongs.
List
In this type of marking set, the markings are independent of each other. The evaluation of effective access simply relies upon the ACL of the individual marking, which is evaluated according to the rules given in “ACL check” on page 176 and simplified because a marking ACL never includes anything but direct ACEs.
Hierarchical
In this case, the evaluation is more complex because it must include the order of precedence of the markings in the MarkingSet and the following rules:
Granting rights to a higher precedence marking implicitly grants the same rights to all lower precedence markings. For example, someone given Top Secret clearance is inherently able to access Secret and Unclassified documents.
Denying rights to a lower precedence marking must also deny those rights to all higher precedence markings. For example, if someone is not allowed to see Secret documents, clearly they also are not permitted to see Top Secret documents.
Therefore, evaluation of the effective access to a marking in a hierarchical MarkingSet needs to include not only all the ACEs of the ACL on that marking itself, but also the Allow ACEs from any higher precedence markings and the Deny ACEs from any lower precedence markings. Although it is not implemented this way, think of this logically as forming a composite ACL from those three components and then performing a normal evaluation of that composite ACL.
5.3.8 Auditing
In some environments, the assurance that the Content Platform Engine will only allow properly authorized operations might not be sufficient. It might be necessary for legal or other reasons to have an actual record of attempts to carry out unauthorized actions or even of permitted operations.
This is the purpose of the auditing feature, which allows an administrator to enable recording of either failed operations, successful operations, or both. This can be done with a considerable amount of selectivity:
Auditing is enabled by class. For example, it can be turned on for some perhaps more sensitive classes but left disabled for others of lesser sensitivity.
Within a class, auditing can be controlled by operation. For example, it can be enabled for deletions but not for anything else.
For each enabled operation, the administrator can select whether a record is made of attempts to perform that operation that failed due to insufficient access, of successful operations, or both.
Finally, a filter expression can optionally be specified that is applied to an object that is a candidate for auditing based on the preceding settings. Only if the object satisfies the filter condition will an audit record be written. This allows auditing to be narrowed to objects having only certain property values or to where certain properties are modified.
There is no mechanism for determining auditing based on the identity of the user.
Operations to be enabled for auditing are expressed in terms of events triggered by those operations, and audit records take the form of stored Event objects of various classes. These are the same objects that participate in the Content Platform Engine Events and Subscriptions feature. For a full description of the Event classes and the corresponding operations, see the following document:
In all cases, the audit record includes the date and time of the operation and the identity of the user that initiated it. For everything apart from Query Event, the record also includes the identity of the object on which the operation was performed. (A query is of a class, not of any one object.) In addition, for all events other than Query Event, Get Object Event, and Get Content Event, the administrator can elect for the audit record to contain property values from the object at the time of the operation. The record can be either a complete snapshot of the object’s state (either before or after the update or both) or in the form of selected properties copied (“audited as”) from the source object into custom properties defined in the event class.
Audit records are independent of the object for which they record an operation and, in particular, they are not automatically deleted when the source object is deleted. An automatic disposal mechanism is however provided, through an Audit Disposition Policy, which periodically scans the audit records deleting those that satisfy a filter condition, often based on date.
5.4 Security best practices
The richness of the access control mechanisms described in the previous section can be both a blessing and a curse. The richness means that a wide variety of security requirements can be addressed but it is not always obvious how best to meet those requirements. This section will give some guidance on that issue.
5.4.1 Physical security measures
The Content Platform Engine rigorously applies the access controls that have been defined to any requests that are received via its APIs. But those controls are only effective to protect the resources managed by the Content Platform Engine if the only way those resources can be accessed is through the APIs. If users are able to bypass the API and access resources directly, the Content Platform Engine access controls are completely compromised. Therefore, it is essential that an organization have in place “physical” security measures to prevent such direct access.
A detailed examination of this topic is beyond the scope of this publication, but a brief list of areas for consideration follows. These are all common issues that arise in any distributed system:
Databases hosting the GCD and object stores must be secured against unauthorized access. Generally, access is restricted to database administrators (who ideally are not P8 users) and the identities used by the Content Platform Engine itself to access the databases (as defined in the application server data sources configuration).
The server host systems and the application server instances on those systems in which the Content Platform Engine is running need strictly controlled access, so that only appropriate people can stop and start the Content Platform Engine and be able to modify the application server configuration.
File systems used for content storage need controls in place to prevent access by anyone but the operating system identities under which Content Platform Engine server instances execute and those with responsibility for maintenance operations, such as backup. File systems used for text index storage must be protected similarly, but also allow access by the CSS server processes.
Fixed devices used for content storage need to give access only to the identity configured for use by the Content Platform Engine (in the Fixed Content Device object) and to device administrators.
The network hosting the Content Platform Engine and CSS servers, databases, and storage devices need to be secured against snooping and attack.
 
Important: This area is critical for any network connections over which raw authentication credentials (such as passwords) are transmitted. We strongly advise that you configure these connections to use Transport Layer Security (TLS)/Secure Sockets Layer (SSL) or equivalent.
As a further measure to prevent direct access to content, the content encryption feature can be enabled for selected storage areas. This feature ensures that even if access controls on the storage device are bypassed, the content will be unreadable.
Compatible disk sector encryption technology can also be used to provide similar protection for the GCD and object store databases as well as for content.
5.4.2 Directory service configuration
Configuring the directory service is one of the most important first steps in setting up a P8 system. A particularly critical aspect is choosing which attribute of user and group objects serves as the unique identifier from which SIDs are constructed. This decision cannot easily be changed after SIDs are stored in ACLs (which happens as soon as the domain is fully initialized), so it is essential to get it right first time.
The default unique identifier attribute for each of the supported directory services is shown in Table 5-7.
Table 5-7 Default unique identifier attributes by directory service type
Directory service
Unique attribute
Microsoft Active Directory and AD LDS
objectSid
Novell eDirectory
guID
Oracle Internet Directory
orclguid
Oracle Directory Server Enterprise Edition
nsuniqueid
CA Directory
cn
IBM Tivoli Directory Server
ibm-entryuuid
Whatever attribute is chosen needs to be either enforced as read-only by the directory service or treated as read-only by the administrators of the directory service. A change in the value for a particular user or group invalidates any stored SIDs referring to that principal and likely results in that principal losing any access they might have been granted.
With the exception of the cn attribute employed for CA Directory, all of the defaults listed in Table 5-7 have the required characteristics of uniqueness and immutability guaranteed by the hosting directory service. We strongly advise that you use them. Alternatives that are merely unique (such as distinguished name) should only be used if procedures are in place to prevent changes.
5.4.3 Defining the security approach
The key to defining an effective approach to access control is to make security considerations an integral part of defining the general data model. Identify the document, folder, and other classes that are to be used, and also in what ways they are to be used and therefore what access rights will need to be granted to them to allow their purposes to be served.
In developing this model, often different areas of responsibility are identified with correspondingly different access rights needed to act on those responsibilities. For example, being responsible for creating and editing a particular type of document requires one set of access rights but being responsible for approving it for publication requires a different set. It is important that the security model clearly identifies these distinctions, and in refining this aspect of the model, you need to remember a couple of general principles.
Avoid overlapping responsibilities. Overlapping responsibilities creates opportunities for accidental violation of intended security controls and for malfeasance. Continuing the previous example, it is likely undesirable for the same individuals with responsibility for authoring documents to also be responsible for approving them for publication.
Grant only the privileges (for example, access rights) that are necessary for a particular task and no more. For example, if a particular task requires only viewing the content of a document, do not give permission to modify or delete the document. Again, the objective is to prevent accidental or malicious violation of the intended security controls. Although this might seem obvious, it is not necessarily always straightforward to apply this principle successfully.
In addition to identifying the responsibilities and corresponding access rights for objects themselves, consider for the model:
Property updates: Under what circumstances can it be possible to modify a particular property? This will determine the appropriate value for the modification access rights defined for the property. (For proxy-defining properties, always include WRITE_ACL.)
Relationships between objects: When is it possible to establish a relationship between two objects by setting an object-valued property of one to reference the other? This will dictate the target access required for the property.
Requirements for commonality of access between related objects: For example, object A is related to object B and the same individuals need to have similar access rights to both. These are potential opportunities for the use of proxying.
Having fully developed the security model, the next task is to determine how that can be expressed concretely in terms of security descriptors, templates, proxy relationships, and markings. Determine how to define the procedures for identifying the individuals to be given particular responsibilities and for assigning them the rights required to carry out those responsibilities. Design how the security model will be implemented.
Two elements of a successful implementation are important:
Wherever possible grant rights to groups rather than to individual users.
To fully exploit this method means creating a group corresponding to each area of responsibility or distinct set of access rights identified in the model, making responsible individuals members of the group, and then assigning the group as the grantee in ACEs.
Make the maximum use of defaults.
Some applications can set and update the security properties on individual objects, either based on their own logic or input from users. However, these are almost always adjustments to the defaults defined for the object class. By far, the most common case is that the class defaults are allowed to take effect without modification.
It is therefore essential that class defaults are defined appropriately. This does not mean only the default permissions and owner. If security templates are to be used through security policies or document lifecycles, defaults might need to be defined for the properties that reference those objects. Similarly, if markings are to be used, defining default values for marking-controlled properties can be desirable. It can even be appropriate to define default values for proxy-defining properties, although that is less likely.
In addition, it is advisable to keep the number of ACEs in any ACL reasonably small (fewer than ten) since this results in more economical storage and makes it easier for administrators to understand the overall effect of the ACL.
Supporting trusted applications
P8 is often used as a “back end” by “middle-tier” applications that offer a higher level service to their clients, making calls to P8 on behalf of those clients. Such an application will typically employ its own authentication and authorization techniques, but the calls it makes to P8 are nevertheless subject to P8’s own access controls. It is therefore preferred that the application’s authentication be aligned with that of P8 (typically by use of JAAS). It is typically preferred that the calls to P8 be made in the context of the end client, so that P8 access controls can be expressed in terms of those users.
However, that is not always possible. It can be necessary in some cases for the application to make calls to P8 under an identity that is distinct from that of any client it is serving and that has sufficient access to objects in P8 to enable it to carry out any operation on behalf of any of its users.
This is a somewhat tricky proposition, since it implies that the usual P8 access controls must be relaxed for the identity under which the application makes calls, and so further implies that the P8 administrator must trust the application to prevent its users from obtaining access that is not allowed if making requests directly to P8. This is not something to be taken lightly.
Assuming that such trust exists, the following approach for supporting such applications is preferred:
A separate directory service user needs to be defined exclusively for use by the one application. It is completely inappropriate for the application to call P8 using an identity that can also be used by direct users or by another trusted application.
The application needs to be configured to perform a JAAS login as that user. The configuration settings containing the credentials for the login need to be stored securely where only the application can get at them.
The user (directly, not via any group) needs to be granted the required access in the default permissions for any class of which instances will be acted upon by the application.
If need for the application ceases, the directory service user needs to be deleted, thus ensuring no possibility that the elevated rights granted to the application can be taken over by anyone or anything.
5.4.4 Planning for evolution
Access control requirements will inevitably change over time. Individuals can join the organization, others can leave, responsibilities can be reassigned, new applications can be introduced, and so on. Being able to evolve the security implementation to meet these new/changed requirements is therefore essential. If the wrong approach is taken in the initial implementation, accommodating such evolution can be impossible or at best extremely time-consuming.
The key to making such evolution possible in relatively straightforward fashion is to heed the advice given earlier to grant access to groups rather than to individual users. This is particularly critical for the lists of administrators and general users given at object store creation. It is almost as important for objects within an object store (although for those there is another technique described in 5.4.5, “Role-based access control using inheritance” on page 186 that can be used to some extent to overcome the same issues).
To see why not following this advice can cause immense problems, consider a couple of examples:
Example 1
User X has sole responsibility for a particular task and is granted rights to perform that task directly (not via a group membership) in ACEs applied to various objects. Now, X leaves the organization and is replaced by Y.
In order to bring about this change, someone with sufficient privilege (specifically, an object store administrator) must locate all the objects with ACEs in which X appears and replace those ACEs with ones granting Y the same rights.
There is no mechanism for querying for objects based on grantees in the ACL. (The internal stored format of the security descriptor makes this impossible.) In limited circumstances, it can be possible to identify the relevant objects in some other way, based on queryable criteria. For example, it can be known that all instances of a particular class are affected. However, even if that is possible, the query can yield a large set of objects, making the process of updating the permissions of each lengthy. And more typically, there will be no such narrowing query and the administrator will have no option but to scan through all documents and folders, examining the permissions of each to locate those needing to be updated.
The most egregious case is where the task for which X is solely responsible is that of object store administrator, for example, X was the sole principal given in the administrators list when the object store was created. In this case, X was placed in the default instance ACEs for every class defined in the object store. Those ACEs likely have been copied into every instance created of all those classes. Fixing that is, practically speaking, impossible.
Example 2
User A currently has sole responsibility for a particular task, but now user B joins the department and is to share responsibility with A for that task. As in the previous example, this requires locating and updating all the objects with ACEs in which A appears, adding ACEs granting the same access to B.
This is largely the same as example 1 except that there is a slight possibility of it being made easier by the participation of A, who can (a) be aware of all the objects involved, and (b) can be able to undertake the permissions updates without the intervention of an administrator, if granted WRITE_ACL permission by the ACEs on those objects.
However, it is likely equally as intractable as the first example.
Compare this with how the changes can be accommodated if groups had been used to assign rights to X and A. In each case, it is a matter of adding Y or B to the group (and in the first example, removing X).
5.4.5 Role-based access control using inheritance
The notion of roles in security access authorization is not new. The motivating idea is to be able to describe access policies in terms of generic functional roles rather than administering user access individually. Roles can be thought as a formalization of the idea of areas of responsibility discussed earlier. Therefore, in the example given previously, one might have an Author role and an Approver role.
A basic role-based access control (RBAC) model typically consists of three elements:
A role definition, specifying a set of access rights associated with the role
A member list for the role, identifying the security principals who are authorized to act in that role
A set of objects to which that role applies
The overall effect of these three elements is that the members of the role are granted the access rights defined by the role for the objects to which the role applies.
Described in this fashion, it is apparent that roles have much in common with groups and offer similar evolutionary benefits. So why not just use groups? One can, in theory, define a directory group for every interesting role and assign users to the appropriate group or groups. In practice, most enterprises are not happy with that approach for one or more of the following reasons:
In large enterprises, the directory is administered by a different group of people than those directly involved with applications.
The dominant pattern for directory groups is one that largely reflects the hierarchical organizational structure of the enterprise. That does not align with roles concepts well since roles tend to cut across organizational boundaries.
Many applications depend on directory information about individuals, and that tends to lead to a conservative policy about directory changes. Frequent updates, for example, to account for temporary role changes, are specifically avoided.
So, using roles defined “locally” for a particular application provides more flexibility than complete reliance on directory service groups.
P8 does not provide a built-in RBAC mechanism. However, inheritance proxies can be used to achieve much the same effect.
The following technote provides a full explanation of various ways this can be done:
The basic concept of using inheritance proxy as described in the technote is as follows:
An object serves as the role. Inheritable ACEs are placed in the ACL of the object, one per member of the role, with the same access mask in each granting the access rights defined by the role.
For each object class to which the role is applicable, an inheritance proxy-defining property is added, with required class that of the role object. Applying the role to an instance of the class is then simply a matter of setting the proxy-defining property to refer to the role object.
With this approach, adding and removing members for the role are achieved by updating the ACL of the role object. Inheritance takes care of ensuring the effect extends to all the objects to which the role has been applied.
5.4.6 Using markings
The important thing to consider about markings is that they only restrict access, they do not extend it. Therefore, they must be used in conjunction with an effective security descriptor that grants the maximum access anyone needs to have to the marked objects. This is an effective technique when used in the manner of the Projects example given earlier and is an alternative to creating a group for each project or using a role-like scheme. (Changing the membership of the group or role is replaced by editing the ACL for the markings.)
The server holds marking sets in memory (including each marking with the associated security descriptor). A large number of marking sets or markings, or markings with complex ACLs, can require an increase in the amount of memory assigned to the Content Platform Engine server.
Marking sets of list type can contain a large number of markings without performance cost, so using them as in the projects example can scale up to many projects without problems (memory requirements notwithstanding).
However, hierarchical marking sets become increasingly expensive as the number of markings in the set grows, due to the need to traverse up and down the hierarchy when evaluating the effective access to any particular marking. Therefore, they are best suited to uses similar to the classification example given previously, where there are only relatively few markings in the set.
5.4.7 Effective use of auditing
Auditing is a useful tool for detecting security intrusion attempts (operations that are refused on access control grounds) or for recording a history of successfully performed sensitive operations. However, auditing is relatively expensive, both in terms of the cost of the additional processing and I/O to write the audit records and of the storage cost, especially when the option to record a complete snapshot of the object state is exercised. Therefore, it needs to be used judiciously. Consider these guidelines:
Usually only certain objects will be of interest, for example, documents with confidential content, so the auditing configuration needs to be narrowed as much as possible to be enabled for just those objects. Often, this is a matter of selectively enabling only certain classes, but in some cases, it can be necessary to use the filtering mechanism to distinguish between interesting and uninteresting objects.
For those objects, only particular operations are likely to be of interest, such as viewing the confidential content or attempting to delete critical folders. Therefore, the set of events for which auditing is enabled needs to be chosen carefully. API operations, such as Checkout and Checkin, generate a specific event and an Update Event. They will be audited if either Update Event or the specific event (in this example: Checkin Event) is enabled. In consequence, if Update Event is enabled, all API operations will be audited, which can be more than necessary.
A complete snapshot of the audited object state consumes several kilobytes of database large object (LOB) storage, and double that if both before and after states are recorded for updates. This can quickly accumulate to consume a large proportion of the available LOB storage if care is not taken. A more economical approach is to use the “audit as” mechanism to capture a limited set of properties from the audited object.
A disposition policy should be defined to remove audit records as quickly as possible after they are no longer needed. For example, if auditing is being used for intrusion detection, a potential approach is to regularly generate a report from the audit log and to define a policy that deletes records that are old enough that they are bound to have been included in a report.
5.4.8 Cache management
Several caches were described earlier that are used to improve access control performance. The default configuration of these caches is adequate for many situations, but in some cases, it can be necessary to adjust the configuration of one or more to obtain optimal performance or to tune server memory usage.
For each of these caches, the server maintains operational statistics that are extremely useful as aids to tuning. These statistics can be viewed in the IBM System Dashboard. Each Content Platform Engine server instance has separate caches, so in a multiple server configuration, the statistics for each need to be considered.
User token cache
The user token cache retains recently evaluated security contexts in memory. The size of a security context varies according to the number of groups each user is a member of. Therefore, the overall amount of memory consumed by the user token cache varies by that and by the maximum size configured for the cache. As the cache grows, the server discards the least recently used (LRU) entries to ensure that the maximum size is not exceeded. (This is referred to as an LRU policy and is common to all the caches discussed here.) So, the ideal size for the cache is around the number of users actively issuing requests at any time. More than this means wasted memory consumed by cache entries that are not being used. Less can mean reduced performance due to LRU discarding and reloading by querying the directory service. However, the ideal size can require a significant amount of memory, so there are trade-offs to be made.
Cache entries can become stale as a result of changes in group memberships for a user. To account for this, cache entries are retained for a maximum period of time referred to as the time to live (TTL). A cache entry whose TTL has expired is refreshed from the directory service to ensure it is up-to-date. However, depending on the length of the TTL, there can be a period of time after group membership changes are made during which the server will continue to use the stale entry. The consequence can be that the user cannot be granted all the access to which they are entitled (if added to a group) or can receive access to which they are no longer entitled (if removed from a group). Therefore, in configurations in which group membership changes are frequent, it can be necessary to reduce the TTL. Conversely, if group membership changes are infrequent, it can be possible to improve performance by increasing the TTL.
Security descriptor cache
There is one security descriptor cache for each object store, independently configured for maximum size with again an LRU policy applied to ensure the maximum size is not exceeded. The size of a security descriptor and therefore the amount of memory consumed by a cache entry is proportional to the number of ACEs in the ACL.
Again, the optimal size for the SD cache is around the number in active use - more leading to wasted memory and less to reduced performance because of the processing time and I/O cost of retrieving security descriptors from the database. However, sharing of security descriptors and other factors such as the frequency of proxy relationships among objects being accessed makes it difficult to estimate what the optimal size will be. So, using the performance statistics available in the Dashboard is the best approach to tuning. The size is independently configurable for each object store since the patterns of access to objects, and therefore to security descriptors, can differ between object stores.
There is no TTL for security descriptor cache entries since they are never modified and can never become stale.
Object-security cache
The object-security cache retains security information for proxy objects in memory, improving performance when the same proxy is accessed several times over a short period of time. An example is when retrieving the subfolders of a folder (each subfolder has the same proxy, namely its parent folder), so the security information for that folder is fetched just once and is reused to evaluate the access rights for every subfolder.
There is an independent object-security cache for each object store, again reflecting the possibility of different patterns of access, in this case, to proxy objects. For each object store, the maximum size and TTL for the cache are configurable.
The information retained in an object-security cache entry consists of a reference to the security descriptor for the proxy object (not the SD itself) plus identity information for the objects referenced by any proxy-defining properties of the proxy itself and the values of any marking-controlled properties of the proxy object. This typically requires a smaller amount of memory than for entries in the other caches, giving more scope for increasing the size without risk of running out of memory. Like the security descriptor cache, estimating the optimal size of the object-security cache is not straightforward and using the Dashboard statistics is the best approach for tuning.
An object-security cache entry can become stale as a result of updates to security-related properties of the proxy object - changes to Permissions or Owner or to proxy-defining or marking-controlled properties. The server that receives the request to make these updates automatically flushes the now stale entry from its cache, but other servers rely on a TTL as the means of overcoming staleness. The default TTL for the object-security cache is relatively short (30 seconds). In a multiple server configuration, it should only be increased if updates to any proxy objects are known to take place much less frequently than that.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.233.160