Implementing access control in the BOD command framework

In the BOD programming model, the resources that services act upon are nouns, which are represented by generated logical SDOs. However, these SDOs do not implement the Protectable interface, which is required in order for the PolicyManager to verify that a service has the rights to work with these nouns. A wrapper class must be implemented for each noun to extract the information required by the PolicyManager to perform its checks. This mapping is defined in the wc-component.xml file.

Procedure

  1. Open HCL Commerce Developer.
  2. For each noun in your service module, create a wrapper class that implements the Protectable interface. When the PolicyManager invokes the methods on the Protectable wrapper object, the Protectable object will use the noun to retrieve information to return the appropriate response. Although some information may be available in the noun, such as owner, the command cannot assume this information is correct. This assumption will allow 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.
    1. Create a Java class in your customization project that extends from the AbstractProtectableProxy class and implements the Protectable interface. The class should follow this naming convention: com.<company name>.<component>.facade.server.authorization.<noun name>ProtectableProxy.
      Note: The skeleton of the class is generated for you, if you followed the steps in Creating an HCL Commerce service module.
    2. There are two methods that must be implemented for each proxy class, fulfills(Long member, String relationship) and getOwner().
      The following code is an example of the fulfills() method:
      	/**
      	 * This method determines if a given member fulfills a given relationship
      	 * with the resource.
      	 * 
      	 * @param member
      	 *            This is the member id of the member.
      	 * @param relationship
      	 *            This is the relationship the member has with to the resource.
      	 * @return This method will always return <code>true</code>.
      	 * @exception RemoteException
      	 * @exception Exception
      	 */
      	public boolean fulfills(Long member, String relationship)
      			throws RemoteException, Exception {
      		final String METHODNAME = "fulfills(Long, String)";
      		if (com.ibm.commerce.foundation.common.util.logging.LoggingHelper
      				.isEntryExitTraceEnabled(LOGGER)) {
      			LOGGER.entering(CLASSNAME, METHODNAME);
      			LOGGER.exiting(CLASSNAME, METHODNAME);
      		}
      
      		return super.fulfills(member, relationship);
      	}
      
      The following code is an example of the getOwner() method:
      		/**
      	 * This method will return the owner of the protectable object. If the owner
      	 * has not been specified on the proxy object, then the owner is the
      	 * owner of the store that can be resolved from the command context.
      	 * 
      	 * @return The owner of the protectable proxy.
      	 * @exception Exception
      	 *                A problem occurred while resolving the owner.
      	 * @exception RemoteException
      	 *                A problem occurred while accessing a remote resource.
      	 * @see com.ibm.commerce.security.Protectable#getOwner()
      	 */
      public Long getOwner() throws Exception, RemoteException {
      
      		final String METHODNAME = "getOwner()";
      		if (com.ibm.commerce.foundation.common.util.logging.LoggingHelper
      				.isEntryExitTraceEnabled(LOGGER)) {
      			LOGGER.entering(CLASSNAME, METHODNAME);
      		}
      		Long oOwner = null;
      		CampaignType aCampaignType = (CampaignType) getObject();
      		// We expect the storeId information in IdentifierType to be resolved
      		if (aCampaignType != null
      				&& aCampaignType.getCampaignIdentifier() != null
      				&& aCampaignType.getCampaignIdentifier()
      						.getExternalIdentifier() != null
      				&& aCampaignType.getCampaignIdentifier()
      						.getExternalIdentifier().getStoreIdentifier() != null
      				&& aCampaignType.getCampaignIdentifier()
      						.getExternalIdentifier().getStoreIdentifier()
      						.getUniqueID() != null) {
      			Integer nStoreId = new Integer(aCampaignType
      					.getCampaignIdentifier().getExternalIdentifier()
      					.getStoreIdentifier().getUniqueID());
      			if (LoggingHelper.isTraceEnabled(LOGGER)) {
      				LOGGER.logp(Level.FINE, CLASSNAME, METHODNAME, "storeId=" + nStoreId);
      			}
      			StoreAccessBean abStore = StoreRegistry.singleton().find(nStoreId);
      			if (abStore != null) {
      				oOwner = abStore.getOwner();
      			} else {
      				// this is site level
      				oOwner = super.getOwner();
      			}
      		} else {
      			oOwner = super.getOwner();
      		}
      
      		if (com.ibm.commerce.foundation.common.util.logging.LoggingHelper
      				.isEntryExitTraceEnabled(LOGGER)) {
      			LOGGER.exiting(CLASSNAME, METHODNAME);
      		}
      
      		return oOwner;
      	}
      
    3. Register the Protectable proxy class.
  3. Create the access control policy XML file, following the examples for the different types of OAGIS verbs presented in Access control in the BOD command framework
  4. Load the access control policy following the instructions in Loading access control policy definitions and other policy-related elements.