From 389 Directory Server
Contents |
Account Policy Plugin - Software Design Specification
Introduction
The Fedora Directory Server equips administrators with a set of features for managing account access, including password policy and account inactivation. However, beyond the ability to lock out an account based on password failures, and being able to specify accounts that should be inactivated, there is a lack of account policy functionality. An example is that roles and class of service can inactivate accounts that were created before a certain date using a filter on the createTimestamp, but it can't inactivate accounts that have existed for more than a certain amount of time because that requires a comparison between the creation time with the current time. Therefore we propose to create an account policy plugin to handle some of the more popular account policy features requested in the past.
Goals and Guidelines
Our goals include simple but flexible configuration. For basic usage the required configuration should be trivial with sensible defaults. However, high customization needs to be available. For example, at least until we've settled on a schema, we'll provide attribute mapping.
We also want to provide easy but flexible administration. We don't want to complicate administrators' lives unnecessarily when they want to add or remove a policy for a set of users. It should be simple to define a policy and target a set of users.
Finally we want to provide easy means for auditing the account states where applicable.
Detailed Design
General Plugin Configuration
When the plugin starts up it will check if it's being started with an argument (nsslapd-pluginarg0). If it has an argument, the value should point to a configuration entry which will be retrieved by DN. If the plugin does not have an argument some defaults will be used. If the entry pointed to be the DN can not be retrieved, plugin initialization will fail and the plugin will not start because assuming defaults when there a configuration entry is indicated would be a security risk. If the configuration entry is retrieved it will be parsed for configuration. Any options missing in the configuration entry will take on defaults. Here is an example configuration:
dn: cn=acct_policy_plugin,cn=plugins,cn=config objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: acct_policy_plugin nsslapd-pluginPath: /path/to/libacctpolicy.so nsslapd-pluginInitfunc: acct_policy_init nsslapd-pluginType: object nsslapd-pluginEnabled: on nsslapd-plugin-depends-on-type: database nsslapd-pluginId: acct-policy nsslapd-pluginarg0: cn=acct_plugin_config,cn=acct_policy_plugin,cn=plugins,cn=config
dn: cn=acct_plugin_config,cn=acct_policy_plugin,cn=plugins,cn=config objectClass: top objectClass: extensibleObject cn: acct_plugin_config alwaysrecordlogin: yes stateattrname: loginTimestamp altstateattrname: createTimestamp specattrname: acctPolicySubentry limitattrname: accountInactivityLimit
Detailed Design of Account Inactivity
Introduction
This component of the account policy plugin will inactivate accounts based on their inactivity. It's implemented in two parts, a post-op BIND callback which maintains a timestamp of the last login in the binding entry, and pre-op BIND callback which compares the current time with the last login timestamp and makes an allow or deny decision.
Logging
The logging subcomponent will record a timestamp in the bind entry after successful binds. The timestamp will be stored in the bind entry in generalized Zulu format like "%Y%m%d%H%M%SZ" (trailing literal 'Z') in the operational attribute loginTimestamp. Unless the configuration has alwaysrecordlogin set to true, the plugin will only maintain the timestamps in bind entries that are covered by an inactivity policy; that is anyone who has an acctPolicySubentry attribute. Here is an example of a person who is covered by an account policy and has a login timestamp:
dn: uid=scarter,ou=people,dc=example,dc=com objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetorgperson title: engineer uid: scarter sn: Carter cn: Sam Carter loginTimestamp: 20060527001051Z acctPolicySubentry: cn=AccountPolicy,dc=example,dc=com
Enforcement Method
Enforcement is implemented as a SLAPI_PLUGIN_PRE_BIND_FN and performs the inactivity check using the loginTimestamp value and the current date, compared to the limit specified in the account policy that covers the bind entry. Example account policy:
dn: cn=AccountPolicy,dc=example,dc=com objectClass: top objectClass: ldapsubentry objectClass: extensibleObject objectClass: accountpolicy # 86400 seconds per day * 30 days = 2592000 seconds accountInactivityLimit: 2592000 cn: AccountPolicy
If successful the plugin returns 0 and the bind proceeds like normal. If the inactivity limit has been exceeded an LDAP error and a message are sent to the client and the plugin returns -1 which ends the bind attempt.
If the loginTimestamp is missing then the user has never logged in and the administrator didn't provision one. An alternate attribute is used in this case, the createTimestamp by default.
However, this method will not work well with older releases of Directory Server because bind preop functions are not currently called from SASL binds, which makes SASL bind a loophole around our inactivity enforcement.
Enforcement Method Alternative 1 (OBSOLETE, IGNORE)
There are three proposals for allowing or denying binds based on account inactivity. The first two methods use a virtual attribute provider but how the exported attribute results in denied binds is different.
In the first proposal every entry that is covered by an account inactivity policy has an acctPolicySubentry specifier which has a DN for value. The entry pointed at provides an inactivity limit. This is similar to how password policy is configured (1). Here is an example:
dn: uid=scarter,ou=people,dc=example,dc=com objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetorgperson title: engineer uid: scarter sn: Carter cn: Sam Carter lastLoginTime: 20060527001051Z acctPolicySubentry: cn=Acct Policy,cn=config
dn: cn=Acct Policy,cn=config objectClass: top objectClass: ldapsubentry objectClass: AccountPolicy accountInactivityLimit: 2592000
Then we will add a virtual attribute provider for the nsAccountLock attribute which will have the value of "true" if the difference between the current time and the timestamp of the last bind exceeds the accountInactivityLimit in the policy. AccountInactivityLimit is specified in seconds, so in the above example nsAccountLock would show up with a value of "true" a month after 2006-05-27 00:10:51.
Enforcement Method Alternative 2 (OBSOLETE, IGNORE)
Using the virtual attribute service provider interface we will expose a computed attribute called timeSinceLastLogin. The value of this attribute will be the delta between the last login time and the current time. Here is an example where Sam has not logged in for 15 days:
dn: uid=scarter,ou=people,dc=example,dc=com objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetorgperson title: engineer uid: scarter sn: Carter cn: Sam Carter lastLoginTime: 20060527001051Z timeSinceLogin: 1296000
With this virtual attribute available we can configure account locking using filter-based roles. Here is an example that sets a one-month inactivity policy for engineers:
dn: cn=Account Inactive Role,dc=example,dc=com objectClass: top objectClass: ldapsubentry objectClass: nsroledefinition objectClass: nscomplexroledefinition objectClass: nsfilteredroledefinition cn: Acount Inactive Role nsRoleFilter: (&(timeSinceLogin>=2592000)(title=engineer))
dn: cn=Account Inactive CoS,dc=example,dc=com objectClass: top objectClass: ldapsubentry objectClass: cossuperdefinition objectClass: cosClassicDefinition cn: Account Inactive CoS costemplatedn: dc=example,dc=com cosspecifier: nsRole cosAttribute: nsAccountLock operational
dn: cn="cn=account inactive role,dc=example,dc=com",dc=example,dc=com cn: cn=account inactive role,dc=example,dc=com objectClass: top objectClass: costemplate objectClass: extensibleobject nsAccountLock: true
Schema Changes
Experimental schema used in development and testing of the plugin.
# # Schema for supporting the account policy plugin (60acctpolicy.ldif) # dn: cn=schema ##### ## accountInactivityLimit specifies inactivity limit in accountPolicy objects ## (DirectoryString syntax) attributeTypes: ( accountInactivityLimit-oid NAME 'accountInactivityLimit' DESC 'Account Policy Plugin' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Experimental' ) ##### ## lastLoginTimestamp holds login state in user entries (GeneralizedTime syntax) attributeTypes: ( lastLoginTimestamp-oid NAME 'lastLoginTimestamp' DESC 'Account Policy Plugin' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Experimental' ) ##### ## acctPolicySubentry points to an account policy (DN syntax) attributeTypes: ( acctPolicySubentry-oid NAME 'acctPolicySubentry' DESC 'Account Policy Plugin' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Experimental' ) ##### ## accountPolicy is the objectclass of account policy subentries objectClasses: ( accountPolicy-oid NAME 'accountPolicy' DESC 'Account Policy Plugin' SUP top MAY ( accountInactivityLimit ) X-ORIGIN 'Experimental' )
Outstanding Issues
- User Interface
- Will we need support in the GUI? Both enforcement methods require the use of Roles and CoS, maybe we can leverage the existing stuff. But the Account Inactivation feature has full UI that adds all the required roles and stuff, and so does Local PWP.
- If we add UI, should we also touch replication? When adding account inactivity policy we could search for agreements and offer to add lastLoginTime to the excluded attribute list, if they don't want to replace last login state.
- Should we inquire with the current maintainer of the password policy draft if we can sneak account inactivity into the same draft? [[1]] Although the password policy draft deals with some account related stuff like account lockout time after password failures, account inactivity falls into an area less gray and more dark, so maybe not. Is there an account policy draft?
Detailed Design of Account Expiration
Introduction
This component of the account policy plugin will inactivate accounts based on an expiration date.
Design
This works in a similar way to Account Inactivation. The account policy in effect for an entry would specify an expiration period for the account and upon login the plugin tests whether the current time minus the time in the createTimestamp is greater than the expiration period. createTimestamp is already automatically added when new entries are added.
dn: uid=scarter,ou=people,dc=example,dc=com objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetorgperson title: engineer uid: scarter sn: Carter cn: Sam Carter createTimestamp: 20060527001051Z acctPolicySubentry: cn=AccountPolicy,dc=example,dc=com
dn: cn=AccountPolicy,dc=example,dc=com objectClass: top objectClass: ldapsubentry objectClass: extensibleObject objectClass: accountpolicy # 86400 seconds per day * 30 days = 2592000 seconds expirationPeriod: 2592000 cn: AccountPolicy
Schema Changes
TBD.
Outstanding Issues
Mostly same as the Account Inactivation issues.
Bibliography
(1) Prasanta Behera's password policy draft, 9th iteration (http://www.faqs.org/ftp/internet-drafts/draft-behera-ldap-password-policy-09.txt)
