Implement role-based access control for internal users
This section describes the Commerce role-based access control system, and describes how you can use it to limit which internal users can access specific shopper data.
Understand property access control
There are a number of property attributes that are used to specify the behavior of the access control system. In particular, the following are the primary attributes used to control which users can read or write the value of a property:
readRole
– You can set this attribute to the ID of a role. Users with the specified role can see the property value.writeRole
– You can set this attribute to the ID of a role. Users with the specified role can set or change the property value.readAccessRight
– You can set this attribute to the ID of an access right. Users with the specified access right can see the property value.writeAccessRight
– You can set this attribute to the ID of an access right. Users with the specified access right can set or change the property value.
By default, these attributes are null for any given property, which means that any user who is logged in can see and modify the property’s value. When you set one or more of these attributes, you are actually revoking access from users who lack the specified role or access right. Note that each attribute can only be set to a single ID.
There are several additional attributes that affect how access control works. These attributes are discussed later in this chapter.
Note: Subsystems of Commerce that exchange data with external systems (for example, webhooks and bulk export and import) are not affected by property access control settings. If you want to restrict property access in these subsystems, you may need to implement access control on the external systems.
In addition, the Freemarker email templates included with Commerce are not affected by property access control settings. If you want to restrict property access in emails your store sends, you must manually remove properties from the templates. (See Customize Email Templates for more information.)
The next section describes how roles and access rights are applied to properties and users.
Understand roles and access rights
Oracle CX Commerce includes a number of roles that control access to various parts of the administration interface and the Agent Console. For example, the Catalog role grants access to the Catalog page. One or more roles can be assigned to a user in the administration interface. See Configure Internal User Accounts for more information.
You can also use roles to control which properties a user can see or edit. For
example, if you set the writeRole
attribute of a property to
adminRole
, only users with the Administrator role can set the
value of the property.
In addition to roles, Commerce can use access rights to control which properties a user can see and modify. An
access right is essentially a label that can be associated with properties and with
individual users. If a specific access right is associated with a property, only
users who have that access right are permitted access to that property. For example,
if you create an access right called ar1
, and you set the
readAccessRight
attribute of a property to
ar1
, then only users who have that access right can view the value
of the property.
Users are associated with access rights through roles. An individual role can have multiple access rights assigned to it, and an individual access right can be assigned to multiple roles. Using access rights thus provides greater flexibility than using roles alone.
A user’s ability to access properties is determined both by the roles the user has and by the access rights those roles have:
- A user has read access to a property if the user has the role that is specified by the property’s
readRole
attribute, or if the user has a role that has the access right that is specified by the property’sreadAccessRight
attribute. - A user has write access to a property if the user has the role that is specified by a property’s
writeRole
attribute, or if the user has a role that has the access right that is specified by the property’swriteAccessRight
attribute.
You should make sure that your settings for these attributes do not result in any users having write access to a property but not read access. Such a user would be able to modify the property’s values but not be able to see the changes he or she makes.
To avoid this situation, be careful when you set these attributes to ensure that the users with write access to a given property are a subset of those with read access. Here are some examples:
- If you want all users to be able to see a property’s values, but want only administrators to be able to modify the values, then you could set the
writeRole
attribute toadminRole
, and leavereadRole
null. - If you do not want any users to be able to edit the values of a property, you could set the
writeAccessRight
attribute to an access right that is not assigned to any roles (and therefore is not associated with any users). You can then usereadRole
orreadAccessRight
to assign read access as desired. - If you want a certain group of users to have read and write access to a property, but for no other users to have either form of access, you could set
writeRole
andreadRole
to the same role.
Bypass access settings for storefront shoppers
Access control can be applied to shoppers as well as to internal users. As a result, when you restrict access to specific profile properties, you may unintentionally prevent shoppers from accessing their own profile data. For example, if you allow only users who have the Administrator role to access shopper email addresses, then shoppers will not be able to see or edit their own email addresses when they view their profiles.
To avoid this issue, the following attributes can be used to enable shoppers to bypass any access restrictions on properties in their own profiles:
shopperReadable
-- Set this totrue
to bypass any role or access right security when a shopper views the property on the shopper’s own profile. Default isfalse
.shopperWriteable
-- Set this totrue
to bypass any role or access right security when a shopper edits the property on the shopper’s own profile. Default isfalse
.
Create access rights for internal users and assign them to roles
By default, Commerce does not include any access rights for internal users. If you want to use access
rights, you need to create them using the createAdminAccessRight
endpoint in the Admin API. For example:
POST /ccadmin/v1/adminAccessRights HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{
"displayName": "Access Right 1",
"name": "ar1",
"repositoryId": "ar1",
"description": "First of several access rights."
}
Once you have created an access right, you can assign it to existing roles using the
updateAdminRole
endpoint in the Admin API. For example:
PUT /ccadmin/v1/adminRoles/catalogRole HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{
"accessRights": [
{
"repositoryId": "ar1"
}
]
}
The response is similar to this:
{
"name": "Catalog",
"repositoryId": "catalogRole",
"description": "Catalog Role",
"links": [
{
"rel": "self",
"href": "http://www.example.com:7002/ccadmin/v1/adminRoles/catalogRole"
}
],
"accessRights": [
{
"displayName": "Access Right 1",
"name": "ar1",
"repositoryId": "ar1",
"description": "First of several access rights."
}
],
"category": "Commerce"
}
Create custom roles for internal users
In addition to the standard roles it includes, Commerce provides support for creating custom roles. For example, you might want to create
a role for providing access to sensitive data, and assign it to a very limited set
of users. You could then restrict access to certain properties by setting their
readRole
and writeRole
attributes to this
role. Or you could create an access right that you assign to the custom role, and
then set the readAccessRight
and writeAccessRight
attributes to this access right.
To create a custom role, use the createAdminRoles
endpoint in the Admin API. For example:
POST /ccadmin/v1/adminRoles HTTP/1.1
Authorization: Bearer <access_token>
x-ccasset-language: en
{
"name": "Auditor",
"repositoryId": "audit",
"description": "User with access to sensitive data.",
"accessRights": [
{
"repositoryId": "ar10"
}
]
}
The response is similar to this:
{
"name": "Auditor",
"repositoryId": "audit",
"description": "User with access to sensitive data.",
"links": [
{
"rel": "self",
"href": "http://www.example.com:7002/ccadmin/v1/adminRoles"
}
],
"accessRights": [
{
"displayName": "Access Right 10",
"name": "ar10",
"repositoryId": "ar10",
"description": "Controls access to very sensitive information."
}
],
"category": "Custom"
}
Note that, as shown in this example, you can create the role and assign access rights to it in the same call. Alternatively, you can create the role and later assign access rights using the updateAdminRole
endpoint, or just use the role (without access rights) to control property access.
Configure the data to return
Properties have two attributes, readSecurityLevel
and
writeSecurityLevel
, that control how Commerce responds when a user lacking the necessary role or access right attempts to
access the property.
The readSecurityLevel
attribute can be set to one of the following values:
ignore
– Return a masking value rather than the actual value of the property. IfreadSecurityLevel
is not set, it defaults toignore
.deny
– Omit the property from the response entirely. This option is available only for custom properties.
The writeSecurityLevel
attribute can be set to one of the following values:
ignore
– Attempts to modify the property value will fail silently. IfwriteSecurityLevel
is not set, it defaults toignore
.deny
– Attempts to modify the property value will result in errors. Note, however, if the user attempts to set the value to the same value that was originally returned (that is, either the current value of the property or a masking value, depending on the user’s read access), no error will result. This is to handle cases where a form populated with current values attempts to write all of those values back when it is submitted. This option is available only for custom properties.
Note that the values of these attributes have an effect only if read or write access
attributes are set on the property as well. For example, if the
readSecurityLevel
attribute is set to deny
for
a custom property, the property is omitted from a response only if read access is
restricted by the readRole
or readAccessRight
attribute, and the user does not have the specified role or access right.
Return masking values
If the value of a property’s readSecurityLevel
attribute is
ignore
, then attempts to access the property by users lacking
the necessary access right or role return a placeholder called a masking value. The
logic for determining the value is as follows:
- If the property is not required, null is returned.
- If the property is required, and its default value is set, the default value is returned. (Note that for a custom property that is required, the default value must be set.)
- If the property is required, and its default value is not set, a generic value is returned. The value depends on the data type of the property:
- String – the empty string
- Numeric value -- 0
- Date or timestamp -- Jan 1 1970
- Enumeration -- the first enumerated value
You can override this logic by explicitly specifying a placeholder value for the
property using the securityMaskingValue
attribute. For example, you
might want to set the placeholder value for strings to “XXXXX
,” to
make it clear that the actual value is being suppressed rather than empty. Note that
the securityMaskingValue
you specify must match the data type of
the property.
Set access control on properties
To set the access control attributes on specific properties, you use the endpoints
in the Admin API for modifying the item type for those properties. For example, to
configure access control on profile properties, you use the
updateShopperType
endpoint to modify the user
shopper type.
The following example illustrates setting the role and access right attributes of a property, as well as its securityMaskingValue
:
PUT /ccadmin/v1/shopperTypes/user HTTP/1.1
Authorization: Bearer <access_token>
x-ccasset-language: en
Content-Type: application/json
{
"properties": {
"lastName": {
"readRole": "audit",
"writeRole": "audit",
"readAccessRight": "ar10",
"writeAccessRight": "ar10",
"shopperReadable": true,
"shopperWriteable": true,
"securityMaskingValue": "XXXXX"
}
}
}
The response shows the attribute values you set:
...
"lastName": {
"shopperWriteable": true,
"readRole": "audit",
"readSecurityLevel": null,
"readAccessRight": "ar10",
"securityMaskingValue": "XXXXX",
"length": 254,
"shopperReadable": true,
"label": "Last Name",
"type": "shortText",
"writeSecurityLevel": null,
"writeAccessRight": "ar10",
"required": false,
"searchable": false,
"writable": true,
"internalOnly": false,
"uiEditorType": "shortText",
"default": null,
"audienceVisibility": null,
"localizable": false,
"textSearchable": false,
"writeRole": "audit",
"dimension": false,
"editableAttributes": [
"shopperWriteable",
"readRole",
"readSecurityLevel",
"readAccessRight",
"securityMaskingValue",
"shopperReadable",
"label",
"writeSecurityLevel",
"writeAccessRight",
"required",
"searchable",
"internalOnly",
"default",
"audienceVisibility",
"textSearchable",
"writeRole",
"dimension",
"multiSelect"
],
"multiSelect": null
},
...
These settings restrict both read and write access to only users that either have the
audit
role or the ar10
access right. If a user
has neither of these and attempts to view a shopper’s profile, the
lastName
property value is masked in the response. For
example:
...
"lastName": "XXXXX",
"GDPRProfileP13nConsentDate": null,
"GDPRProfileP13nConsentGranted": false,
"gender": "female",
...
Note that you should not set access-control attributes on a property that points to another object or collection of objects. Instead, set the attributes on the individual properties of the objects.
For a property that holds an array of strings or numeric values, you can set access-control attributes to specify access rights and roles, but you cannot set the securityMaskingValue
attribute.