Keystone/Federation/TempUserCreation/Blueprint

Temporary User Creation in a Federated Keystone
Version 1.2. 11 April 2013

1.	Introduction
In a standard centrally managed Keystone environment users are managed by an administrator of the Keystone service and are created manually via the Keystone REST API. However, in a federated environment, the Keystone Identity service for Openstack Cloud services does not have access to the available users as the external Identity Provider(s) (IdPs) manage them. Therefore, in order to achieve a fully federated Keystone installation it is necessary to implement a mechanism for automatically creating the internal Keystone user entries after external IdPs successfully authenticate the users. After authentication, external IdPs provide Keystone with a set of identity attributes for the user e.g. as a SAML assertion. An attribute mapping service allows Keystone to assign the correct privileges to these users (as roles, projects, domains etc. collectively called the authz attributes in this document) according to the identity attributes provided by the external IdP. This document describes the design and workflow of such a mechanism. It is based on creating a temporary user in Keystone, whose lifespan is based on that of the IdP’s identity assertion.

2.	Initial Assumptions
We assume that user authentication against an external IdP is available, such as that described in the federation blueprint, and that after authentication Keystone is provided with an assertion by the IdP that contains the following information: We also assume that IdPs are stored in the existing Keystone Service Catalog as described in here. The final assumption is that for ease of implementation, higher level utility APIs are available for retrieving a user’s authz attributes using a single API call with a parameter of a list of identity attributes as described here. Because a temporary user entry is created in Keystone’s database, this means that the UUID returned by Keystone on entry creation would normally be different each time the same federated user accesses OpenStack, so that the UUID could not be used in access control lists. This problem is addressed here.
 * Some sort of unique user name or identifier (UNUNID) that uniquely identifies the subject of the assertion. The type and location of this data in the IdP’s assertion will be federation protocol specific (the type might be configured as extra data in the Service Catalog service endpoint entry of the authenticating IdP). It might be the same or different for the same user in different assertions (note that it could be a random number but in this case the user ID cannot be used to authorize the user in service ACLs). The protocol specific code will handle extraction of this identifier and return its value. It will be used by Keystone to uniquely identify the user.
 * A set of type and value paired identity attributes which will be used to authorize the authenticated user. This set should be consistent and repeatable in multiple assertions.
 * A date which defines the maximum validity time of the assertion.

3. FIM Controller
In this design document, the FIM Controller is the module responsible for orchestrating the validation of the IdP’s assertion and creating the temporary user entry in Keystone’s databases. (In the implementation the FIM Controller is the federated.FederatedAuthentication module.)

3.1 Identifying Users
The first stage in this mechanism is to identify the user and to create a temporary user entry within Keystone, which is valid only for the current session. In order to minimize the redundancy of data stored in the Keystone backend, a validity time should be stored alongside each temporary user entry. At each call of the FIM controller’s user creation module, the stored temporary users should be queried and any expired users deleted. In order to maintain current functionality a blank value for validity time will denote a permanent user.

Each federation protocol has its own specific credential validation service (usually a module with the name of the protocol) that validates the IdP’s assertion and returns three parameters: the UNUNID, the set of identity attributes, and the validity time.

The UNUNID is extracted from the returned values and is used as the username for this temporary user entry; its value is not important and is just used by services managed by Keystone to retrieve the user’s authz attributes (role, project and domain assignment information) during authorization. Note that we have modified the Keystone code that issues tokens to ensure that the token’s validity time does not exceed that of the temporary user entry.

The workflow for temporary user entry creation is as follows:
 * 1) Call the protocol specific module to validate the IdP’s assertion in a protocol specific way.
 * 2) It returns the UNUNID, identity attributes and validity time from the assertion.
 * 3) Call the user management module. If a user entry with the UNUNID already exists, then update the validity time to match the latest value, else create a new temporary user entry with a name and UUID created from the UNUNID and a validity time of the returned value. The UNUNID is hashed using SHA1 to create a 20 byte string, then converted into a 40 hexadecimal string.
 * 4) In order to create a user entry a password is required. Also the Token API requires that both the username and password are presented for token creation. Consequently, a strong random password is generated during initialization of the Keystone server, and held in memory (only). This is then used for all the temporary users’ passwords. The password is generated as follows: a randomly generated number of size 128 bits is created, concatenated with the current system timestamp in milliseconds, reduced to 20 bytes by using the SHA1 algorithm, then base 64 encoded to produce a 28 character password.  This is stored in memory and is lost when the system is stopped. It is important to note that any existing tokens created using the federated middleware will be invalidated at restart time if the user authenticates again, as a new password will have been created. It is a built in mechanism of Keystone user management to invalidate existing tokens when a user’s password is changed.
 * 5) It returns the new user details. The username and password will subsequently be used to authenticate on behalf of the federated user and retrieve an unscoped token after attribute mapping has been performed.

3.2 Assigning Authz Attributes to Users according to Attribute Mappings
The second stage is to perform the attribute mapping in order to add the user’s authz attributes to the user’s entry. For each attribute mapping that matches a subset of the user’s identity attributes, a set of authz attributes is returned. Each authz attribute set is assigned to the user independently of the other matched sets. There are currently three types of authz attributes in the Openstack service: Roles, Projects and Domains. There are no constraints in the attribute mapping code as to the mapping of these authz attributes from identity attributes, even if some of the mappings may not give the user any OpenStack privileges. However, mappings which do not conform to the current limitations in Keystone will necessarily have to be ignored by the FIM Controller (for now anyway, until the restrictions in Keystone are removed).

Roles alone are currently meaningless in Keystone for authz purposes and must be assigned on a project. There is currently no mechanism for assigning roles to users without the context of a project. This means an authz attribute set containing only OpenStack roles will grant no privileges to the user, and consequently will be ignored by the FIM Controller. Projects alone can be assigned to users, though whether they grant any privileges or not will be determined by the service. These will not be ignored by the FIM Controller.

Both roles and projects are domain specific in the V3 API. However, the concept of a default domain is available and as such, a set containing only roles and projects, or projects alone, will be assigned to the user under this default domain (automatically by the existing Keystone code).

With these constraints in mind, authz attribute assignment within an authz attribute set should conform to the following rules:
 * A set comprising roles, projects and domains: each role should be assigned to the user on each project under each domain;
 * A set comprising roles and projects only: each role should be assigned to the user on each project under the default domain;
 * A set comprising projects and domains is ignored;
 * A set containing only projects is ignored;
 * A set containing only roles is ignored;
 * A set containing only domains is ignored.

With these rules in mind, the following workflow should be followed:


 * 1) Retrieve all the existing authz attributes assigned to the user (oldAuthz list). For a new user the list will be empty, but for a returning user it will contain those mapped from his previous identity attributes.
 * 2) For each authz attribute set:
 * 3) If the set contains 1 or more domains:
 * 4) 	For each domain (D) in the set
 * 5)        For each role (R) in the set
 * 6)        Assign role (R) under domain (D)
 * 7)        Remove from oldAuthz list (if present).
 * 8) 	For each project (P) in the set
 * 9)  If set contains 1 or more domains AND project's domain does not match any of these domains:
 * 10) Skip this project
 * 11) Else:
 * 12) 	For each role (R) in the set
 * 13) 	Assign role (R) to user under project (P).
 * 14)      Remove from oldAuthz list (if present).
 * 15) Any attributes remaining in the oldAuthz set are no longer valid so remove them.

Examples
The examples assume an environment with three mappings set up in Keystone as follows.

Mapping 1

Identity Attributes: accountType=Staff

Authz Attributes: role=Admin, role = User, project=myProject

Mapping 2

Identity Attributes: organization=University of Kent

Authz Attributes: role=Member, project=myProject, domain=Kent

Mapping 3

Identity Attributes: organization=University of Kent, department=Computing

Authz Attributes: role=developer, project=computingProject,	domain=KentComputing

Example 1
User Identity Attributes:	accountType=Staff, 	organization=University of Kent

Returned Authz Attribute Sets: {role : Admin, User; project : myProject},  {role : Member,  project : myProject, domain : Kent}

Resulting Assignments:
 * User is assigned role: Admin on project: myProject under default domain
 * User is assigned role: User on project: myProject under default domain
 * User is assigned role: Member on project: myProject under domain: Kent

Example 2
User Identity Attributes:	accountType=Student,	organization=University of Kent

Returned Authz Attribute Sets: {role : Member, project : myProject, domain : Kent}

Resulting Assignments:
 * User is assigned role: Member on project: myProject under domain: Kent

Example 3
User Identity Attributes:	department=Computing,	organization=University of Kent

Returned Authz Attribute Sets: {role : developer, project : computingProject, domain : KentComputing}, {role : Member,  project : myProject, domain : Kent}

Resulting Assignments:
 * User is assigned role: Member on project: myProject under domain: Kent
 * User is assigned role: developer on project: computingProject under domain: KentComputing