Xaraya | M. Lutolf |
Request for Comments: 0030 | Xaraya Development Group |
Category: Best Current Practice | November 2002 |
RFC-0030: Security System
This document specifies a Xaraya Best Current Practices for the Xaraya Community, and requests discussion and suggestions for improvements. Distribution of this memo is unlimited.
Copyright © The Digital Development Foundation (2002). All Rights Reserved.
This RFC presents a proposal for the Xaraya security system. The main difference with respect to the existing security system is that privileges are defined as objects independent of users and groups. As a corollary, the structure of users and groups is also revisited.
To avoid confusion before specifying anything, here is the list of terms we use in relation to the security system.
Example: the site administrator or the group of registered users are both roles.
Example: the ability to see the front page, or its login block is a privilege.
Example: the login block on the front page of a Xaraya site is an instance of the Block component in the Roles module. An administrator might choose to create more than one such instance e.g. in a multilingual site.
Roles is a generalization of the Users and Groups concepts in PostNuke. In Xaraya both Users and Groups of users are implemented as roles. As in PostNuke, roles that are Users can be members of other roles that are Groups. The difference to the PostNuke concepts is that there is no limit to the levels of nesting available. In addition, a role can be a member of any number of other roles.
The roles in Xaraya are arranged in a hierarchy or tree, and every role defined must be a member of at least one already existing role. At the top of the hierarchy is a role called "Everybody".
Note: Contrary to the PostNuke permissions system, the order in which multiple parents of a role are defined is not relevant for the way privileges are applied and has no impact on whether access is granted or denied. Specifically, there is no "first encountered wins" rule in Xaraya. ALL the privileges available will be checked for access.
The following rules apply to the roles hierarchy:
Role A Big Boss | | |--Role B |--Small Boss | | | | | |--Role C | |--John Doe | | |--Role C |--John DoeJohn both reports to "Big Boss" and "Small Boss" and as such has two roles in the system.
In the user interface we use the term "User" for roles which have one member and "Group" for roles which have multiple members. Conceptually however there is no difference between the two, both are roles. Since one can expect numerically many more Users than Groups or, in other terms, more leaves then nodes, the former are not displayed by default. Rather, one can specifically request to see the Users belonging to a given Group.
For convenience a number of roles are created at initialization time. They are:
Everybody (Group) | |--Administrators (Group) | | | |--Admin (User) | |--Users (Group) | |--Anonymous (User)
Everybody: This is the root of the roles tree and is defined as a group that contains all other subgroups and users.
Administrators: This is a group that contains those users that can do anything in the system, a sort of superuser. The Administrators group contains one such user, the Admin. The Admin is the default user logged on when Xaraya is installed.
Users: This is a group that represents users of the site. By default new users that register on the site become members of this group. This default can be changed by modifying the configuration settings of the Base module.
Anonymous: This is a user that represents users of the site that are not logged in.
Myself: This is a special "meta-user" that represents the current user. Myself can be used to create special privileges that allow, for instance, only the author of an article to modify the article.
The Xaraya concept of privileges has a structure similar to privileges in PostNuke. A privilege is an object that grants a particular type of access to a resource. Every privilege incorporates:
In addition, each privilege also has:
Similar to roles, privileges can be composed of other privileges. In addition to the attributes described above a privilege can have any number of subprivileges. A privilege can also be a part of any number of "parent" privileges. However, privileges do not live in a single hierarchy. Instead, the UI presents all the privileges in a list, with each privilege containing its subprivileges in a separate list, as the following example shows:
NoPrivileges a privilege with no subprivileges Administration another privilege with no subprivileges CasualAccess a privilege with 2 subprivileges, contains: ViewRolesBlock one of which itself contains contains: ViewLoginBlock 2 subprivileges. ViewOnlineBlock ViewThemes
N.B.: Privileges can be defined as empty containers, i.e. not themselves granting any rights. This is useful if they only serve to group other privileges. In the example above the privilege CasualAccess is an empty container that holds its 2 subprivileges.
It's important to understand that grouping privileges like this does not imply that "parent" privileges are in any way "stronger" than "children". Making privileges subprivileges to other privileges is just a convenient way of grouping them, so that bundles of them can be assigned at a time.
In the above example note that although the names are suggestive of certain behaviour there is no fixed naming rule. You can assign any names you want as long as they are unique within their module.
Furthermore there is no rule for how to group privileges, for instance by module. A good administrator will structure his privileges according to the roles he wants to assign them to, rather than by component or level.
In Xaraya privileges are defined without reference to any group or user. They are objects with no relevance until they are assigned to one or more roles. As explained below, assigning a privilege to a role also assigns ALL the subprivileges of that privilege to the role.
For convenience a number of privileges are created with each installer configuration at initialization time. Examples of these are:
Realm Module Component Instance Level --------- --------- ------------ ----------- ------------ All All All All ACCESS_ADMIN
As mentioned above Xaraya uses the access levels originally defined in PostNuke. These are:
Name Level -------------- ----- ACCESS_NONE 0 ACCESS_OVERVIEW 100 ACCESS_READ 200 ACCESS_COMMENT 300 ACCESS_MODERATE 400 ACCESS_EDIT 500 ACCESS_ADD 600 ACCESS_DELETE 700 ACCESS_ADMIN 800
The levels are cumulative. A given level implies the right to all the levels below it. The right to DELETE implies the rights to ADD, EDIT, MODERATE etc. An exception is ACCESS_NONE, which can override any other access right.
As noted above, when two privileges are defined on the same module, component and instance the one with the higher access level includes the right to the one with the lower level. We say that the privilege with the higher access level implies the other. In the following example two privileges are defined on the Examples module:
Name Realm Module Component Instance Level ----------------- --------- --------- ------------ ----------- ------------ ReadExampleBlock All Examples Block All ACCESS_READ EditExampleBlock All Examples Block All ACCESS_EDITThe privilege EditExamples implies ReadExamples.
Note that two privileges A and B are considered equal (identical) if A implies B and B implies A.
In the following example, however:
Name Realm Module Component Instance Level ----------------- --------- --------- ------------ ----------- ------------ ReadExampleBlock All Examples Block All ACCESS_READ EditArticleBlock All Articles Block All ACCESS_EDIT EditArticleItem 1 Articles Item All ACCESS_EDITnone of the privileges imply any of the others, as they refer to different modules and/or realms. We call such privileges disjoint. (NOTE: This example contains a Realm which is a feature which will not be used in the initial implementation.)
Definition: An Irreducible Set of privileges is a set in which all the privileges are disjoint.
Definition: Winnowing is the process by which the Xaraya privileges system creates irreducible sets of privileges.
A privilege accumulates the attributes of its children. As mentioned above since each privilege refers to a single realm/module/component/instance combination, you create more complex privilege-schemes by successively adding privileges to other privileges. During a security check all the component privileges in the tree will be taken into account.
However, in any given tree not all the privileges will necessarily be relevant. Take the following example:
ReadAll | |--DeleteExamples | | | |--AddExamples | |--EditArticles | |--AddArticles with the following definitions: Name Realm Module Component Instance Level ------------------- --------- --------- ------------ ----------- ------------ 1. ReadAll All All All All ACCESS_READ 2. DeleteExamples All Examples All All ACCESS_DELETE 3. AddExamples All Examples All All ACCESS_ADD 4. EditArticles All Articles All All ACCESS_EDIT 5. AddArticles All Articles All All ACCESS_ADDIt can be seen that, with the definitions given above, 3 implies 2 and 5 implies 4. Therefore when comparing all the privileges in the set, privileges 2 and 4 are not relevant, because they are superceded by 3 and 5 respectively.
During the winnowing process the privileges system compares each privilege in a tree with all the others in the same tree and discards those privileges implied by others. In particular duplicate privileges are removed. In the example above winnowing would leaves us with the following privileges:
ReadAll DeleteExamples AddArticles
As can be seen, all the privileges left in the example above after winnowing are disjoint. The set is irreducible.
Note also that the system doesn't care what the tree looks like. The same result would be gotten with the following tree, among others:
ReadAll | |--DeleteExamples | |--AddExamples | |--EditArticles | |--AddArticles[NOTE: MrB: This is somewhat counterintuitive. I would expect the shape of the tree to have influence. I understand it technically doesn't, but by representing it as a tree the user expects AddExamples to be "a part of" DeleteExamples, whatever that means to him. The difference between "defining" the tree and "checking the tree is a concept which is mentally merged for the user.]
In order for the privileges system to do something useful, privileges need to apply for users and groups. This is done by assigning privileges to roles in the UI. Theoretically any privilege can be assigned to any role.
Suppose I have a role FOO and the tree of privileges in the example above. The operation:
"assign ReadAll to FOO"
will assign all 5 of the privilege in the tree to FOO. (Note the notation for assignment shown here is only for convenience; the privileges UI is graphical)
However, note that the operation:
"assign DeleteExamples to FOO"
will give a different result depending on the shape of the tree, as the following examples show:
ReadAll "assign DeleteExamples to FOO" | |--DeleteExamples | Privileges assigned: DeleteExamples |--AddExamples AddExamples | EditArticles |--EditArticles AddArticles | |--AddArticles
ReadAll "assign DeleteExamples to FOO" | |--DeleteExamples Privileges assigned: DeleteExamples | | AddExamples | |--AddExamples | |--EditArticles | |--AddArticles
For convenience a number of assignments are made at initialization time.
For instance, the role Administrators is assigned the privilege Administration. In other words, members of the Administrators group can do anything.
In addition, a special privilege called GeneralLock is also assigned to the roles created at installation. GeneralLock contains privileges that stop you from changing or deleting basic roles and privileges such as the site Admin or Everybody. Removing or altering GeneralLock makes it possible to make such changes. This should only be done in special cases and with an understanding of how the system works, however, as such changes can damage the site in ways difficult to recover from.
A privilege assigned to a role is automatically inherited by all the role's descendants. For example, using the previous example:
ReadAll "assign ReadAll to FOO" | |--DeleteExamples | | Privileges assigned: DeleteExamples | |--AddExamples AddExamples | EditArticles |--EditArticles AddArticles | and ReadAll (if it is not empty) |--AddArticlesRole FOO will have 5 privileges assigned to him. However the same privileges will also be assigned to a child of FOO:
FOO | |--BARWe say that BAR has inherited the privileges of FOO. Note that BAR may also have privileges assigned to it. The UI of the privileges system will show for each role which privileges have been assigned and which inherited.
It's pretty apparent that if an inherited and an assigned privilege are disjoint, then nothing will happen. Essentially the two privileges have nothing to do with each other. But what happens when one of them implies the other? To wit:
FOO has assigned DeleteExamples | |--BAR has assigned ReadExamples where Name Realm Module Component Instance Level ------------------- --------- --------- ------------ ----------- ------------ 2. DeleteExamples All Examples All All ACCESS_DELETE 3. ReadExamples All Examples All All ACCESS_READIn this case the relevant privilege for BAR would be ReadExamples, even though its access level is lower, because
Rule: For privileges that are not disjoint, those of the children take precendence over those of the parents. We say that BAR's privilege "trumps" that of his parent FOO.
A mask is a special type of privilege in the Xaraya security system. Each mask refers to one or more security checks in the code. When a security check is encountered, the system gets the relevant mask and compares it to the privileges of the user. A green light is given if the mask is implied by one of the user's privileges. Otherwise an exception is thrown.
The structure of a Schema corresponds to that of a privilege. For example the following Schema
Name Realm Module Component Instance Level ------------- --------- --------- ------------ ----------- ------------ ReadExamples All Examples All All ACCESS_READrequires that a user has a privilege assigned with at least ACCESS_READ in order to pass a given security check.
When a security check is encountered in the code, the privileges system goes through the following steps:
In the following example:
Everybody offspring distance 2 or 3 | |--Marketing offspring distance 1 | | | |--Product Mgr | |--Europe offspring distance 2 | |--Spain offspring distance 1 | |--Product MgrLet's assume the user logged in has the Product Mgr role and an action is requested by that user which is protected by the security system. Below are the steps what happens. Look at this example from the point of view of the actual role requesting the protected action (here: Product Mgr). The offspring distance is the ancestry relative to Product Mgr (the maximum value for it)
You probably want to read the above again. ;-)
The following are the standard-type APIs used in Xaraya. The $args parameter represents an array of arguments to the function.
The following functions should be used to create default roles and privileges in the init.php of a module.
The classes and class methods should in general not be accessed directly. Most of them return objects rather than arrays, so use them at your own risk.
A central repository of user and group definitions. Each user, group, group of groups etc. is a role with an entry in this repository.
An implementation of the roles object conceptually replaces the tables xar_user and xar_groups. The code for manipulating roles will deal with the issue of whether the role is a group or a user and handle things accordingly.
Methods:
An object representing a single group or user.
Methods:
A central repository of privilege masks (policies?). The masks are normally defined and registered as entries upon installation of a module. There needs to be a restriction that assigned names for components need to be unique within a module.
Methods:
A central repository for privileges defined at any given time. No duplicate privileges are allowed. This object extends the xarMasks object.
Methods:
An object representing a single mask.
Methods:
An object representing a single privilege. This object extends xarMask.
Methods:
The tables xar_groups and xar_users can be merged into a new Roles table. The table xar_group_membership also changes:
Table xar_roles Table xar_rolemembers xar_uid xar_uid xar_name xar_parentid xar_type xar_users xar_uname xar_email xar_pass xar_date_reg xar_valcode xar_state xar_auth_moduleThe field xar_type is 0 implies child is a user, 1 implies child is a group. Calls to groups and users in the API have to be appropriately modified to look up the new table. [MrB: evaluate whether we can use "implicit" typing. if(nochildren): user;else: group]
Table xar_security_masks xar_sid xar_name xar_realm [MrB: leave it for now, don't use it] xar_module xar_component xar_instance xar_level xar_description
Table xar_security_instances xar_iid xar_module xar_component xar_header xar_query xar_limit xar_description
Table xar_privileges Table xar_permmembers xar_pid xar_pid xar_name xar_parentid xar_realm xar_module xar_component xar_instance xar_level xar_description
Table xar_security_acl xar_partid xar_privid
A mask is a special kind of privilege used to check other privileges. When a mask is encountered it is checked against the user's privileges to see whether access to the resource in question is granted. The resource a mask protects is called a component.
Each mask that will be used for security checks needs to be registered. This is done with the function xarRegisterMask, which has the following syntax:
function xarRegisterMask($name,$realm,$module,$component,$instance,$level, $description='') where: $name : a name given to the mask. The name needs to be unique within the module. $realm : the realm the mask applies to. $module : the name of the module the mask applies to. $component : the name of the component the mask belongs to. The component name is referenced during security checks. $instance : the name of the instance the mask applies to. This refers to an instance that has been defined at runtime (see below), $level : the security level a privilege must have to pass the check. These are the usual values 0 - 800. $description : a text field that describes the mask.All fields except the description are mandatory. The value 'All' can be used for realm, module, component, instancetype or instance. In the case of instances, expanding 'All' to the number of instance types makes your definition clearer, as shown in the example below:
xarRegisterMask('EditClassification','All','articles','Classiciation','All:All:All',ACCESS_EDIT);This creates a mask named EditClassification for the articles module. Security checks can invoke the mask as described below.
Masks need to be registered at init time. In other words, for each mask to be registered, invoke the xarRegisterMask function in the init.php of the module the mask belongs to.
Such a call could also be inserted when a new instance is created. This would let have the user define masks at run time. (can of worms, here) [MrB: yeah, don't allow it initially till we have worked it out how exactly to do that]
Security checks in a module need to check against specific instances. We therefore want to ensure that the instances administrators include in the privileges they create are well formed. This is done by registering the instance definitions with the system,
Instance definitions are not strictly necessary to make the security system work, but they help make creating privileges easier.
Instances conceptually are objects that a module deals with, e.g. articles, folders, download items, dynamic data fields. They can be created initially or at run time.
An instance can usually be defined by one or more database fields. For example an instance in the categories module, a category, can be defined by its title, or even more precisely by its ID, which is a unique reference. Module developers will use several such "filters" to define instances. Postnuke limited their number to 3, but Xaraya allows any number.
Instances are defined by the xarDefineInstance function:
function xarDefineInstance($module, $component, $instancedefinition) where $module : module to which the instance applies. $component : component which the instance is part of. $instancedefinition : an arry that represents the definition of the instance. The array contains n entries 3 elements each: - a header text - a field definition given by an sql query - a parameter giving the maximum number of instance items to be shown.
Each instance to be defined must invoke this function in the init.php file of the module it refers to.
Each entry in the instance definition array defines one "filter" for the instance (such as a category title). The elements in the array entry let the UI create a dropdown that is used when creating privileges. The header text can be displayed to indicate the type of "filter". The sql statement defines what database entries will be shown in the dropdown. The limit parameter can be set by the module developer to limit the number of dropdown items. If the actual number of instances is greater than the limit, the UI will show an empty text field for manual entry instead of a dropdown.
An example of how this might be used:
$query1 = "SELECT DISTINCT xar_pubtypeid FROM xar_articles"; $query2 = "SELECT DISTINCT xar_cid FROM xar_categories"; $query3 = "SELECT DISTINCT xar_authorid FROM xar_articles"; $instances = array( array('header' => 'Pub. Type ID:', 'query' => $query1, 'limit' => 20 ), array('header' => 'Category ID:', 'query' => $query2, 'limit' => 20 ), array('header' => 'Author ID:', 'query' => $query3, 'limit' => 20 ) );With this definition (which is created in the init.php of the articles module) the UI will create 3 dropdowns for defining instances that are article, namely publication type, category and author, all given by their respective IDs. The option 'All' is automatically added to each dropdown.
If more than, for instance, 20 categories have been defined, the UI will substitute a text box for the second dropdown, requiring the administrator to manually enter a category ID when defining a privilege. Note that no validity checks are performed on such input.
Note that, although the UI can ensure that the ID choices for publication type, category and author are valid, there is no guarantee that an article corresponding to a given combination exists or will exist. In other words, with instance definitions the UI can ensure that privileges contain well formed instances, but it cannot ensure that the instances are valid.
Security checks are the way the system checks a user's a privileges against a mask of a component. Security checks replace the previous xarSecAuthAction function. A simple example of a security check is:
if(!xarSecurityCheck('EditArticles')) return;On encountering this line in the code, the system will check the user's privileges against those of the mask 'EditArticles'. If the mask is implied by at least one of the user's privileges, the function returns true. If the security check fails the function returns false. Like the xarSecAuthAction function, securitycheck will also display a standard error message if the check fails.
The error message can also be suppressed, as shown in the following example:
if (xarSecurityCheck('EditArticles',0)) { ...code to edit an article in the articles module }Here the user's privileges are again checked against 'EditArticles' to see whether the user may add an article. The 0 value tells the function not to display an error message if the check fails.
The full syntax of the xarSecurityCheck function is:
function xarSecurityCheck($name,$catch=1,$component='',$instance='',$module='',$role='') where $name : name of the mask to be checked. $catch : 1 = show the exception message if the check fails. 0 = do not show an exception message $component : name of a component to be checked against. $instance : name of an instance to be checked against. $role : name of a role to be checked against. $module : name of a modules to be checked against.The component, instance, role and module values are used to override values defined in the mask's definition. For instance, entering a value for $component and $instance lets you check against an instance defined at runtime, rather than when the mask is registered.
The default values for $role and $module are the current user and the module in which the security check is encountered. Entering a value for $role lets you check against the privileges of a user other than the current user.
Here is a step by step guide to switching modules from Postnuke's (or Xaraya's previous) permissions system to the Xaraya security system.
Defining instances is a bit of work. The good news is that there are probably not more than 3 of these in any given module.
The first question to answer is: what instances do I have or need? Instance definitions ("security schemas") can generally be found in the version.php file of the module. However, you'll probably also want to look through the module code for calls of the pnSecAddSchema or xarSecAddSchema function, which also define security schemas. You'll need to create an instance definition for each of the entries in a security schema.
Security schemas have the form:
$modversion['securityschema'] = array('categories::category' => 'Category name::Category ID', 'categories::item' => 'Category ID:Module ID:Item ID');In this case we have a schema with two entries, which will call for two instance definitions. In the first entry the line
'categories::category'refers to the module name ("categories") and the component name ("category"). Both of these can be inserted into the instance definition as shown below. If there is no component name, insert "All" in the definition instead.
The second part of the entry is a bit more complicated:
'Category name::Category ID'This part of the schema consists of up to 3 names of database fields which make up the instance definition. You need to define the sql query strings which return a recordset with each of these fields from the database. In this case the query strings would be:
$query1 = "SELECT DISTINCT xar_name FROM xar_categories"; $query2 = "SELECT DISTINCT xar_cid FROM xar_categories";Note you'll have to look in the database a bit to identify the correct table and field names. Unfortunately this is not clearly documented anywhere, but in most cases the table will be one of those belonging to the module itself, and the field names can be identified fairly easily.
Once you have the module, component names and the query strings these can be inserted in the instance definition. The definition for the first entry in the security schema above is shown below, with appropriate values for the header and limit parameters included:
$query1 = "SELECT DISTINCT xar_name FROM xar_categories"; $query2 = "SELECT DISTINCT xar_cid FROM xar_categories"; $instances = array( array('header' => 'Category Name:', 'query' => $query1, 'limit' => 20 ), array('header' => 'Category ID:', 'query' => $query2, 'limit' => 20 ) ); xarDefineInstance('categories','Category',$instances);
The next step is to create masks for all the security checks in the code. These are privilege definitions which are referenced whenever a security check is called: the check compares the user's privileges with the privilege defined by the mask and decides whether the user passes the check or not.
There are typically 3-6 different masks for any given module. How do I know what masks to define? Unfortunately the only way to figure that out is to go through the code searching for pnSecAuthAction or xarSecAuthAction calls and seeing how many different types there are.
Here is a useful rule: Assume 1 mask to be created for each security level you find in the *SecAuthAction calls.
Once you have identified the different calls, create a mask definition for each of them in the init.php of the module. Use the following function:
Syntax: xarRegisterMask(Name,Realm,Module,Component,Instance,Level,Description) Example: xarRegisterMask('ReadCategoryBlock','All','categories','Block','All:All:All',ACCESS_READ);
The next step is the most labor intensive: changing the *SecAuthAction calls to the new system using xarSecurityCheck. A module may contain literally dozens of these calls sprinkled through the code. Unfortunately each needs to be visually examined and appropriately modified.
Some examples are shown below. In each of these we assume an appropriate mask has been created based on the information in the old call, and that can be referenced by the new call.
if (!xarSecAuthAction('All', 'categories::', "::", ACCESS_EDIT)) { return;} becomes if (xarSecurityCheck('EditCategories')) return;The xarSecuritCheck call references the mask we defined above via the mask name. The module name and access level information is stored in the mask, so there is no need for them as parameters in the call. If the security chekc fails the system will automatically generate an exception message.
if (xarSecAuthAction('All', 'categories::', "::", ACCESS_EDIT)) { becomes if (xarSecurityCheck('EditCategories',0)) {This is identical to the previous call except that the exception message that would be generated in the case of a failed security check is suppressed by setting the second parameter to 0.
This call is useful when you want to loop through a series of security checks in the code without halting execution if the check fails.
if (!xarSecAuthAction(0, "categories::item", "$name::$id", ACCESS_EDIT)) { return; } becomes if (!xarSecurityCheck('EditCategories',0,'Item','$name:All:$id')) return;In this example we override some of the mask definition parameters with dynamic values. Recall that the mask definition above is:
Syntax: xarRegisterMask(Name,Realm,Module,Component,Instance,Level,Description) Example: xarRegisterMask('EditCategories','All','categories','All','All',ACCESS_EDIT);In this definition both the Component and Instance parameters are "All". By adding the parameters "item" and "$name::$id" to the xarSecurityCheck call we replace the values "All" by dynamic values to be checked against.
Note that "$name::$id" in the old call becomes "$name:All:$id" in the new call. We explicitly list all of the instances "filters", even those that in the old call are not mentioned.
It is important for there to be consistency among instances, masks and security checks. If a security check does not find a mask of the name called, it will throw an exception. If the check includes dynamic component and/or instance values that do not coincide with an instance definition, it may fail.
The following code becomes redundant after the conversion and can be removed:
We recommend leaving the security schema definitions in the version.php files for documentation purposes. However, they should accurately reflect the instances used in the xarSecurityCheck calls.
I'd rather dispense with this and run the UI through dropdowns and checkboxes, but I understand that some people are clamoring for an "advanced user" UI for the privileges system. There may also be some performance considerations here, trading CPU processing for DB hits. And then there's backwards compatibility. Well, OK.
My suggestion for the future would be to limit the advanced UI to entering lists into the appropriate form fields, say a "Component" or "Instance" field in the UI. On submitting, the list(s) would be disassembled to records in the privileges table with one component/instance per record. This in itself is not trivial, because the user would be entering some sort of name, and you'd have to parse the name, make sure it corrsponded to a real object registered in the privileges system, and then translate it to a numeric ID.
Need to check to make sure any calls using the name of an object rather than its ID don't screw up the ML capabilities.
Realms have been in the old security system, but no-one seems to know exactly what they do and how to use them. Until that is crystal clear, realms will not be supported, or rather, actively not supported. We can't have loose ends in a security system
The issues encountered in Version 1.0 suggest merging the Roles and Privileges modules into a single module in the future.
A thourough evaluation needs to be done, whether we want the security system in user module space. This has both advantages and disadvantages. For ease of migration they will be in user module space for now, possibly classified as "Core Admin", so a reasonable guarantee can be given they exist when bootstrapping the system.
Version 0.9, Dec 15, 2002: First release of this document
Version 1.0, Jan 15, 2003: Major rewrite based on the first version of the code. Clearer definition of the architecture, implementation and UI.
Version 1.1, Feb. 8, 200: terminology changes, review by MrB
The DDF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the DDF's procedures with respect to rights in standards-track and standards-related documentation can be found in RFC-0.
The DDF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to practice this standard. Please address the information to the DDF Board of Directors.
Funding for the RFC Editor function is provided by the DDF