Access control in the BOD command framework

As in previous versions of WebSphere Commerce, access control checks in the BOD command framework are performed just before the business logic is executed. This framework continues to use the WebSphere Commerce PolicyManager as its default access control engine. Access control policies are still required to grant users access to commands and resources. However, the action and resource naming convention is different for the BOD command framework.

Resources that the BOD commands act upon are nouns are represented by generated Java objects. These generated Java objects do not implement the Protectable interface required by the PolicyManager. To address this requirement, a wrapper object must be implemented for each noun to extract the information required by the PolicyManager to perform authorization checks. This mapping is defined in the wc-component.xml file. For SOI name-value pair commands, before they run, a command level and a resource level authorization is performed. In the BOD command framework, only resource level access control checks are performed, except for Get requests, where Get performs an access control check on whether the request is allowed to use the specified access profile. The access profile indicates the view of the data and certain views can be limited to certain types of users. This is sufficient to check whether a user can run the command against a particular resource.

There are two assets that need to be implemented for access control for a BOD command:

  • The Protectable Proxy class that represents the noun
  • Access control policies that grant user access to the particular command.

Protectable proxy class

When the PolicyManager invokes the methods on the Protectable wrapper object, the Protectable object uses the noun to retrieve information to return the appropriate response. Although some information might be available in the noun, such as owner, the command cannot assume this information is correct. This assumption allows the access control check to pass even though it could be invalid. It is the Protectable wrapper object that understands the noun and how the information correlates to the authorization check.

This proxy class should extend from AbstractProtectableProxy class and implement the Protectable interface. The naming convention of the protectable wrapper object is as follows:


com.mycompany.commerce.facade.server.authorization.noun_typeProtectableProxy

When the protectable proxy is instantiated, the noun and the associated command context is set. The noun can be retrieved by the getObject() method and the command context can be retrieved via the getCommandContext() method. There are two methods that must be implemented for each proxy class – fulfills(Long member, String relationship) and getOwner().

The fulfills() method is used to check if a given member has the specified relationship with the resource. For example, the creator of an order. If fulfills() is not explicitly implemented, it returns "false", as of 7.0.0.1.

The getOwner() method is used to return the member owner of the resource. For example, the organization that owns the order. The owner should be retrieved from the database, or wherever it is stored. Most of the resources in WebSphere Commerce are owned by a store, and in this case, the value that is returned in this method is the organization that owns the store. If the getOwner() method is not explicitly implemented, the store owner organization is returned.
Note: The storeId should not be retrieved from the command context, because it can be changed by the client. The storeId is retrieved from the persistence layer, using the identifier of the noun. That is, since the owner of an object is typically the owner of the store that the object is in, it is not safe to take the store from the context and return the stores owner. The identifier of the object should be used to look up its owner from the database.

The protectable proxy object is registered as follows in the wc-component.xml file:

<_config:authorization-configuration>
	<_config:protectable-proxy 
		protectable="com.ibm.commerce.infrastructure.facade.server.authorization.WorkspaceTypeProtectableProxy"
		interfacename="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType"/>	
</_config:authorization-configuration>

Access control policies for Get services

There are two types of access control for Get services:

Access profile authorization
This type of access control determines if the current user, under the current context, has permission to use a particular access profile. An access profile is like a view of an object, and not all users should have permission to view the same object details. The action is based on the BOD and the access profile. The resource is the AccessProfileProtectableProxy object. The access profile is represented as the name of the service, for example, "GetCatalogEntry", followed by ".AccessProfileName", for example, ".IBM_Admin_Details".
Note: IBM_Admin_ prefixes all services intended to be used by admin/CMC based services calls. Access profiles which do not follow the new naming conventions continue to function correctly, as compatibility is maintained with earlier versions. It is recommended, however, that they are followed for existing access profiles, and when making changes to future access profiles.
In this example, the GetWorkspace service has four different access profiles for retrieving different amounts of data. The IBM_Admin_Summary and IBM_Admin_Details access profiles are being enabled for AllUsers, and the IBM_AdminDetails and IBM_Admin_All access profiles are being enabled just for WorkspaceManagers.
<Policies>

<!-- ================================== -->
<!-- My Service Module Polices.xml -->

	<!-- Registers the access profiles of the service module  -->
	<Action Name="GetWorkspace.IBM_Admin_Summary" CommandName="GetWorkspace.IBM_Admin_Summary"/>
	<Action Name="GetWorkspace.IBM_Admin_Details" CommandName="GetWorkspace.IBM_Admin_Details"/>
	<Action Name="GetWorkspace.IBM_Admin_All" CommandName="GetWorkspace.IBM_Admin_All"/>
	<Action Name="GetWorkspace.IBM_AdminDetails" CommandName="GetWorkspace.IBM_AdminDetails"/>	
	
	<!-- The default resource category for all access profiles -->
 	<ResourceCategory 
		Name="com.ibm.commerce.foundation.server.authorization.policymanager.AccessProfileResourceCategory" 
		ResourceBeanClass="com.ibm.commerce.foundation.server.authorization.policymanager.AccessProfileProtectableProxy"/>


 <!-- Grouping access profiles into user groups for access control policy registration -->
	<ActionGroup Name="Infrastructure-Workspace-AllUsers-AccessProfileActionGroup" OwnerID="RootOrganization">
		<ActionGroupAction Name="GetWorkspace.IBM_Admin_Summary"/>
		<ActionGroupAction Name="GetWorkspace.IBM_Admin_Details"/>
	</ActionGroup>
	
	<ActionGroup Name="Infrastructure-Workspace-WorkspaceManagers-AccessProfileActionGroup" OwnerID="RootOrganization">
		<ActionGroupAction Name="GetWorkspace.IBM_AdminDetails"/>
		<ActionGroupAction Name="GetWorkspace.IBM_Admin_All"/>
	</ActionGroup>
	
	<!-- Required for access profile access control registration.  -->
	<ResourceGroup Name="AccessProfileResourceGroup" OwnerID="RootOrganization">
  	<ResourceGroupResource Name="com.ibm.commerce.foundation.server.authorization.policymanager.AccessProfileResourceCategory"/>
  </ResourceGroup>
	

<!-- Defining the access control policies for the access profile grouping defined above -->
	<Policy Name="Infrastructure-Workspace-AllUsers-AccessProfilePolicy" 
		OwnerID="RootOrganization" UserGroup="AllUsers" 
		ActionGroupName="Infrastructure-Workspace-AllUsers-AccessProfileActionGroup" 
		ResourceGroupName="AccessProfileResourceGroup" PolicyType="groupableStandard"/>
	
	<Policy Name="Infrastructure-Workspace-WorkspaceManagers-AccessProfilePolicy" 
		OwnerID="RootOrganization" UserGroup="WorkspaceManagers" 
		ActionGroupName="Infrastructure-Workspace-WorkspaceManagers-AccessProfileActionGroup" 
		ResourceGroupName="AccessProfileResourceGroup" PolicyType="groupableStandard"/>
	
<!-- Defining the policy group -->
	<PolicyGroup Name="ManagementAndAdministrationPolicyGroup" OwnerID="RootOrganization">
		<PolicyGroupPolicy Name="Infrastructure-Workspace-AllUsers-AccessProfilePolicy" PolicyOwnerID="RootOrganization"/>
		<PolicyGroupPolicy Name="Infrastructure-Workspace-WorkspaceManagers-AccessProfilePolicy" PolicyOwnerID="RootOrganization"/>
	</PolicyGroup>	

</Policies>
Read result filtering
For each noun that is returned by the FetchNounCmd, a Display access control check is performed. The action is hard coded to be Display. The resource is the protectable proxy object of the returned noun. For performance reasons, it is recommended that the search includes entitlement conditions to reduce the return results. For each result where access control indicates the current user does not have Display authority on the resource, the resource is removed from the list. For example, for each noun, if the user does not have display permission, then the noun is removed from the list.
Note: Read result filtering, and the access control for read result filtering, is optional. In cases where this access control filtering is not required, it is recommended to implement the filterNouns() method on the GetNounNameCmdImpl controller. The implementation should do nothing and just return. This prevents the performance overhead of performing an access control check on the result in the cases where it is not required. This filter is needed in cases where the business logic to retrieve the business objects does not consider who has permission to view the object, yet these objects should not be displayable by everyone.
<Policies>
<!-- how to register a resource for Get access control -->
<!-- ================================================== -->
<!-- My Service Module Polices.xml -->

<!-- The action to register -->
	<Action Name="DisplayResourceAction" CommandName="Display"/>		

	<ResourceCategory Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceTypeResourceCategory" 
		ResourceBeanClass="com.ibm.commerce.infrastructure.facade.server.authorization.WorkspaceTypeProtectableProxy"/>
 
	<ActionGroup Name="DisplayResourceActionGroup" OwnerID="RootOrganization">
		<ActionGroupAction Name="DisplayResourceAction"/>
	</ActionGroup>
 
	<!-- The resource group for the noun-->
<ResourceGroup Name="Infrastructure-Workspace-ResourceGroup" OwnerID="RootOrganization">
      		<ResourceGroupResource Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceTypeResourceCategory"/>
   	</ResourceGroup>
   	

		<!-- The policy.  The creator can display the object -->
   	<Policy Name="Infrastructure-Workspace-AllUsers-CreatorPolicy" 
			OwnerID="RootOrganization" UserGroup="AllUsers" ActionGroupName="DisplayResourceActionGroup" 
			ResourceGroupName="Infrastructure-Workspace-ResourceGroup" RelationName="creator" PolicyType="groupableStandard"/>
   	
<!-- Register the policy -->
   	<PolicyGroup Name="ManagementAndAdministrationPolicyGroup" OwnerID="RootOrganization">
		<PolicyGroupPolicy Name="Infrastructure-Workspace-AllUsers-CreatorPolicy" PolicyOwnerID="RootOrganization"/>
	</PolicyGroup>

</Policies> 
Note:

Access control policies for Change and Sync services

The access control policies for Change and Sync services determine whether the current user under the current context can perform the change actions on the specified noun. The action is the actionCode in the action expression to perform. The resource is the protectable proxy object of the noun being operated on.

<Policies>
<!-- how to register a resource for Change/Sync access control -->
<!-- ================================================== -->
<!-- My Service Module Polices.xml -->

	<Action Name="ChangeResourceAction" CommandName="Change"/>

	<ResourceCategory Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceTypeResourceCategory" 
		ResourceBeanClass="com.ibm.commerce.infrastructure.facade.server.authorization.WorkspaceTypeProtectableProxy"/>
 
	<ActionGroup Name="ChangeResourceActionGroup" OwnerID="RootOrganization">
		<ActionGroupAction Name="ChangeResourceAction"/>
	</ActionGroup>
 
<!-- Resource group for the noun -->
	<ResourceGroup Name="Infrastructure-Workspace-ResourceGroup" OwnerID="RootOrganization">
  		<ResourceGroupResource Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceTypeResourceCategory"/>
  </ResourceGroup>
   	
  <Policy Name="Infrastructure-Workspace-AllUsers-CreatorPolicy" 
			OwnerID="RootOrganization" UserGroup="AllUsers" ActionGroupName="ChangeResourceActionGroup" 
			ResourceGroupName="Infrastructure-Workspace-ResourceGroup" RelationName="creator" PolicyType="groupableStandard"/>
   	
  <PolicyGroup Name="ManagementAndAdministrationPolicyGroup" OwnerID="RootOrganization">
		<PolicyGroupPolicy Name="Infrastructure-Workspace-AllUsers-CreatorPolicy" PolicyOwnerID="RootOrganization"/>
	</PolicyGroup>

</Policies>

Access control policies for Process services

The access control policies for Process services determine whether the current user has permission to execute the action on the noun. The action is the action code found in the Process verb in the BOD. The resource is the protectable proxy object of the noun being operated on.

<Policies>
<!-- how to register a resource for process access control -->
<!-- ============================================= -->
<!-- My Service Module Polices.xml -->

	<Action Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType.create" 
		CommandName="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType.create"/>
	<Action Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType.promote" 
		CommandName="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType.promote"/>
	<Action Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType.cancel" 
		CommandName="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType.cancel"/>
		
<!-- Mapping the category to the protectable proxy that represents the noun. -->
	<ResourceCategory Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceTypeResourceCategory" 
		ResourceBeanClass="com.ibm.commerce.infrastructure.facade.server.authorization.WorkspaceTypeProtectableProxy"/>
 
	<ActionGroup Name="Infrastructure-Workspace-WorkspaceManagers-ActionGroup" OwnerID="RootOrganization">
		<ActionGroupAction Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType.create"/>
		<ActionGroupAction Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType.promote"/>
		<ActionGroupAction Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceType.cancel"/>
	</ActionGroup>
 
	<ResourceGroup Name="Infrastructure-Workspace-ResourceGroup" OwnerID="RootOrganization">
      		<ResourceGroupResource Name="com.ibm.commerce.infrastructure.facade.datatypes.WorkspaceTypeResourceCategory"/>
  </ResourceGroup>
   	
 <!-- The policy. The creator of the resource and execute actions defined in the workspace managers action group.-->
 <Policy Name="Infrastructure-Workspace-WorkspaceManagers-CreatorPolicy" 
		OwnerID="RootOrganization" UserGroup="WorkspaceManagers" 
		ActionGroupName="Infrastructure-Workspace-WorkspaceManagers-ActionGroup" 
		ResourceGroupName="Infrastructure-Workspace-ResourceGroup" 
		RelationName="creator" PolicyType="groupableStandard"/>
   	
  <PolicyGroup Name="ManagementAndAdministrationPolicyGroup" OwnerID="RootOrganization">
		<PolicyGroupPolicy Name="Infrastructure-Workspace-WorkspaceManagers-CreatorPolicy" 
		PolicyOwnerID="RootOrganization"/>
	</PolicyGroup>
		
</Policies>