Cortex Authorization
Apache Shiro is a role-based access control framework (RBAC). Shiro provides a dynamic security model where roles and permissions can be configured at run time.
Role Based Access Control works by restricting the CRUD (Create Read Update Delete) operations logged in users can perform on Cortex resources. Depending on a user’s role, they may only have permission to view (Read) a resource, or they may be able to insert (Create), update, or delete data through a resource.
Resource Authorization Workflow
When Cortex receives a request with an access token, it generates a Subject
object. The subject represents the user’s log in state and contains a list of operations the user is authorized to perform.
When the request reaches the resource, the ResourceKernel
verifies the Subject
object and checks the user’s permissions. If the request has the proper permissions, the resource kernel forwards the request to the resource for processing. If the request does not have the proper permissions, a 401
or 403
status code is returned.
Roles and Permissions
Elastic Path Roles and Shiro Roles
Each Cortex API request is assigned a single Elastic Path role. An Elastic Path role is assigned to a collection of Shiro roles. A Shiro role is a granular access control that conveys a right to perform a particular business function.
Cortex determines the effective role for each request as follows:
- If the
x-ep-account-shared-id
header is set:- Read the account user association record for the specified account and signed-in user.
- Set the role based on the role value in the record.
- If the
x-ep-account-shared-id
header is not set:- Read the store record for the current scope.
- If the user is single-session, set the role based on the single-session role in the record.
- If the user is registered, set the role based on the registered role in the record.
- Ensure that permissions for account resources are defined by the association to that account, regardless of the header. While processing Cortex resource permissions, if the name of Cortex resource is contained within the
accountOverrideResourceNames
list in theep-rs-authorization-epcommerce
bundle, then perform the following steps:- Read the account GUID from the
accounts.account-id
parameter. - Read the account user association record for the account related to the account ID parameter and signed-in user. If the signed-in user is not associated to the account, read the account ancestors in order until an association is found.
- Set the role based on the role value in the record.
- Read the account GUID from the
Out of the box, Cortex supports the following Elastic Path roles:
SINGLE_SESSION_BUYER
This role is typically assigned to unauthenticated users that are not transacting on behalf of an account.
LIMITED_CATALOG_BROWSER
Shoppers with the limited catalog brower role can view the catalog, but cannot add items to any shopping cart or see product prices.
CATALOG_BROWSER
Shoppers with the catalog browser role can view the catalog, including pricing, but cannot add items to any shopping cart.
BUYER
Shoppers with the buyer role can add items to cart and checkout, but cannot modify any aspects of the accounts they are assigned to.
BUYER_ADMIN
Shoppers with the buyer admin role have full access to modify the accounts they are assigned to, including assigning new users to the account.
The following table shows the Shiro roles that are assigned to each Elastic Path role by default:
Shiro Roles | Single-session Buyer | Limited Catalog Browser | Catalog Browser | Buyer | Buyer Admin |
---|---|---|---|---|---|
PUBLIC | x | x | x | x | x |
REGISTERED | x | x | x | x | |
READ_PRICES | x | x | x | x | |
MODIFY_CARTS | x | x | x | ||
READ_CUSTOM_CARTS | x | x | |||
MODIFY_ACCOUNTS | x | ||||
MODIFY_ACCOUNT_ASSOCIATES | x | ||||
MODIFY_ACCOUNT_PAYMENT_INSTRUMENTS | x | ||||
MODIFY_ACCOUNT_ADDRESSES | x |
To customize the Elastic Path roles or the assigned Shiro Roles, update the roleToPermissionsMap
in the commerce-engine/core/ep-core/src/main/resources/spring/service/service.xml
file.
note
When defining a permission.properties
file, each Shiro role needs to be prefixed with 'relos.role.
'. Any role defined without this prefix is ignored.
There is also a special Shiro role named relos.role.OWNER
. This role applies to all shoppers. The role restricts shoppers to access only their own carts, orders, and so on. Other shoppers, who are not the OWNER
of the cart, order, and so on cannot access them. For example, carts have the following configuration: relos.role.OWNER=CREATE,READ,UPDATE,DELETE:{base.scope}:{carts.cartId}
. Only the owner of a cart, whether PUBLIC
or REGISTERED
users, can CREATE
, READ
, or UPDATE
their cart. Other shoppers, who are not the owner of the cart, do not have access to that cart.
Shiro Permissions
In Shiro, a permission defines what links or advisors appear on each Cortex resource and which HTTP verbs are permitted for each resource.
Cortex supports the following permissions:
CREATE
Specifies that the users can create new information in the resource.
READ
Specifies that the users can read from the resource.
UPDATE
Specifies that the users can update data in the resource.
DELETE
Specifies that the users can delete data from the resource.
LINK
Specifies that the users can link between certain resources.
INFO
Provides meta information on a resource. Currently supports maximum age of a resource only.
ADVISE_READ
Users may advise certain resources on a
READ
operationADVISE_CREATE
Users may advise certain resources on a
CREATE
operation.ADVISE_UPDATE
Users may advise certain resources on an
UPDATE
operation.ADVISE_DELETE
Users may advise certain resources on a
DELETE
operation
These permissions are assigned to Shiro roles within a permission.properties
file in each Cortex bundle.
Permission Parameters
Permission parameters refine permissions, allowing you to apply permissions to a specific instance of a resource. For example, the cartId
parameter restricts a user’s permissions so they only apply to the user’s own cart.
Out of the box, Cortex has the following permission parameters. The following parameters are exclusive to a resource:
Parameter | Description | Resource |
---|---|---|
addresses.address-id | The user’s address | Addresses |
carts.cart-id | The user’s cart | Carts |
emails.email-id | The user’s email | Emails |
orders.order-id | The order associated with a user’s cart | Orders |
paymentMethodId | The user’s payment method | PaymentMethods |
profiles.profile-id | The user’s profile | Profiles |
accounts.account-id | Accounts that the user is associated to | Accounts |
purchases.purchase-id | The user’s purchase | Purchases |
shipmentdetails.shipment-details-id | The user’s shipment details | ShipmentDetails |
wishlists.wishlist-id | The ID of the user’s wishlist | Wishlists |
The following parameters are available for all resources:
{base.scope}
- The scope of the store that the user belongs to
Special Parameters
In addition to the permission parameters described above, Cortex has special permission parameters to further refine your permissions:
*
A wildcard parameter. Applies the permission to all the resource’s elements and subresources.
EOL
A parameter that prevents permissions from applying to the resource’s elements and subresources.
{unauthenticated}
A parameter that prevents
REGISTERED
from inheriting this permission fromPUBLIC
.Only applicable for the registrations resource. You must manually apply this parameter when you extend or change the registrations resource
URIs and Permissions
The pattern for URIs in permissions is: :{RESOURCE-FAMILY.PARAMETER}:{URI-PART}
Where {RESOURCE-FAMILY.PARAMETER}
is the resource’s base family, and {URI-PART}
is a resource identifier, like form
. In many cases, {RESOURCE-FAMILY.PARAMETER}
is {base.scope}
. For more information on resource identifiers, see Resource Identifiers.
For example, the URI of the orders resource displays in Cortex Studio as scope/orders/
. To apply the CREATE
permission to the orders resources, do the following: relos.role.PUBLIC=CREATE:{base.scope}:{orders}:EOL
With Shiro, you can use wild cards at any point in the URI, using *
. For example: relos.role.PUBLIC=CREATE:{base.scope}:*:{orders}:EOL
The above would apply the CREATE
permission to any URI with the pattern scope/[something]/orders
, but not to scope/orders/[something]
.
note
You must add EOL
at the end of the permission string to ensure that the same permissions are not applied to the child resources within the resource. To apply changes to the child resources within the resource, add the wild character *
at the end of the permission string.
For example, to apply permissions only to a resource, use EOL
at the end of the permission string: relos.role.PUBLIC=CREATE:{base.scope}:{orders}:EOL
Configuring Roles and Permissions in a Custom Resource
After creating a custom Cortex resource, you must assign roles and permissions to restrict the operations a user can perform with the resource. You can use the available roles and permissions or any new roles and permission you created. For instructions on creating roles and permissions, see Creating Your own Roles and Permissions.
Defining Default Roles and Permissions
In your resource project’s root directory, navigate to
src/main/resources
(or for old resources navigate tosrc/main/resources/OSGI-INF/config
)With a text editor, open
permission.properties
In
permission.properties
, define your resource’s default role permissions. For information on how to define role permissions, see Assigning Permissions to a Role.
Assigning Permissions Note
When assigning your resource permissions in permission.properties
, don’t surround your permissions and parameters with double quotations. For example: relos.role.PUBLIC=LINK:*
Making Roles and Permissions Configurable During Runtime
To support the ability to configure your resource’s roles and permissions during runtime, modify your resource’s src/main/resources/spring/applicationContext-resource-server.xml
:
With a text editor, open
applicationContext-resource-server.xml
Modify the
overrideRolePermissionsProvider
bean’spersistent-id
to the name of the resource’s role and permissions configuration file.For example, in items:
For information on the role and permissions configuration file, see Modifying the Roles and Permissions of an Existing Resource.
Permission Parameter Strategies for Helix Resources
Permission parameters are configured in a Helix resource by extending the AbstractHelixModule
class, and binding PermissionParameterStrategy
to the class:
For more information, see Configuring Prototypes.
Permission Parameter Strategies for Legacy Resources
To add permission parameters to a custom legacy resource’s resource permissions, assign the parameter to a parameter strategy in the resource’s permissionParameterResolver
.
The following steps show how to add a permissionParameterResolver
to your custom resource:
With a text editor, open your resource’s
src/main/resources/spring/applicationContext-resource-server.xml
Add constructor arguments to the
permissionParameterResolver
bean to specify each parameter and its resolution strategyFor example, to define the
permissionParameterResolver
for aREAD:{base.scope}:{resourceFamilyId.resourceId}
permission:<bean name="permissionParameterResolver" class="com.elasticpath.rest.authorization.parameter.PermissionParameterResolver"> <constructor-arg> <map> <entry key="scope" value-ref="scopeParameterStrategy"/> <entry key="resourceId" value-ref="yourResourceIdParameterStrategy"/> </map> </constructor-arg> </bean>
The scopeParameterStrategy
is predefined in Cortex, but the custom yourResourceIdParameterStrategy
needs to be implemented.
Out of the box,Cortex has the following parameter types and strategies:
- Scope:
ScopeParameterStrategy
Creating Your own Roles and Permissions
Adding New Roles to the Role Hierarchy
Cortex uses a role hierarchy to enable roles to implicitly include the parent role’s access rights. Out of the box, the role hierarchy has been defined as roles=["PUBLIC","REGISTERED"]
. If you want to define or add to the Role Hierarchy, edit the roleHierarchy.config
file.
Once a new roleHierarchy.config
file is created, the API overrides the predefined role hierarchy with the hierarchy defined in the new config file.
Role hierarchy takes effect without having to restart Cortex.
To add new roles to the role hierarchy:
Create a
roleHierarchy.config
file in either the/ep/conf/cortex/permissions
or${user.home}/ep/conf/cortex/permissions
directory.Add roles starting with the lowest-level role (role with the least permissions) to highest-level role (role with the most permissions) following this format:
roles=["ROLE_LOWEST","ROLE_HIGHER",...,"ROLE_HIGHEST"]
For example, to add a new IDENTIFIED role that inherits from PUBLIC:
roles=["PUBLIC","IDENTIFIED","REGISTERED"]
Role Hierarchy
Role Hierarchy must start with the role of an unauthenticated user, eg. PUBLIC
Modifying the Roles and Permissions of an Existing Resource
Cortex resources have predefined roles and permissions. Configure an existing resource’s permissions by defining new permissions in a <Family_Name>RolePermissions.config
file. Permissions take effect without having to restart Cortex.
note
When the Cortex detects a <Family_Name>RolePermissions.config
file, the API ignores the resource’s predefined role permissions and applies only the permissions defined in the <Family_Name>RolePermissions.config
file.
Assigning Permissions to a Role
Create a
<Family_Name>RolePermissions.config
file in either the/ep/cortex/conf/permissions
or${user.home}/ep/conf/cortex/permissions
directory.To assign permissions to a role, add the role and its permissions in the following format to the resource’s
<Family_Name>RolePermissions.config
file:ROLE=ROLE_PERMISSION:{RESOURCE-FAMILY.PARAMETER}
PARAMETER
can be included optionally if you want to refine your permission to a specific instance of a resource. For a list of permission parameters supported for each out of the box resources, see Permission Parameters.
For example, to allow single session shoppers to create and read their own order, create an ordersRolePermissions
.config file in your permissions
directory and set the following role permissions:
relos.role.PUBLIC=LINK:*;CREATE,READ:{base.scope}:{orders.orderId}
`EOL` Warning
Do not surround default, EOL
and *
permission parameters with curly braces.
Empty Permission Warning
Do not assign empty permission strings to your roles. Roles with empty permission strings throw exceptions and the last known valid permissions assignment will be used.
To prevent a role from accessing your resource, use EOL
: relos.role.PUBLIC=EOL
Assigning Multiple Permissions to a Role
Role permissions are defined on a single line. To assign multiple role permissions and permission parameters, structure your permission assignment as shown:
To assign same parameter to multiple role permissions, separate permissions with commas as shown:
ROLE=ROLE_PERMISSION_1,ROLE_PERMISSION_2:{RESOURCE-FAMILY.PARAMETER}
To assign multiple parameters to the same role permissions, separate parameters with colons as shown:
ROLE=ROLE_PERMISSION:{RESOURCE-FAMILY.PARAMETER_1}:{RESOURCE-FAMILY.PARAMETER_2}
To assign different parameters to different role permissions, separate sets of role permissions and parameters with semicolons as shown:
ROLE=ROLE_PERMISSION_1:{RESOURCE-FAMILY.PARAMETER_1};ROLE_PERMISSION_2:{RESOURCE-FAMILY.PARAMETER_2}
Link
Parameters
The LINK
permission uses different permission parameters. For this permission, you specify the resources the role can link to. For example, the following LINK
permission allows only the carts and items resources to link to your resource when the shopper is not signed-in:
relos.role.PUBLIC=LINK:carts,items
Do not surround LINK
parameters with curly braces.
To permit all resources to link to your resource, use *
:
relos.role.PUBLIC=LINK:*
Advise Parameters
The following ADVISE
permissions use the same permission parameters as LINK
.
ADVISE_READ
ADVISE_CREATE
ADVISE_UPDATE
ADVISE_DELETE
For example, the following ADVISE_READ
permission allows only the carts and items resources to be advised when the shopper is not signed-in:
relos.role.PUBLIC=ADVISE_READ:carts,items
Do not surround ADVISE_*
parameters with curly braces.
To permit all resources to use any ADVISE
capability, list each of the ADVISE
operation and use *
:
relos.role.PUBLIC=ADVISE_READ:*,ADVISE_CREATE:*,ADVISE_UPDATE:*,ADVISE_DELETE:*
Configuring Role Permissions through the Felix Web Console
After creating your <Family_Name>RolePermissions.config
file, you can modify your resource’s permissions through the Apache Felix Web Console.
note
Without a <Family_Name>RolePermissions.config
file, you cannot modify your resource’s role permissions through the Felix Web Console.
To configure your permissions through the Felix Web Console:
Log into the Felix Web Console:
Navigate to
http://[server]:[port]/system/console/configMgr
. If Cortex is running locally at port8080
, the URL ishttp://localhost:8080/cortex/system/console/configMgr
.Enter the User Name and Password in the Authentication dialog box:
The default credentials are as follows:
- Username:
admin
- Password:
admin
- Username:
Set the permissions:
- Click
<Resource Name>RolePermissions
- Modify your resource’s role permissions. For information on how to define role permissions, see Assigning Permissions to a Role
- Click Save
- Click
Permissions save to the <Family_Name>RolePermissions.config
file will take effect immediately.