Implement property access control for internal users
There are a number of property metadata attributes that you can use to limit access to specific shopper data.
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.
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.
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.)
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
.
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 the values of access control attributes
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.