- Introduction
- Authentication and authorization
- Entitlement service API
- Managed Planning Data Foundation user groups
The Entitlements service is used to enable authorization in the Managed Planning Data Foundation. A group name defines a permission. Users who are added to that group obtain that permission. The main motivation for the Entitlements service is data authorization, but the functionality enables three use cases:
- Data groups used for data authorization. For example: data.welldb.viewers, data.welldb.owners
- Service groups used for service authorization. For example: service.storage.user, service.storage.admin
- User groups used for hierarchical grouping of user and service identities. For example: users.datalake.viewers, users.datalake.editors
For each group you can either be added as an OWNER or a MEMBER. The only difference between these groups is that an OWNER of a group can manage the members of that group.
All group identifiers (emails)are of the form {groupType}.{serviceName|resourceName}.{permission}@{partition}.{domain} with:
- groupType ∈ {'data', 'service', 'users'}
- serviceName ∈ {'storage', 'search', 'entitlements', ...}
- resourceName ∈ {'welldb', 'npd', 'ihs', 'datalake', 'public', ...}
- permission ∈ {'viewers', 'editors', 'admins' ...}
- data-partition-id ∈ {'opendes', 'slb-osdu-qual', ...}
- domain ∈ {'enterprisedata.slb.com', ...}
As shown, a group is unique to each data partition. This means that access is defined on a per data partition basis. In other words, giving a service permission in one data partition does not give that user service permission in another data partition. See below for more information on data partitions.
A group naming convention has been adopted as a best practice, such that the group's name should start with the word "data." for data groups, "service." for service groups, and "users." for user groups. The group's name is case-insensitive. Refer to Group creation guidelines under the API section for more details.
The Managed Planning Data Foundation is a multi-partition solution with two layers of isolation: data partition isolation and data access isolation. A data partition represents a strong separation of all data between clients. Data access isolation is achieved with a dedicated ACL (access control list) per object within a given data partition.
All groups and permissions are unique at the data partition level, meaning that granting permissions in one data partition has no effect on any other data partitions.
The group named users contains all the identities that are allowed access to the data partition in question. When a contract is created, we create the corresponding data partition in the Managed Planning Data Foundation, and all user identities are added to the users group of the corresponding data partition.
To deal with data partitions and to be able to track user identities, the Managed Planning Data Foundation introduces two headers:
- data-partition-id - This required header for all Managed Planning Data Foundation APIs is used to determine the data partition context for the call.
- correlation-id - This optional header for all Managed Planning Data Foundation APIs is used to trace the API call. If the correlation-id value is provided in the request, the same value is used in the response. If no correlation-id header is provided, then the Entitlements service generates a GUID for this field in the response.
@delfiserviceaccount.com to the client ID, the client ID can be onboarded the same way as with the regular users from the portal. For example, clientid@delfiserviceaccount.com would be the email address to use for onboarding the client ID.clientid@delfiserviceaccount.com to a department or user group in the billing account that is associated with the desired data partition, such as DepartmentA.Use the Add member API to add the account without the domain suffix. For example:
curl --request POST \
--url '/groups/service.example.viewers@opendes.enterprisedata.slb.com/members' \
--header 'authorization: Bearer <JWT>' \
--header 'content-type: application/json' \
--header 'data-partition-id: opendes' \
--data '{
"email": "clientid",
"role": "MEMBER"
}'A client ID can be granted data access in the same way as a regular user.
The Schlumberger Authenticator token is required when calling the Entitlements APIs.
Service or client IDs need to be onboarded to a data partition for authorization. See How to onboard and grant data access to Client IDs.
The Entitlements service requires users or services to have the following authorization to access the APIs. The following authorization is automatically granted to users when they are onboarded. For new users, authorization is granted instantly. For existing users, changes to the contract or department are reflected immediately.
- Valid data partition member - The Entitlements service checks whether the member ID from the Authorization header consisting of a JWT belongs to users@{data-partition-id}.{domain}, where the {data-partition-id} information is received from the data-partition-id header.
- Valid entitlements service user - The Entitlements service checks whether the member ID from the Authorization header consisting of a JWT belongs to service.entitlements.user@{data-partition-id}.{domain}, where the {data-partition-id} information is received the from data-partition-id header.
Service authorization is used to establish if a service calling another service has proper permission to invoke the service. This means that the requesting service must provide the JWT to identify itself to the Managed Planning Data Foundation API it is calling. This token should be provided in the Authorization header. Specifically, if a service wants to call another service, that service must provide a valid OSDU Data Authenticator token for the service account it uses to identify itself to the Managed Planning Data Foundation API it is calling.
In each data partition that the service is used, the group corresponding to the permission that the service supports should be created. For example, given a service named "my_service", where user and admin permissions are desired, then groups called service.my_service.user and service.my_service.admin should be created in all relevant data partitions. How to name the service permission groups is entirely up to the service team, as long as the mapping of the service groups and the user permission groups like user.datalake.viewers, users.datalake.editors, and users.datalake.admins are done properly.
To authorize access to your service, your service must call the Entitlements service GET /groups API by providing its JWT in the Authorization header and required data partition identifier in the Data-Partition-Id header.
The Entitlements service will return all the groups of your service if:
- the service account is a member of the specified data partition.
- the service account is a member of the service.entitlements.user group in the specified data partition.
If one of the above conditions is not met, the Entitlements service will return an Unauthorized error. On success, the calling service can inspect the returned groups to determine if the required group (for example, service.my_service.user) is returned, and depending on result, can authorize access.
After your service has authorization, the data authorization will use the Entitlements group on the data. Refer to Managed Planning Data Foundation user groups to see which permission your service has in relation to the Storage service. The Storage service calls the Entitlements API to determine if the user has access to the record. Refer to Storage service to learn about how to use an ACL in the record structure.
Data access can be granted to a user, including a service account, or a group by adding it to a data group using the Add member API.
Note:
- If the member is a group, then all members of the group will have the same data access.
- If the member is a client, then the "email" is only the "clientid" (the username without the @ and the domain).
For example:
curl --request POST \
--url '/groups/data.example.viewers@opendes.enterprisedata.slb.com/members' \
--header 'authorization: Bearer <JWT>' \
--header 'content-type: application/json' \
--header 'data-partition-id: opendes' \
--data '{
"email": SomeUserID@opendes.enterprisedata.slb.com",
"role": "MEMBER"
}'The current API is V2.
| Entitlements V2 |
|---|
| An identity can belong to up to 5000 unique groups per partition. |
| Each data partition can have a maximum of 5000 user + data groups. |
Because the write APIs listed above now behave asynchronously, the response codes for these APIs to indicate a success has changed from 200 OK to 202 Accept for some cases.- Add Member API: 200 OK.- Remove Member API: 204 No Content.- Create Group API: 201 Created. |
| Eventual consistency after write operations. The write APIs in the Entitlements service that this affects are Add Member, Remove Member, and Create Group. |
| Editing default groups and associations needed by the Managed Planning Data Foundation core is not allowed. You will receive an error message if you attempt to do so explaining that this operation is not supported. |
What happens when a user reaches the group quota limit? A user can delete groups that they have previously created by using Entitlements V2's new Delete Group API.
All the APIs can be found here.
| URL |
|---|
| /api/entitlements/v2 |
For all APIs, the identity of the calling user or service is extracted from the JWT (email claim) in the Authorization header for the data partition provided in the data-partition-id header. All APIs require the authorization specified here.
GET /groups - Retrieves all the groups for the user or service caller. This API provides a flat list of the groups, including all hierarchical groups, that the user belongs to. Optional query parameter 'roleRequired' when passed gives the additional information of a user's Role in the groups he's part of. If not passed, by default this is set to false.
curl --request GET \ --url '/groups?roleRequired=true' \ --header 'authorization: Bearer <JWT>' \ --header 'content-type: application/json' \ --header 'data-partition-id: opendes'
POST /groups - Creates the group within the data partition provided in the data-partition-id header. This API creates a group with the following email {name}@{data-partition-id}.{domain}, where {data-partition-id} is received from the Data-Partition_Id header. The caller of this API is made OWNER of the created group.
- Data groups are used for data authorization. For example: data.{resourceName}.{permission}@{data-partition-id}.{domain}
- Service groups are used for service authorization. For example: service.{serviceName}.{permission}@{data-partition-id}.{domain}
- User groups are used for hierarchical grouping of user and service identities. For example: users.{serviceName}.{permission}@{data-partition-id}.{domain}
Entitlements service creates the groups with all lowercase, even if the input has mixed case.
curl --request POST \ --url '/groups' \ --header 'authorization: Bearer <JWT>' \ --header 'content-type: application/json' \ --header 'data-partition-id: opendes' \ --data '{ "name": "service.example.viewers", "description": "This is an service group for an example service which has viewer permission." }'
UPDATE /groups/{group_email} - Updates the group with an email group_email within the data partition provided in the data-partition-id header.
Users need to provide list of update operations, each of which must contain op(operation type), path, and value. The currently supported operation is "replace" and currently supported paths are "/name" and "/appIds".
curl --request PATCH \ --url '/groups' \ --header 'authorization: Bearer <JWT>' \ --header 'content-type: application/json' \ --header 'data-partition-id: opendes' \ --data '[ { "path": "/name", "value": ["service.example.viewers"], "op":"replace" }, { "path": "/appIds", "value": ["app1", "app2"], "op": "replace" } ]'
GET /members/{member_email}/groups - Retrieves all the groups on behalf of the given member within the data partition provided in the data-partition-id header. For example, the member_email value is member@{domain}. A query parameter type can be specified to filter groups by type: DATA, SERVICE, USER, or NONE. Type 'NONE' lists all the types of groups in the response. The default value of type is NONE. The query parameter appid can be specified to filter the groups by the application ID value. Appid is only relevant if an application-level permission is applied to groups. Using the appid filter, the user discovers which groups belong to that application and the given member's permissions in that application. This API lists all the groups on behalf of the given member.
curl --request GET \ --url '/members/member@domain.com/groups?type=NONE' \ --header 'authorization: Bearer <JWT>' \ --header 'content-type: application/json' \ --header 'data-partition-id: opendes'
GET /groups/{group_email}/members - Retrieves members that belong to a group_email within the data partition provided in the data-partition-id header. For example, the group_email value is {name}@{data-partition-id}.{domain}. A query parameter role can be specified to filter group members by role of OWNER or MEMBER. This API lists the direct members of the group, excluding hierarchical groups. When we need to get all members in the hierarchy, users must implement their own recursive function. The "includeType=true" query parameter could be useful to determine whether a member is a USER or GROUP. Optional query parameter 'roleRequired' when passed gives us additional parameter in the response containing the user's Role in the groups he's member of. If not passed, by default this is set to false.
curl --request GET \ --url '/groups/service.example.viewers@opendes.enterprisedata.slb.com/members?includeType=false?roleRequired=true' \ --header 'authorization: Bearer <JWT>' \ --header 'content-type: application/json' \ --header 'data-partition-id: opendes'
POST /groups/{group_email}/members - Adds members to a group with group_email within the data partition provided in the data-partition-id header. The member being added can either be a user or a group. For example, the group_email value is {name}@{data-partition-id}.{domain}. The member body must have an email and role for a member. The member role can be OWNER or MEMBER.
A user group can be a member of another user group, which is a member of a data group. The Entitlements service allows a hierarchy between user and data groups. For example: users.child.viewers is a MEMBER of users.parent.viewers, which is a MEMBER of data.example.viewers. This constitutes 3 levels of depth.
There is a feature flag
group-size-limit-enabledthat controls the maximum size of a group. When this flag is set totrue, the group size is limited to 20,000 members. The default value for the flag istrue, which means the group size limit is ON, even if the flag is not explicitly set in the partition service. This feature was implemented to prevent high latency during some group operations (list group members, add group members, delete group...). For groups with a very large number of members (>150,000), some of these operations may not be possible at all.curl --request POST \ --url '/groups/service.example.viewers@opendes.enterprisedata.slb.com/members' \ --header 'authorization: Bearer <JWT>' \ --header 'content-type: application/json' \ --header 'data-partition-id: opendes' \ --data '{ "email": "member@domain.com", "role": "MEMBER" }'
DELETE /groups/{group_email}/members - Deletes members from a group with email group_email within the data partition provided in the data-partition-id header. The member being deleted can either be a user or a group. For example, the group_email value is {name}@{data-partition-id}.{domain}. The path parameter member_email needs the email of a member.
curl --request DELETE \ --url '/groups/service.example.viewers@opendes.enterprisedata.slb.com/members/member@domain.com' \ --header 'authorization: Bearer <JWT>' \ --header 'content-type: application/json' \ --header 'data-partition-id: opendes'
DELETE /groups/{group_email} - Permanently deletes a group with an email group_email within the data partition provided in the data-partition-id header. For example, the group_email value is {group_email}@{data-partition-id}.{domain}.
This API enables the permanent deletion of groups that have been created, regardless of whether those groups have been associated to storage records. The use of this “hard” delete functionality should be limited to very well-understood situations and privileged users because improper use can lead to valid data being hidden from view by all users of the system.
Relevant use cases
This hard delete functionality is directed at addressing two main use cases:
- Cleanup of unneeded entitlements groups that have been created as a product of automated or manual testing as well as ongoing probes or health checks.
- Cleanup of data groups created by applications that are part of a larger data purge, such as for contractual compliance, or for keeping group membership counts below those enforced by Entitlements V2. Refer to Entitlements limitations.
Cleaning up groups in the latter case may not be strictly necessary from a data security perspective, but excess groups for both cases reduce the scalability of the Entitlements service, such as quotas, as well as performance.Important Note: The Entitlements service does not check whether there are associated storage records with the entitlement group being deleted. The calling application must check whether or not there are storage records associated with an entitlement group before it is deleted. If an entitlement group is deleted while it is still associated with storage records, then those records become inaccessible. This delete operation is irreversible.
Note: It takes a few seconds for the cache to be flushed after the group is deleted. So it is possible for the deleted group to still be available in the list groups response when checked immediately after the delete group operation.
curl --request DELETE \ --url '/groups/service.example.viewers@opendes.enterprisedata.slb.com' \ --header 'authorization: Bearer <JWT>' \ --header 'content-type: application/json' \ --header 'data-partition-id: opendes'
GET /entitlements/v1/groups/{group_email}/membersCount - Retrieves the count of members that belong to a group_email within the data partition provided in data-partition-id header. E.g. group_email value is {name}@{data-partition-id}.{domain}.com. Query parameter role can be specified to filter group members by role of OWNER or MEMBER. This API lists the count of direct members of the group (excluding hierarchical groups).
curl --request GET \ --url '/groups/service.example.viewers@opendes.contoso.com/membersCount?role=OWNER' \ --header 'authorization: Bearer <JWT>' \ --header 'content-type: application/json' \ --header 'data-partition-id: opendes'
- PATCH /groups/{group_email} - Updates entitlements group.
curl --request PATCH \
--url '/groups/data.test.viewers@opendes.contoso.com' \
--header 'authorization: Bearer <JWT>' \
--header 'content-type: application/json' \
--header 'data-partition-id: opendes' \
--data '{
"op": "replace",
"path": "/appIds",
"value": ["app1", "app2"]
}'Managed Planning Data Foundation user groups provide an abstraction from Managed Planning Data Foundation service level permission groups. Managed Planning Data Foundation user groups hierarchically groups the various service groups. A user or service can be directly added to the user groups to get access to various services. The following Managed Planning Data Foundation user groups exists in the Managed Planning Data Foundation in each data partition:
- users.datalake.viewers is used for viewer-level authorization for Managed Planning Data Foundation services.
- users.datalake.editors is used for viewer-level authorization for Managed Planning Data Foundation services and authorization to create the data using the Managed Planning Data Foundation storage service.
- users.datalake.admins is used for admin-level authorization for Managed Planning Data Foundation services. An account manager can grant this permission to a user from the OSDU Data portal.
Each user group has privileges that determine which Entitlements APIs it can call. See the Permissions table below for more details.
| Endpoint URL | Method | Minimum Permissions Required |
|---|---|---|
| /groups | GET | users.datalake.viewers |
| /groups | POST | users.datalake.admins |
| /groups/{group_email}/members | GET | users.datalake.viewers |
| /groups/{group_email}/members | POST | users.datalake.viewers |
| /groups/{group_email}/members/{member_email} | DELETE | users.datalake.viewers |
| /groups/{group_email} | DELETE | users.datalake.admin |