User_Life-Cycle_Management

Contents

User_Life-Cycle_Management#

Overview#

Corporate or big setups of Identity Management system often requires an advanced user life-cycle management capabilities (like staging area for new or deleted users) or standard LDAP interface for adding or removing users that can be used by provisioning systems.

Use Cases#

External Provisioning System#

User Story#

As an Administrator, I want to configure my employee provisioning system to manipulate the employee records to FreeIPA via LDAP protocol using standard LDAP objectclasses, so that I do not have to request FreeIPA specific integration with my provisioning system vendor.

Description#

The following supported workflows are expected:

  1. Create a user: provisioning system adds user to staging tree are using standard LDAP add. Not all fields that standard FreeIPA user has need to be specified. Provisioning system may or may not use the Freeipa CLI to add the user.

  2. Activate user: activate user by moving it from staging area to active user area. All attributes required by FreeIPA are generated if they are missing. All activations of a user accounts must be done on the same server, else it can leads to replication issues as attribute uniqueness can reject some operation.

  3. Assign group memberships: add group membership to activated user. Membership can only be added in active users tree. Staged or deleted users have no membership information.

  4. Update user: modify user attributes

  5. Change password: administratively change user password

  6. Delete user: move user from active user tree to staging tree to keep it’s attributes (like UID) and settings in case the user returns back and need to be restored

  7. Restore deleted user: move deleted user back to the tree of active users

  8. Lock user: temporarily lock user so that it is not accessible

  9. Unlock user: unlock temporarily locked user

Privilege Separation for Employee Entry and Activation#

User Story#

As an Administrator, I want to allow Human Resources Administrators to add future employees to FreeIPA and in the same time I do not want to allow them activating them, so that I can delegate that privilege to my Security Administrator after the employee credentials are verified on the first day of employment.

Design#

User status#

In User Life Cycle, a user account is stored in a LDAP repository as an entry in the DIT. A user account follows a workflow that changes the status of the user. There are 3 differents status:

  • Stage

    • This is an initial state where some of the user properties may not be already set

    • In this state the user account can not be used to authenticate.

    • The ldap entry of a user account is stored: cn=staged users,cn=accounts,cn=provisioning,$SUFFIX

    • The staging container usually contains few user account that represent the few new comers in the organisation.

  • Active

    • This is the normal state where all necessary properties are set

    • In this state the user account can be used to authenticate (if user is enabled)

    • The ldap entry of a user account is stored: cn=users,cn=accounts,$SUFFIX

    • The active container contains hundreds/tousands user accounts that represent all the people currently in the organisation.

  • Delete

    • This is the state of deleted active user account. Most of its properties have been preserved. Unpreserved properties are for example membership properties that have been reset

    • The user account can not be used to authenticate

    • The ldap entry of a user account is stored: cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX

    • The deleted container contains hundreds/tousands user accounts that represent all the people who left the organisation.

    • The deleted container preserves former users to conform legacy, law and policies. It can help to recover user properties in case a former user returns back to the organization.

  • Active account

    • in addition to active user, a special container contains all the active accounts. Accounts are not only users

    • the ldap entry of active accounts is stored: cn=accounts,$SUFFIX

workflows#

The main workflow allows moves: stage --> active <--> delete
  • stage -> active: The appropriate set of approvals are granted and a new comer is now fully operational in the organisation

  • active -> delete: The user leaves temporary the organisation

  • delete -> active: The user join back the organisation and recover some of his previous settings

The workflow allows to recreate a user if the entry gets corrupted:

  • delete -> stage: The entry got corrupted and was deleted. Moving it back to ‘ Stage ‘ the entry can later be activated again. The following FreeIPA attribute are preserved: ‘ ipaUniqueID ‘ , ‘ uidNumber ‘ and ‘ gidNumber ‘.

The workflow allows to add user accounts in:

  • stage: the user needs some approval before being active

  • active: the user does not need any approval before being active

The workflow allows to delete user accounts from:

  • staging: The user account will never receive the approval in order to be active

  • delete: The user will never join back the organisation

Note: delete action will erase permanently the entry from the repository. It is a LDAP DEL.

The workflow allows to modify user account from:

  • stage: modify the user account that remains in stage

  • active: modify the user account that remains in active

                                                 -- find ---+                     -- find --+
                                                 -- show ---+                     -- show --+
                                                 -- add-----+                               |
                                                 -- mod ----+                               |
                                                            |                               |
                                                            V                               V
              -------------------                    ----------------                  ---------------
 -- find -->  |                 |                    |              |                 |              |
 --- mod -->  |                 |                    |              |                 |              |
 --- add  --> |                 |  --- activate -->  |              |  --- delete --> |              |
<-- delete -- |      STAGE      |                    |     ACTIVE   | <-- undelete -- |    DELETE    | -- delete ->
              |                 |                    |              |                 |              |
              | <plg. stageuser>|                    |  <plg user>  |                 |  <plg. user> |
 -- show -->  |                 |                    |              |                 |              |
              -------------------                    ----------------                 ---------------
                       ^                                                                      /
                       \                                                                    /
                         ----------------------- add (from-delete opt.) ---------------------

stageuser plugin#

Add a stage entry#

  • Support engineer can use the following command

    • ipa stageuser-add <user_identifier> –first=<first name> –last=<last name>

      ipa stageuser-add tuser  --first=test --last=user
      
    • if needed, command may specify more details about the user, including the password

      ipa stageuser-add  tuser --first=Test --last=User --random --manager=muser --phone 123456789
      
    • ipa stageuser-add supports almost the same options as user-add, but compare to user-add here is the list of differences:

      • noprivate: no supported as a stage entry has no private group

      • manager: must be an active user

    • Filled with placeholders the entry will look like

dn: uid=tuser,cn=staged users,cn=accounts,cn=provisioning,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalperson
objectClass: posixAccount
cn: Test User
sn: User
uid: tuser
uidNumber: -1
gidNumber: -1
homeDirectory: /home/tuser
loginShell: autogenerate
  • A stage user can also be created from a former user. There is still discussion (see 1 and 2 ) if the former user can be picked up from the ‘Delete’ container or from the ‘Active’ container or both.

Currently the proposed interface are

stageuser-add <uid> --from-delete

or

user-undel <uid> --to-stage

or

user-unactivate <uid>

The drawback of the first CLI (stageuser-add) is that lastname/firstname are required option, but when the ‘uid’ entry is taken from the ‘Delete’ container lastname/firstname are useless.

Provision stage entry#

  • As described in the first Use case, provisioning systems (external) create the vast majority of Stage entries (using or not the FreeIPA CLI).

    • Provisioned entries MUST follow the following rules

      • Provisioning system places a staged user entry to cn=staged users,cn=accounts,cn=provisioning,SUFFIX

      • Entry RDN attribute is ‘ uid ‘ (see Supported Staged entries)

    • Entry may contain both data and placeholders. Note that when the entry will become active, some of the data/placeholders may be changed.

    • Provisoning system can create an entry with few constraints, that mean that the activation of a stage entry must be done with care. So provisioning systems is the main justification why activation will be done using a ADD-DEL approach

    • A Stage entry does not need to have all attributes that standard FreeIPA user has. In order to allow the correct processing of User Life Cycle, staged users must have a minimal set of attributes

dn: uid=tuser,cn=staged users,cn=accounts,cn=provisioning,dc=example,dc=com
objectClass: top
objectClass: inetOrgPerson
cn: Test User
sn: User
uid: tuser

Activate StageUser#

Activating a user is a major step in the User Life Cycle. It allows FreeIPA to start managing the entry and the user to authenticate with it. This action is only authorised to Support Engineer.

  • Support Engineer is using FreeIPA CLI: ipa stageuser-activate <user_identifier>

    ipa stageuser-activate tuser
    
  • The CLI supports only one account ID (no series of accounts can be activated in a row)

  • This operation ‘moves’ the entry, using LDAP ADD on the destination entry then DEL on the source entry

Source:           cn=staged users,cn=accounts,cn=provisioning,SUFFIX
Destination:     cn=users,cn=accounts,SUFFIX
  • Error handling

    • ADD fails, the source entry is preserved and the CLI reports an error

    • if DEL fails, the destination entry is removed and the CLI reports an error. If it fails to delete destination entry, both entries will remain. This is not a concern as the Stage entry will never be activated as long as the destination entry exists and have the same uid.

  • The destination Active LDAP entry is a NEW entry compare to the source Stage entry (see MODRDN vs ADD-DEL)

    • It contains all FreeIPA required objectclasses/attributes (including structural objectclasses) (comment: TBL in implementation)

    • Unsupported objectclasses/attributes present in the Stage entry have been removed

  • The destination Active LDAP entry is a NEW entry (LDAP ADD). The source Stage entry may contain userPassword in an hashed way (see http://www.freeipa.org/page/V4/User_Life-Cycle_Management#Staging_entry stored password). To allow the storing of pre-hashed password ipa-pwd-extop:ipapwd_pre_add must relax its control for example if the krb keys already exists in the entry.

  • Stage container is out of the scope of uid uniqueness plugin, so the destination entry can be added even if the source entry still exists

  • Active and Delete containers are in scope of uid uniqueness plugin, so destination entry can not be added if it already exists an Active or Delete entry with the same RDN (‘uid’) value. For example, it exists jdoe Active or Delete entry that contains several uid values. The entry jdoe has been created by a provisioning system, in fact Regular Freeipa CLI do not create user entry with multiple uid. foo can not be Activate because jdoe already have the uid: foo value:

dn: uid=foo,cn=staged users,cn=accounts,cn=provisioning,SUFFIX
...
uid: foo

dn: uid=jdoe,cn=users,cn=accounts,cn=provisioning,SUFFIX
...
uid: jdoe
uid: foo

or if it exists a Delete entry that already have the ‘’uid: foo value:

dn: uid=foo,cn=staged users,cn=accounts,cn=provisioning,SUFFIX
...
uid: foo

dn: uid=jdoe,cn=deleted users,cn=accounts,cn=provisioning,SUFFIX
...
uid: jdoe
uid: foo

MODRDN vs. ADD-DEL

When a staged user is moved to active users tree or an active user is moved to deleted users tree, there are 2 possible approaches - renaming (LDAP MODRDN operation with defining newsuperior attribute) and moving the LDAP object (LDAP ADD and DEL operations). In the end, the result will the same for outer world, but the operation will affect DS internals and plugin function.

  1. Renaming operation is a better approach from atomicity point of view (second, delete opration may fail and there would be 2 duplicate entries), but it may interfere with both internal DS plugin (referential integrity, memberOf, manged entry plugin) and 3rd party plugins. They may tend to keep all DN links to the entry unless they are modified not to do so when such entry is moved to deleted tree.

  2. Moving operation seems cleaner approach as all these plugins (including current plugins) will understand the operation in the right semantics. However, it is more difficult to control (see related tickets) and ability to move a user from staging tree to active users tree would require ability to read and write all user attributes, including userPassword.

Provisioning system does not guarantee to create the stage entry with the appropriate set of structural objectclasses (see Activating staged user. The active entry requires all the FreeIPA structural objectclasses/attributes. It can be addressed:

  • Adding in the stage entry each missing objectclasses/attributes - Remove the unwanted objectclasses/attributes

  • Create a new entry with all the required objectclasses/attributes and fill it from values taken in the stage entry

A stage entry is possibly partially initialized (especially with provisioning systems), using MODRDN means that this incomplete entry becomes active and one can bind with it (if credential are set). So some MODs are needed to make it a valid entry, before we can issue the MODRDN.

The second approach is chosen solution because:

  • it allows to (see this thread ‘Supported Stage entries’ )

    • filter objectclasses/attributes set in the Stage entry but the admin do not want to see in Active. When filling the new entry we just need to skip the no wished values/attributes.

    • add objectclasses/attributes necessary for Active entries. The new entry contains by default all required OC/Attribute, we need to pick values from the Stage entry

  • guaranty that structural objectclasses are present

  • It is most simplest solution to implement.

Adjustment of DN syntax attributes

A Stage or Delete user entry may contains DN syntax attributes. Referential integrity plugin is not checking the validity of the DN in those containers, so they may contain invalid values. When an Active entry is deleted (user-del), most of the its DN syntax attributes are replaced with empty values except for manager/managedby/secretary that are preserved.

A Stage entry may contain any values in its DN syntax attributes.

When an entry becomes Active (userstage-activate or user-undel) the values of DN syntax attributes need to be checked. The value is preserved if it is the DN of an Active entry, else it is replaced with an empty value. (see this thread)

Update StageUser#

  1. Support engineer uses standard FreeIPA calls to modify user attributes (including password)

    ipa stageuser-mod tuser --phone=123456789

  2. ipa stageuser-mod supports the same options as user-mod, but more control are done when updating a stage user.

    1. manager must be an active user

    2. nsaccountlock can not be set. Its value is forced to be True by a COS

Delete StageUser#

  1. Support engineer deletes the stage user using the following CLI

    ipa stageuser-del <user identifier>

  2. stageuser-del triggers LDAP delete operation on LDAP stage entry that deletes it permanently

Restore StageUser#

``Support engineer can restore a Delete user (under cn=deletedusers,cn=accounts,cn=provisioning,SUFFIX). Delete user contains properties of a former user. If some of the properties are corrupted, it may be not acceptable to ``\ ```restoreandactivate`` <http://www.freeipa.org/page/V4/User_Life-Cycle_Management#Restore_Deleted_User>`__\ `` a Delete user. Stepping the entry into Stage allows to keep valid properties and update the corrupted ones before making the user Active.``
  1. Support engineer restore the user using the following CLI

    ipa stageuser-add –from-preserved

Find StageUser#

  1. authenticate user can find an Stage account with

    ipa stageuser-find [] []

  2. ipa stageuser-find supports the same options as user-find except the flag –preserved=<true|false because stageuser-find only deal with Stage accounts (not Delete or Active)

ipa stageuser-find
---------------
2 users matched
---------------
  User login: kau1
  Home directory: /home/kau1
  UID: 181818
  GID: 181818
  Password: True
  Kerberos keys available: False

  User login: xy2
  First name: x
  Last name: y
  Home directory: /home/xy2
  Login shell: /bin/sh
  Email address: xy2@domain.com
  UID: -1
  GID: -1
  Password: False
  Kerberos keys available: False
----------------------------
Number of entries returned 2
----------------------------

Show StageUser#

  1. authenticate user can show an Stage account (entry uid=LOGIN,cn=staged users,cn=accounts,cn=provisioning,$SUFFIX)

    ipa stageuser-show <LOGIN>

user plugin#

Add an active user#

  • Support Engineer has permission to add active users using the following FreeIPA CLI : ipa user-add <user_identifier> –first=<first name> –last=<last name>

    ipa user-add tuser  --first=test --last=user
    
  • provisioning systems has not the permission to add active user (they are only allowed to add Stage entries)

  • if needed, command may specify more details about the user

    ipa user-add  tuser --first=Test --last=User  --manager=muser --phone 123456789
    
  • if password is specfies, to allow FreeIPA generate Kerberos keys, the following modifications occur

    • add krbprincipalaux objectclass and krbPrincipalName attribute

    • When the entry will be added FreeIPA plugin generates krbPrincipalKey, krbLastPwdChange and krbPasswordExpiration which will allow the user to authenticate by Kerberos

  • The active user entry looks like

dn: uid=test_user, cn=staged users,cn=accounts,cn=provisioning,$SUFFIX
objectClass: top
objectClass: person
objectClass: organizationalperson
objectClass: inetorgperson
objectClass: inetuser
objectClass: posixaccount
objectClass: krbprincipalaux
objectClass: krbticketpolicyaux
objectClass: ipaobject
objectClass: ipasshuser
objectClass: ipaSshGroupOfPubKeys
homeDirectory: /home/tuser
uidNumber: 646400009
gidNumber: 646400009
ipaUniqueID: 3f1b5cce-e1b8-11e3-86fe-001a4a104ecd
nsAccountLock: yes
uid: test_user
cn: first last
sn: last
givenName: first
gecos: first last
displayName: first last
loginShell: /bin/sh
mail: test_user@domain.com
krbPrincipalName: test_user@domain.com
initials: tu

Assign Group Memberships (already available)#

  1. Support engineer uses standard FreeIPA calls to assign membership

    ipa group-add-member testgroup --user tuser

  2. This command is only available on ‘Active’ entries. When a ‘Stage’ entry containing memberOf attribute is Activate, the memberOf attribute is not preserved and membershift is recomputed .

Update User (already available)#

  1. Support engineer uses standard FreeIPA calls to modify user attributes (including password)

    ipa user-mod tuser --phone=123456789

  2. Regular user uses standard FreeIPA CLI calls to modify its own entry (including password)

  3. Standard FreeIPA CLI does not allow to modify

    :* ipaUniqueID

    :* objectclass

  4. When updating DN syntax attributes (like –manager option) , if the entry is not an Active entry the modification fails.

Change Password (already available)#

  1. Support engineer uses standard FreeIPA calls to change user password:

    ipa passwd tuser

  2. Regular user uses same CLI to modify the password of its own entry

Delete User#

Once activated a user is fully managed by freeIPA. If the user leaves the company, his account can be permanently removed (deleting the ldap entry) or moved (modrdn) to a ‘Delete’ container (cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX) in order to preserve it.

ipa user-del tuser [[--no-preserve][--preserve]]

Option –no-preserve and –preserve are mutually exclusive. The default option is –no-preserve. A configuration attribute could decide what is the default option (see global policy)TBD

If the entry was preserved (moved to Delete container), it can be deleted (permanently) with the same command.

Both Active/Delete containers are under uid attribute uniqueness. So for a give value val, it exists either uid=val,cn=accounts,$SUFFIX or uid=val,cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX. So when the Support engineer decides to delete a user, he does not need to specify if the user is in Delete or Active state.

  1. delete (Permanently) of an active entry

    1. This is done by a direct ldap delete of the entry.

    2. all references to the entry are removed. That is done by referential integrity and memberof that scope Active containers.

  2. delete (preserve) of an active entry

    1. removes credential attributes userPassword and kerberors keys (krbPrincipalKey, krbLastPwdChange and krbPasswordExpiration) attributes to prevent any chance of using that entry to bind to LDAP server

    2. save manager/managedby/secretary that may get cleared when the entry will be moved to Delete container

    3. LDAP MODRDN operation on LDAP entry to move the entry (discussed 1 and 2 and 3)

      Source: cn=users,cn=accounts,SUFFIX Destination: cn=deleted users,cn=accounts,cn=provisioning,SUFFIX

      1. all references to the entry must be removed. That is done by referential integrity and memberof that only scope Active containers.

    4. Replace others existing DN syntax attributes with an Empty

      1. DN syntax attributes contains reference to entries. When the user entry is in Delete container, it is no longer in the scope of integrity plugin and then may contain invalid values (Note: is it usefull ? attribute covered by RI have been cleared on MODRDN, attribute not covered may be checked during activation rather than clearing them)

      2. removing the attribute may not be possible if it is required by the schema. So the attribute will be kept with an Empty value.

    5. restore manager/managedby/secretary with the original values

      1. if later the entry is activated or restored, the value of those attributes will be checked.

    6. Some attributes are preserved, so that a corrupted active entry can get deleted/staged/activate and keep its previous settings

      1. ipaUniqueID

      2. uidNumber

      3. gidNumber

      4. passwordHistory

  3. delete (Permanently) of a Delete entry

    1. This is done by a direct ldap delete of the entry.

Restore Deleted User#

Once activated a user is fully managed by freeIPA. If the user leaves the company, his account is moved to a ‘Delete’ Status and is hold in a separated container (cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX). Both Active/Delete containers are under uid attribute uniqueness. So for a give value val, if the entry was delelte (uid=val,cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX) it does not exists uid=val,cn=accounts,$SUFFIX.

Once deleted a user entry still contains some properties that are specific to the former user. The user account may becomes Active again,

  1. Support engineer call the following command

    ipa user-undel tuser

  2. user-undel triggers LDAP MODRDN operation on LDAP entry to move the entry (appropriate aci allows only support engineer to move the entry)

    Source: cn=deleted users,cn=accounts,cn=provisioning,SUFFIX Destination: cn=users,cn=accounts,SUFFIX DS plugin will recompute the memberbship attributes and will add nsAccountLock: True

  3. There is ajustments of DN syntax attributes

Lock User (already available)#

  1. Support engineer uses standard FreeIPA call:

    ipa user-disable tuser

  2. nsAccountLock operation attribute is put to TRUE, user cannot bind to LDAP. Membership and password attributes are preserved

  3. Only Active account can be locked/disabled

Unlock User (already available)#

  1. Support engineer uses standard FreeIPA call:

    ipa user-enable tuser

  2. nsAccountLock operation attribute is put to FALSE, user operation is restored

  3. Only Active account can be unlocked/enabled

Find User#

  1. authenticate user can find an Active account (Active container cn=users,cn=accounts,$SUFFIX) with

    ipa user-find [] []

  2. a new flag –preserved=true is used to find the entries from the Delete container (cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX)

  3. by default or if the flag is –preserved=false it only lookup into the Active container

In addition if the retrieved entry is preserved it displays a flag: Preserved user: True

prompt> ipa user-find --preserved=true
--------------
1 user matched
--------------
  User login: xy2
  First name: x
  Last name: y
  Home directory: /home/xy2
  Login shell: /bin/sh
  Email address: xy2@domain.com
  UID: 1337000003
  GID: 1337000003
  Account disabled: True
  Preserved user: True
  Password: False
  Kerberos keys available: False
----------------------------
Number of entries returned 1
----------------------------

Show User#

  1. authenticate user can show an Active account (entry uid=LOGIN,cn=users,cn=accounts,$SUFFIX)

    ipa user-show <LOGIN> []

  2. This command can retrieve Active or Deleted account. If the returned account is delete account, it displays a flag: Preserved user: True

prompt> ipa user-show xy2
  User login: xy2
  First name: x
  Last name: y
  Home directory: /home/xy2
  Login shell: /bin/sh
  Email address: xy2@domain.com
  UID: 1337000003
  GID: 1337000003
  Account disabled: True
  Preserved user: True
  Password: False
  Kerberos keys available: False

Placeholders#

When an entry is created using FreeIPA CLI user-add, the value of the required attributes need to be specify somewhere. Usually it is provided using the CLI options or if absent CLI uses some default values.

A provisioning system when creating an entry needs to provide all required attribute or to modify the CLI to adapt the default values. That is not really flexible.

In addition with User Life Cycle, an entry will follow a workflow that means that some require attribute value may be unknown at some point of the flow and defined later. If a new plugin is developed to generate the value, it requires to adapt CLI options/default value.

Instead of that we will use placeholders. A placeholder is added to the entry and contains an initial value (waiting for its final value to be set). A placeholder is couple attribute/value that defines the default value of a given attribute. The placeholders definitions will be stored under the FreeiPa configuration under the following entries:

# placeholders for ADD entries
dn: cn=placeholders,cn=ipaConfig,cn=etc,$SUFFIX
cn: placeholders
objectClass: top
objectClass: extensibleObject

# placeholders for ADDed entries in staging
dn: cn=stage,cn=placeholders,cn=ipaConfig,cn=etc,$SUFFIX
cn: stage
objectClass: top
objectClass: extensibleObject
<attrname>: <value>
...

#placeholders for ADDed entries in active
dn: cn=active,cn=placeholders,cn=ipaConfig,cn=etc,$SUFFIX
cn: active
objectClass: top
objectClass: extensibleObject
<attrname>: <value>
...

Syntax#

attribute name is : ALPHA *(ALPHA / DIGIT / HYPHEN)

The value of the placeholder may be used in different attribute types with different syntaxes, they should follow the most restrictive syntax. In case of LDAP, it should follow Printable String syntax (also see RFC 4517):

PrintableCharacter = ALPHA / DIGIT / SQUOTE / LPAREN / RPAREN /
                                PLUS / COMMA / HYPHEN / DOT / EQUALS /
                                SLASH / COLON / QUESTION / SPACE
PrintableString    = 1*PrintableCharacter

Mechanism#

When creating an entry, the CLI picks up all definitions found in the placeholders (of the container) and add them to the entry. There is no modification of the value from what is in the placeholder definition.

An exception is if the placeholder value starts and finishes with ‘ ? ‘, then CLI strip ‘ ? ‘ from the value before adding it (i.e. placeholder value is ‘?autogenerate?’ -> added value is ‘autogenerate’).

Priority#

When an entry is created the attribute value is taken in the following order:

  • CLI option

  • placeholder

  • CLI default value

That means that if the attribute value is defined as a CLI option it selects it and the possible values in placeholder or default value are ignored. Else if the placeholder attribute exists in the placeholders entry it selects the placeholder value and the possible default value is ignored. Else it selects the default values.

Limitation - Future enhancement#

A placeholder allows an entry to conform the schema. In that purpose it is sufficient to define a single value for a required attribute. If a placeholder defines multiple values for an attribute, there is no guaranty that all the values will be added in the entry.

As futur enhancement, we can imagine a placeholder being defined with: homeDirectory: /home/net/%{uid}. In that case for user ‘uid=tuser’, the added value for homeDirectory will be /home/net/tuser

Staging container#

Staging tree#

Core part of the feature is to allow provisioning system to add or delete users with standard LDAP protocol without a need to understand or use FreeIPA API. Standard tree of active FreeIPA users (cn=users,cn=accounts,$SUFFIX) is not used to avoid collisions or misinterpretation of active and staged users by other IdM systems.

Staging tree should have the following structure:

  • SUFFIX

    • cn=provisioning

      • cn=accounts

        • cn=staged users: new staged users

Staging Users in a Special Database#

Stage user container is separated from the Active container. A question is to store the containers in separated database or keep them in the same database protected by special ACIs. Both approaches have pros and cons.

Pros

  • Is naturally separated from standard FreeIPA objects, no need to re-configure existing plugins (like attribute uniqueness or memberOf plugin) to ignore users in the staging area

  • Easier management in heterogeneous environment when some FreeIPA replicas have the feature and and some does not

Cons

  • Increased maintenance burden with multiple LDAP databases

  • Increased maintenance burden with replication agreements of the new database

Staging Users in a Normal Suffix (preferred)#

Pros

  • IdM systems are kept idempotent - command to activate a user or moving it to deleted users tree can be done against any FreeIPA server.

  • No need to manage new databases or replication agreements

Cons

  • Staging or deleted users container may interfere with normal users in the cn=users,cn=accounts,$SUFFIX in older FreeIPA replicas. Even though the tree is not visible by standard users due to ACIs, it is still visible by plugins.

  • during upgrade from a old instance, the Staging/deleted containers will be created if they do not already exists. The use of COS to disable potential already existing stage/deleted entry will prevent to authenticate with them.

  • Running in a topology with different versions, will require that the ACI, containers are replicated

Stage placeholders#

The placeholders for the staging container are:

# placeholders for ADD entries
dn: cn=placeholders,cn=ipaConfig,cn=etc,$SUFFIX
cn: placeholders
objectClass: top
objectClass: extensibleObject

# placeholders for ADDed entries in staging
dn: cn=stage,cn=placeholders,cn=ipaConfig,cn=etc,$SUFFIX
cn: stage
objectClass: top
objectClass: extensibleObject
uidNumber: -1
gidNumber: -1
ipaUniqueId: ?autogenerate?
nsAccountLock: yes

Stage entry requirements#

This container can contain entries coming from

  • external provisioning systems

  • stageuser CLI (stageuser-add)

  • Delete entries

The common requirements from these origins are

  • entry must conform the schema

  • Entry RDN attribute is ‘ uid ‘ (see Supported Staged entries)

  • entry is disabled (i.e. contains operational attribute ‘nsAccountLock: True’)

  • ipaUniqueID is set to autogenerate. This requirement is not enforced for provisioning systems (but for stageuser CLI) but if an entry have a different value its value will be reset during activation of the Stage entry (stageuser-activate). (see ipaUniqueID reset)

Example of Stage entry (provisioning origin)#

In addition to the common requirements above, the entry may contains any objectclasses/attributes

Example of Stage entry (stageuser-add)#

A staged entry created with FreeIPA CLI is looking like the following:

dn: uid=test_user, cn=staged users,cn=accounts,cn=provisioning,$SUFFIX
objectClass: top
objectClass: person
objectClass: organizationalperson
objectClass: inetorgperson
objectClass: inetuser
objectClass: posixaccount
objectClass: krbprincipalaux
objectClass: krbticketpolicyaux
objectClass: ipaobject
objectClass: ipasshuser
objectClass: ipaSshGroupOfPubKeys
homeDirectory: /home/tuser
uidNumber: -1
gidNumber: -1
ipaUniqueID: autogenerate
nsAccountLock: yes
uid: test_user
cn: first last
sn: last
givenName: first
gecos: first last
displayName: first last
loginShell: /bin/sh
mail: test_user@domain.com
krbPrincipalName: test_user@domain.com
initials: tu

In case CLI option/placeholder do not define them, the entries in staging will contains those default values:

  • uid: generated from first letter of cn and sn

  • givenName: generated from cn by removing the last part of the name

  • displayName: copied from cn

  • initials: first letter of cn, first letter of sn

  • homeDirectory: default value defined in FreeIPA configuration

  • gecos: copied from cn

  • loginShell: default value defined in FreeIPA configuration

  • mail: generated from uid and default domain defined in FreeIPA configuration

  • krbPrincipalName: generate from uid and kerberos realm defined in FreeIPA configuration

The way those values are generated is hardcoded in the CLI core.

Example of Stage entry (stageuser-undel)#

A staged entry that is created from a former Delete entry mainly differs from an entry created by stageuser-add because the following attributes:

  • uidNumber (with value different from -1)

  • gidNumber (with value different from -1)

  • ipaUniqueID (with value different from autogenerate)

dn: uid=test_user, cn=staged users,cn=accounts,cn=provisioning,$SUFFIX
objectClass: top
objectClass: person
objectClass: organizationalperson
objectClass: inetorgperson
objectClass: inetuser
objectClass: posixaccount
objectClass: krbprincipalaux
objectClass: krbticketpolicyaux
objectClass: ipaobject
objectClass: ipasshuser
objectClass: ipaSshGroupOfPubKeys
homeDirectory: /home/tuser
uidNumber: 646400009
gidNumber: 646400009
ipaUniqueID: 3f1b5cce-e1b8-11e3-86fe-001a4a104ecd
nsAccountLock: yes
uid: test_user
cn: first last
sn: last
givenName: first
gecos: first last
displayName: first last
loginShell: /bin/sh
mail: test_user@domain.com
krbPrincipalName: test_user@domain.com
initials: tu

Active container#

Active tree#

Active entries are under cn=users,cn=accounts,SUFFIX

Active Placeholders#

The placeholders for the Active container are:

# placeholders for ADD entries
dn: cn=placeholders,cn=ipaConfig,cn=etc,$SUFFIX
cn: placeholders
objectClass: top
objectClass: extensibleObject

# placeholders for ADDed active entries
dn: cn=active,cn=placeholders,cn=ipaConfig,cn=etc,$SUFFIX
cn: active
objectClass: top
objectClass: extensibleObject
uidNumber: -1
gidNumber: -1
ipaUniqueId: ?autogenerate?
  • uidNumber: value generated by FreeIPA DNA plugin, based on the defined UID range of the server

  • gidNumber: copied from uidNumber

  • ipaUniqueId(final value generated by FreeIPA IPA UUID plugin)

Active entry requirements#

The requirements for active entries are

  • entry must conform the schema

  • entry RDN is uid

  • entry is enabled (nsAccountLock: False or absent)

  • entry is a objectclass: posixAccount and contains the following required attributes

    • uidNumber (final value generated by FreeIPA DNA plugin)

    • gidNumber (final value generated by FreeIPA DNA plugin)

    • ipaUniqueId (final value generated by FreeIPA IPA UUID plugin)

    • homeDirectory (generated from default FeeIPA configuration cn=ipaConfig,cn=etc,$SUFFIX)

    • uid/cn (generated from the CLI)

Example of Active entry (user-add)#

The freeipa CLI creates an entry like:

dn: uid=test_user, cn=users,cn=accounts,SUFFIX
objectClass: top
objectClass: person
objectClass: organizationalperson
objectClass: inetorgperson
objectClass: inetuser
objectClass: posixaccount
objectClass: krbprincipalaux
objectClass: krbticketpolicyaux
objectClass: ipaobject
objectClass: ipasshuser
objectClass: ipaSshGroupOfPubKeys
homeDirectory: /home/tuser
uidNumber: 646400009
gidNumber: 646400009
ipaUniqueID: 3f1b5cce-e1b8-11e3-86fe-001a4a104ecd
nsAccountLock: yes
uid: test_user
cn: first last
sn: last
givenName: first
gecos: first last
displayName: first last
loginShell: /bin/sh
mail: test_user@domain.com
krbPrincipalName: test_user@domain.com
initials: tu
memberOf: cn=ipausers,cn=groups,cn=accounts,SUFFIX

Delete container#

Delete tree#

Delete entries are under cn=deleted users,cn=accounts,cn=provisioning, SUFFIX

Delete placeholders#

N/A No entry are added in the Delete container

Delete entry requirements#

A Delete entry was create with user-del and conform the following requirements

  • entry must conform the schema

  • entry RDN is uid

  • entry is disabled (nsAccountLock: True)

  • entry is a objectclass: posixAccount and contains the at least the following required attributes

    • uidNumber (value different from -1)

    • gidNumber (value different from -1)

    • ipaUniqueId (value different from autogenerate)

    • homeDirectory

    • uid

    • cn

  • entry has no ‘memberof’ attribute

Example of Delete entry#

A entry in Delete container is looking like

dn: uid=test_user, cn=deleted users,cn=accounts,cn=provisioning,SUFFIX
objectClass: top
objectClass: person
objectClass: organizationalperson
objectClass: inetorgperson
objectClass: inetuser
objectClass: posixaccount
objectClass: krbprincipalaux
objectClass: krbticketpolicyaux
objectClass: ipaobject
objectClass: ipasshuser
objectClass: ipaSshGroupOfPubKeys
homeDirectory: /home/tuser
uidNumber: 646400009
gidNumber: 646400009
ipaUniqueID: 3f1b5cce-e1b8-11e3-86fe-001a4a104ecd
nsAccountLock: yes
uid: test_user
cn: first last
sn: last
givenName: first
gecos: first last
displayName: first last
loginShell: /bin/sh
mail: test_user@domain.com
krbPrincipalName: test_user@domain.com
initials: tu
nsAccountLock: True

Authentication#

Authentication is not allowed with Stage and Delete entries. Authentication can be done with simple bind or through an external mechanism (like GSSAPI).

Staging entry#

A first idea to prevent this authentication was to prevent credentials (password / krb keys) creation in both stageuser-add/stageuser-mod. But this is not enough because provisioning system can create entries with userPassword and then allow simple bind. For kerberos authentication, it requires kerberos keys that are generated from a plain text password. userPassword being stored in an hashed way, we can not generate kerberos keys from a stored password. kerberos keys need to be generated when the userPassword is set (see https://www.redhat.com/archives/freeipa-devel/2014-June/msg00462.html credential). So if a stage entry receives a userPassword then kerberos keys need to be generated as well. That means:

  • stageuser-add / staguser-mod must support –password option

  • ipa-pwd-extop DS plugin must scope Stage container.

To prevent authentication from Stage entry, we can use two methods:

  • using a COS (likely a pointer COS), that overwrite the nsAccountLock operational attribute.nsAccountLockis added to anActiveentry when we need to disable (user-disable) it. It prevents simple bind as well as kerberos authentication. It is quite easy to implement (likely in the.updates’’ files). A drawback is to use a DS opertional attribute to do this.

  • using a pre-op DS plugin, that would reject bind (simple or SASL) on Stage and Delete containers. It is a bit more complex solution and requires a new deliverable.

The COS solution will be use because it seems good enough without major drawback

Active entry#

Authentication is allowed with an Active entry (as long as it owns credential).

If this is a newly activated (stageuser-activate) entry it owns credentials (userpassword/krb) at the condition userPassword was set in the staging area. To activate such entry it requires a change in ipa-pwd-extop to relax the setting of pre-hashed password.

If this is a newly undelete (“user-undelete”) entry, credentials have been removed. So it is not possible to authenticate with it before the userPassword (user-mod –password) is set (and krb keys generated).

If this is a True new user (user-add), it is possible to authenticate with it at the condition it has userPassword and kerberos keys

Delete entry#

Authentication is not allowed with Delete entry. Delete entries are kept for legal or regulation reasons but they may become Active (user-undelete) or Stage (stageuser-add) again. In that case we do not want to preserve any credential because they are likely too old and we want the user to assign again new credential.

So when deleting (user-delete) an Active entry, kerberos keys must be cleared. Password attribute must be cleared as well at the exception of passwordHistory. passwordHistory will prevent the user to reuse one of password it used when the entry was Active.

Permissions and ACIs#

New permissions should be created:

  • Add Staged Users

  • Delete Staged Users

  • Modify Staged Users

  • Read Staged Users

  • Discard Deleted Users

  • Modify Deleted Users

  • Read Deleted Users

Add Deleted Users permission is needed as this operation would be done by new DS plugin.

New privilege should be created:

  • Staged User Administrators: should contain all permissions listed above

  • Staged User Provisioning: should contain Add Staged Users permission

Following roles should be updated:

  • User Administrator: should contain Staged User Administrators privilege

Allow Moving Staged Users Only#

We cannot distinguish a situation when a new user is added and when a user is moved (copied) from staged or deleted tree. Both require add access control on cn=staged users, cn=accounts,cn=provisioning,SUFFIX tree. It is therefore difficult to allow helpdesk people only moving an entry from staged tree and not allowing creating a new random user.

The stageuser-activate command selects a stage user and “move” it to the active container. The stage user attributes/values may be not appropriated to because a true operational active user. The command prepares a new user entry, taking the existing values from the stage user and the check them, fills the required (for active user) values that are missing from the stage entry. So the “helpdesk” people will not move entry but always create new user from one the example stored in the staging container.

User life cycle do not “move” entries (LDAP moddn) but create valid user and delete stage user/preserved user.

Moving Users from Staging Tree Automatically#

By default, new staged users are moved to active user area manually, by running a specified user-add command. However, some deployments may want to active users automatically. This operation should be done periodically using a custom script run on one chosen server (to prevent race unexpected conditions when more servers are activating staged users).

Proposed Script Workflow#

  • kinit as a special user (with keytab)

  • With user-find, search for all staged users

  • For each new staged user:

    • Activate user with user-add, log result

Affected Directory Server Plugins#

Active FreeIPA plugins that are active in any user-related operation need to be checked or updated, to avoid interference with users in staged or deleted tree, namely:

DNA plugin#

This plugin is reponsible to update uidNumber and gidNumber attribute. If those attributes have a predefined value (dnaMagicRegen: -1), then the plugin generate a new value and replace -1 value with it. This plugin should not update values of Stage and Delete entries. so DNA plugin should exclude cn=provisioning,SUFFIX (relies on 47828) from its scope set to:

dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
...
dnaScope: $SUFFIX
dnaExcludeScope: cn=provisioning,$SUFFIX
dnaMagicRegen: -1
dnaFilter: (|(objectClass=posixAccount)(objectClass=posixGroup)(objectClass=ipaIDobject))

The following possibilities were evaluated but did not work:

  • dnaScope: cn=accounts,$SUFFIX. This is not possible because freeipa trust requires cn=trusts,SUFFIX (see trusted domains)

  • dnaFilter: (&(|(objectClass=posixAccount)(objectClass=posixGroup)(objectClass=ipaIDobject))(!(entrydn=*cn=provisioning)))*. This is not possible because entrydn is not present in the added entry when the DNA preop-plugin is called (see filter entrydn)

  • trusts domain is sharing the same DS config entry for cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config (because it needs the same IPA range). So having a different DNA config entry (i.e. “cn=Trust IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config’’ is not an option)

krbPrincipalName uniqueness#

This plugin is reponsible to enforce the uniqueness of an krbPrincipalName value in Active and Delete containers. So that a given value of krbPrincipalName is unique in both Delete and Active containers together

This is important the krbPrincipalName remains unique as for regulation, law or policy we need to be able to uniquely identify a user (Active or not) with his krbPrincipalName

Active and Delete containers are under separated subtrees (see attribute uniqueness). In order to check simultaneous (requires 47823) both container the plugin configuration contains:

dn: cn=krbPrincipalName uniqueness,cn=plugins,cn=config
...
nsslapd-pluginAllSubtrees: on
nsslapd-pluginAttributeName: krbPrincipalName
nsslapd-pluginContainerScope: cn=accounts,SUFFIX
nsslapd-pluginContainerScope: cn=deleted users,cn=accounts,cn=provisioning,SUFFIX
uniqueness-across-all-subtrees: on

krbCanonicalName uniqueness#

For the same reasons as krbPrincipalName, we apply the following configuration

dn: cn=krbCanonicalName uniqueness,cn=plugins,cn=config
...
nsslapd-pluginAllSubtrees: on
nsslapd-pluginAttributeName: krbCanonicalName
nsslapd-pluginContainerScope: cn=accounts,SUFFIX
nsslapd-pluginContainerScope: cn=deleted users,cn=accounts,cn=provisioning,SUFFIX
uniqueness-across-all-subtrees: on

uid uniqueness#

For the same reasons as krbPrincipalName, we apply the following configuration

nsslapd-pluginAllSubtrees: on
nsslapd-pluginAttributeName: uid
nsslapd-pluginContainerScope: cn=accounts,SUFFIX
nsslapd-pluginContainerScope: cn=deleted users,cn=accounts,cn=provisioning,SUFFIX
uniqueness-across-all-subtrees: on

ipaUniqueID uniquness#

For the same reasons as krbPrincipalName, we apply the following configuration

dn: cn=ipaUniqueID uniqueness,cn=plugins,cn=config
...
nsslapd-pluginAllSubtrees: on
nsslapd-pluginAttributeName: ipaUniqueID
nsslapd-pluginContainerScope: cn=accounts,SUFFIX
nsslapd-pluginContainerScope: cn=deleted users,cn=accounts,cn=provisioning,SUFFIX
uniqueness-across-all-subtrees: on

Stage container is not part of the scope because first provisioning system can set any values and stageuser-add CLI creates entries with the same value autogenerate

Referential integrity#

This plugin scopes Active account (nsslapd-pluginContainerScope and nsslapd-pluginEntryScope). To correctly update the reference in entries it requires that an Active account (A) refers only Active accounts (B) (This is a requirement enforced during stageuser-active, user-undel, user-mod, user-add). If it follow that requirements then:

  • entry B is deleted (LDAP DEL) => entry A is updated removing B DN

  • entry B is moved (MODRDN) in Active container => entry A is updated with the new DN

  • entry B is moved (MODRDN) out of Active container (user-del) => entry A is updated removing B DN

If an Active account does not follow this requirement, Active account A refers an external entry B ( in Stage or Delete or elsewhere), then the entry A may get corrupted

  • entry B is deleted (LDAP DEL) => entry A is NOT modified

  • entry B is moved (MODRDN) in Active container => entry A is updated with the new B DN

  • entry B is moved (MODRDN) out of Active container => entry A is NOT modified

The configuration of this plugin is :

dn: cn=referential integrity postoperation,cn=plugins,cn=config
...
nsslapd-pluginContainerScope: cn=accounts,SUFFIX
nsslapd-pluginEntryScope: cn=accounts,SUFFIX

MemberOf plugin#

MemberOf plugins excludes Active and Delete containers that are both under cn=provisioning,SUFFX (config attribute memberofentryscopeexcludesubtree). Like described in referential integrity if an Active account is member of a group and the account is deleted

  • RI remove the (member) account from the group

  • MemberOf plugin removes memberof from the account for the group

the configuration of this plugin is:

dn: cn=MemberOf Plugin,cn=plugins,cn=config
..
memberofentryscope: SUFFIX
memberofentryscopeexcludesubtree: cn=provisioning,SUFFIX

Managed Entries plugin#

When a new Active entry is created (ADD or MODRDN), it creates a managed entry and adds mepManagedEntry to the entry. When an Active entry is deleted (MODRDN or DEL), the managed entry is removed and mepManagedEntry

So configuration of that

dn: cn=NGP Definition,cn=Definitions,cn=Managed Entries,cn=etc,SUFFIX
...
originscope: cn=hostgroups,cn=accounts,SUFFIX

dn: cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,SUFFIX
...
originscope: cn=users,cn=accounts,SUFFIX

When a stage entry is created/deleted it is not in under originscope, so no managed entry is added/delete. This is the expected behaviour. When a stage entry is activated, it is deleted from the stage container and added into the Active container. When it is added to the Active container, it falls under the scope of mep plugin and its managed entry is created. Here again this is the expected behavior.

When an Active entry is deleted (permanently (del) or move (modrdn) from the Active container), its associated managed entry is deleted. This is the expected behavior.

In conclusion, the current configuration of the mep plugin does not need to be change because of user life cycle.

IPA UUID plugin#

This plugin excludes Stage and Delete entries (ipaUuidExcludeSubtee) from generation of ipaUniqueID (if the current value is autogenerate (ipauuidmagicregen)). Delete entries (user-del) will keep the value of ipaUniqueID.

The configuration of that plugin is

dn: cn=IPA Unique IDs,cn=IPA UUID,cn=plugins,cn=config
...
ipaUuidExcludeSubtree: cn=provisioning,SUFFIX

Schema Compatibility plugin#

should not be affected as it is already focused on cn=users, cn=accounts, SUFFIX tree only TBC

IPA MODRDN plugin#

This plugin make sure that a targetattribute (krbPrincipaLName) is composed of a sourceattribute (RDN) (uid) and a given suffix. For example uid=foo,cn=accounts,SUFFIX will have krbPrincipalName: foo@.

Scoping the plugin to the full SUFFIX mean that Stage and Delete entries will be updated if the sourceattribute is modified. It is not strictly necessary, but it makes sense that any provisioning entry (even Stage) conforms the same rules as Active.

So this plugin scope will not be restricted to Active entries but to the full SUFFIX.

ipa-kdb#

Stage and Delete entries should not contain valid kerberos keys. Now to be sure Stage or Delete are not used for kerberos authentication, ipa-kdb should ignore users in staged or deleted

ipa-pwd-extop#

This plugin should scope Stage and Active containers. In fact both Stage and Active container may receive userpassword (see authenticate) This plugin should allow the storing of pre-hashed password ipa-pwd-extop:ipapwd_pre_add must relax its control for example if the krb keys already exists in the entry (see user-activate)

Future enhancements#

Deletion of active user#

When using the FreeIPA CLI user-del, the entry is moved (MODRDN) from the Active container to the Delete container. If the authorized person, issue LDAP DEL (outside of FreeIPA framework) on an active user the entry will be deleted permanently from the database and its properties lost. It could be interesting to implement a new preop DS plugin, which would intercept the LDAP delete operation and move the Active entry to the Delete container.

Implementation#

http://www.freeipa.org/page/V3/User_Life-Cycle_Management/Implementation Implementation details still need to be defined. Consider this section as a work in progress.

FreeIPA tickets#

  • #3911: [RFE] Allow managing users add/modify/delete via LDAP client

  • #3813: [RFE] Provide user lifecycle managment capabilities

  • #4675: [RFE] prevent newly activated user to be immediatly in the configured automember groups

389 Directory Server tickets#

Scoping of plugins#

  • #47527: Allow referential integrity suffixes to be configurable (fixed 1.3.2.8)

  • #47621: make referential integrity configuration more flexible (exclude subtree) (fixed 1.3.2.9)

  • #47525: Allow memberOf to use an alternate config area (fixed 1.3.3)

  • #47526: Allow memberOf suffixes to be configurable (fixed 1.3.2.8)

  • #47829: memberof scope: allow to exclude subtrees (fixed 1.3.3)

  • #47828: DNA scope: allow to exlude some subtrees

others#

  • #47529: Automember plug-in should treat MODRDN operations as ADD operations (fixed 1.3.3)

  • #47553: Enhance ACIs to have more control over MODRDN operations (fixed 1.3.3)

  • #47823: Enforce attribute uniqueness accross all the scoped subtrees (fixed 1.3.3)

Feature Management#

UI

When user provisioning is enabled, add new tab to Identity section - Staged Users. There should be 2 user sections:

  • List of staged users. Ability to make the staged user active

  • List of deleted users. Ability to make the deleted user active and move either to staged or active users area.

In IPA Server section, Configuration tab, there should be a new section User Life-Cycle Management with configuration options described in section #Major configuration options and enablement.

CLI

user-add#

  • New option --from-staged=tuser: activates user specified by it’s primary key in the staged tree

  • New option --to-staged: creates a new user in the staging tree

  • New option --staged-pkey=uid: optional, defines alternative primary key of the staged user. uid is the default

  • New option --from-deleted=tuser: specifies primary key of the deleted user to be activated

user-find#

  • New option --staged: lists staged users instead of active users

  • New option --deleted: lists deleted users instead of active users

user_provisioning_is_enabled#

Returns TRUE if cn=provisioning exists. Will be used by Web UI to find out if the feature is enabled or not.

config-mod#

Major configuration options and enablement#

Following global user configuration options should be implemented:

  • ipaStagedUserNumericMagic: placeholder for generation of user value for numeric attribute types. Default is -1

  • ipaStageDeletedUser: move deleted users to deleted users tree instead of deleting them permanently. Default is FALSE

Replication#

cn=provisioning subtree should be replicated.

Given number of affected plugin configuration described in section #Affected Directory Server Plugins we should consider moving configuration of some of these plugins from cn=config to replicated tree to enable easier changes in the configuration.

Attribute uniqueness will scope Active and Delete containers. In order to prevent replication issue, all activation (stageuser-activate) of user account should be done on the same server.

Updates and Upgrades#

Feature should not be enabled by default, but after running a configuration script ipa-advanced-provisioning-install. The script should:

  1. Check if all replicas are of the current FreeIPA version. If not, it should end with error stating that the feature may have negative impact on the older FreeIPA versions. There should be a --force option to overcome this limitation.

  2. When check is successful or --force flag is used:

    1. Create cn=provisioning structure

    2. Add new schema and config options

    3. Add new ACIs, permissions, privileges and roles

    4. Add new Directory Server plugins

    5. Restart Directory Server

Heterogeneous Environment#

If there is an environment with FreeIPA servers supporting the feature and olded FreeIPA servers, there may be issues with the life-cycle management, like:

  • When user delete operation is run against an older FreeIPA server, it is not copied to deleted users tree

  • Staged or deleted users in cn=provisioning tree may interfere with older FreeIPA and it’s DS plugins.

External Impact#

Changes in 389 Directory Server and slapi-nis packages will be required.

How to Test#

External Provisioning System#

Adding New User#

In following example, we will simulate adding new Stage User by provisioning system using the standard inetorgperson objectclass, without using any FreeIPA specific attribute.

Add Stage User with ldapmodify:

# ldapmodify -Y GSSAPI
SASL/GSSAPI authentication started
SASL username: admin@RHEL72
SASL SSF: 56
SASL data security layer installed.
dn: uid=stageuser,cn=staged users,cn=accounts,cn=provisioning,dc=rhel72
changetype: add
objectClass: top
objectClass: inetorgperson
cn: Stage
sn: User

adding new entry "uid=stageuser,cn=staged users,cn=accounts,cn=provisioning,dc=rhel72"

Show it’s all attributes (see that the account is explicitly disabled by nsaccountlock attribute):

# ipa stageuser-show stageuser --all --raw
  dn: uid=stageuser,cn=staged users,cn=accounts,cn=provisioning,dc=rhel72
  uid: stageuser
  sn: User
  cn: Stage
  has_password: FALSE
  has_keytab: FALSE
  nsaccountlock: TRUE
  objectClass: top
  objectClass: inetorgperson
  objectClass: organizationalPerson
  objectClass: person

Activate the Stage User (may be also done by other admin, with System: Add Users permission):

# ipa stageuser-activate stageuser
------------------------------
Stage user stageuser activated
------------------------------
  User login: stageuser
  First name: Stage
  Last name: User
  Full name: Stage
  Home directory: /home/stageuser
  Login shell: /bin/sh
  Kerberos principal: stageuser@RHEL72
  UID: 626000004
  GID: 626000004

Show the resulting activated user which has all the FreeIPA specific attributes generated:

# ipa user-show stageuser --all --raw
  dn: uid=stageuser,cn=users,cn=accounts,dc=rhel72
  uid: stageuser
  givenname: Stage
  sn: User
  cn: Stage
  homedirectory: /home/stageuser
  loginshell: /bin/sh
  uidnumber: 626000004
  gidnumber: 626000004
  nsaccountlock: FALSE
  has_password: FALSE
  has_keytab: FALSE
  ipaUniqueID: 48a58be2-dc67-11e5-b93e-001a4a23140a
  krbPrincipalName: stageuser@RHEL72
  memberof: cn=ipausers,cn=groups,cn=accounts,dc=rhel72
  mepManagedEntry: cn=stageuser,cn=groups,cn=accounts,dc=rhel72
  objectClass: ipaobject
  objectClass: person
  objectClass: top
  objectClass: ipasshuser
  objectClass: inetorgperson
  objectClass: organizationalperson
  objectClass: krbticketpolicyaux
  objectClass: krbprincipalaux
  objectClass: inetuser
  objectClass: posixaccount
  objectClass: ipaSshGroupOfPubKeys
  objectClass: mepOriginEntry

Activating Users Automatically#

Alternatively, if the Provisioning System does not have any means of calling the API operation and you do not want to do it manually, you can also setup a cron call (example for Fedora) that would periodically kinit with a keytab of a service allowed to add users, search for staged users and activating them.

Original situation:

# ipa stageuser-find
---------------
2 users matched
---------------
  User login: bar
  First name: bar
  Last name: bar
  Home directory: /home/bar
  Login shell: /bin/sh
  Email address: bar@rhel72.test
  UID: -1
  GID: -1
  Password: False
  Kerberos keys available: False

  User login: foo
  First name: foo
  Last name: bar
  Home directory: /home/foo
  Login shell: /bin/sh
  Email address: foo@rhel72.test
  UID: -1
  GID: -1
  Password: False
  Kerberos keys available: False
----------------------------
Number of entries returned 2
----------------------------

The automated activation task example that can be used in cron script:

# kinit -kt service.keytab activator/ipa.provisioning.system.rhel72.test
# for x in `ipa stageuser-find | grep "User login:" | cut -d":" -f 2`; do
    ipa stageuser-activate $x;
done
------------------------
Stage user bar activated
------------------------
  User login: bar
  First name: bar
  Last name: bar
  Full name: bar bar
  Display name: bar bar
  Initials: bb
  Home directory: /home/bar
  GECOS: bar bar
  Login shell: /bin/sh
  Kerberos principal: bar@RHEL72
  Email address: bar@rhel72.test
  UID: 626000005
  GID: 626000005
------------------------
Stage user foo activated
------------------------
  User login: foo
  First name: foo
  Last name: bar
  Full name: foo bar
  Display name: foo bar
  Initials: fb
  Home directory: /home/foo
  GECOS: foo bar
  Login shell: /bin/sh
  Kerberos principal: foo@RHEL72
  Email address: foo@rhel72.test
  UID: 626000006
  GID: 626000006

Deleting a User#

When a user account is deleted permanently, Provisioning System should simply issue LDAP DEL operation. When the user account is to be preserved, it just needs to be moved to specific container.

Preserving a user can be done with CLI/API call:

# ipa user-find
...
  User login: fbar
  First name: Foo
  Last name: Bar
  Home directory: /home/fbar
  Login shell: /bin/sh
  Email address: foo@rhel72.test
  UID: 626000001
  GID: 626000001
  Account disabled: False
  Password: True
  Kerberos keys available: True

  User login: stageuser
  First name: Stage
  Last name: User
  Home directory: /home/stageuser
  Login shell: /bin/sh
  UID: 626000004
  GID: 626000004
  Account disabled: False
  Password: False
  Kerberos keys available: False
  ...
# ipa user-del fbar --preserve
-------------------
Deleted user "fbar"
-------------------
# ipa user-find --preserved=1
--------------
1 user matched
--------------
  User login: fbar
  First name: Foo
  Last name: Bar
  Home directory: /home/fbar
  Login shell: /bin/sh
  Email address: foo@rhel72.test
  UID: 626000001
  GID: 626000001
  Account disabled: True
  Preserved user: True
  Password: False
  Kerberos keys available: False
----------------------------
Number of entries returned 1
----------------------------

The preserved user is automatically disabled and can no longer authenticate.

Second option is to preserve the user via LDAP MODRDN command directly:

# ldapmodify -Y GSSAPI
SASL/GSSAPI authentication started
SASL username: admin@RHEL72
SASL SSF: 56
SASL data security layer installed.
dn: uid=stageuser,cn=users,cn=accounts,dc=rhel72
changetype: modrdn
newrdn: uid=stageuser
deleteoldrdn: 0
newsuperior: cn=deleted users,cn=accounts,cn=provisioning,dc=rhel72

modifying rdn of entry "uid=stageuser,cn=users,cn=accounts,dc=rhel72"

# ipa user-find --preserved=1
---------------
2 users matched
---------------
  User login: fbar
  First name: Foo
  Last name: Bar
  Home directory: /home/fbar
  Login shell: /bin/sh
  Email address: foo@rhel72.test
  UID: 626000001
  GID: 626000001
  Account disabled: True
  Preserved user: True
  Password: False
  Kerberos keys available: False

  User login: stageuser
  First name: Stage
  Last name: User
  Home directory: /home/stageuser
  Login shell: /bin/sh
  UID: 626000004
  GID: 626000004
  Account disabled: True
  Preserved user: True
  Password: False
  Kerberos keys available: False
----------------------------
Number of entries returned 2
----------------------------

Privilege Separation for Employee Entry and Activation#

In following example, we will simulate adding a user in 2 steps. First, adding a Stage User by a Helpdesk administrator without a permission to add active users and second activating the user by Security Administrator.

First, Stage User is added (System: Add Stage User permission is sufficient for that operation):

# ipa stageuser-add barbar --first Bar --last Bar
-------------------------
Added stage user "barbar"
-------------------------
  User login: barbar
  First name: Bar
  Last name: Bar
  Full name: Bar Bar
  Display name: Bar Bar
  Initials: BB
  Home directory: /home/barbar
  GECOS: Bar Bar
  Login shell: /bin/sh
  Kerberos principal: barbar@RHEL72
  Email address: barbar@rhel72.test
  UID: -1
  GID: -1
  Password: False
  Kerberos keys available: False

The user is already created with all FreeIPA specific attributes. UID and GID are not generated yet:

# ipa stageuser-show barbar --all --raw
  dn: uid=barbar,cn=staged users,cn=accounts,cn=provisioning,dc=rhel72
  uid: barbar
  givenname: Bar
  sn: Bar
  cn: Bar Bar
  initials: BB
  homedirectory: /home/barbar
  gecos: Bar Bar
  loginshell: /bin/sh
  mail: barbar@rhel72.test
  uidnumber: -1
  gidnumber: -1
  has_password: FALSE
  has_keytab: FALSE
  description: __no_upg__
  displayName: Bar Bar
  ipaUniqueID: autogenerate
  krbPrincipalName: barbar@RHEL72
  nsaccountlock: TRUE
  objectClass: ipaobject
  objectClass: person
  objectClass: top
  objectClass: ipasshuser
  objectClass: inetorgperson
  objectClass: organizationalperson
  objectClass: krbticketpolicyaux
  objectClass: krbprincipalaux
  objectClass: inetuser
  objectClass: posixaccount
  objectClass: ipaSshGroupOfPubKeys

Activate the Stage User (System: Add Users permission is required):

# ipa stageuser-activate barbar
---------------------------
Stage user barbar activated
---------------------------
  User login: barbar
  First name: Bar
  Last name: Bar
  Full name: Bar Bar
  Display name: Bar Bar
  Initials: BB
  Home directory: /home/barbar
  GECOS: Bar Bar
  Login shell: /bin/sh
  Kerberos principal: barbar@RHEL72
  Email address: barbar@rhel72.test
  UID: 626000003
  GID: 626000003

See that the user has all the FreeIPA attributes including UID and GID generated:

# ipa user-show barbar --all --raw
  dn: uid=barbar,cn=users,cn=accounts,dc=rhel72
  uid: barbar
  givenname: Bar
  sn: Bar
  cn: Bar Bar
  initials: BB
  homedirectory: /home/barbar
  gecos: Bar Bar
  loginshell: /bin/sh
  mail: barbar@rhel72.test
  uidnumber: 626000003
  gidnumber: 626000003
  nsaccountlock: FALSE
  has_password: FALSE
  has_keytab: FALSE
  displayName: Bar Bar
  ipaUniqueID: 9d5dddca-dc66-11e5-b542-001a4a23140a
  krbPrincipalName: barbar@RHEL72
  memberof: cn=ipausers,cn=groups,cn=accounts,dc=rhel72
  mepManagedEntry: cn=barbar,cn=groups,cn=accounts,dc=rhel72
  objectClass: ipasshgroupofpubkeys
  objectClass: ipaobject
  objectClass: person
  objectClass: top
  objectClass: ipasshuser
  objectClass: inetorgperson
  objectClass: organizationalperson
  objectClass: krbticketpolicyaux
  objectClass: krbprincipalaux
  objectClass: inetuser
  objectClass: posixaccount
  objectClass: mepOriginEntry

Test Plan#

See Unit tests plan