Announcement: You can find the guides for Commerce 7.5 and later on the new Elastic Path Documentation site. The Developer Center continues to support Commerce 6.13.0 through 7.4.1.Visit new site

Tutorial 7 - Integrating Cortex API with an alternate Identity Management System

Tutorial 7 - Integrating Cortex API with an alternate Identity Management System

This class explains how you could potentially swap a custom Identity Management System (IdM) with Cortex API's out-of-the-box one.

An Identity Management System manages the authentication, authorization, roles and privilege of each customer across systems and enterprises. Out of the box, Cortex API integrates with Commerce Engine's Identity Management System. This tutorial follows the implementation methodology described in Tutorial 5 - Creating a Resource Integration to swap out the Commerce Engine's IdM and swap it with a custom IdM to communicate with Cortex API.

What you should already know:

  • Your Identity Management System (Our tutorial code does not talk to an Identity Management System. From the examples below, you need to infer how code a resource integration to communicate with your custom Identity Management System).
  • DTOs and Interface Strategies (Don't worry, you don't need to know these inside out, just be aware of how they work).
  • Cortex API Web Application POMs

Creating the Identity Management Integration Project

Creating a new Resource Integration project is the first lesson in this class. Elastic Path provides a Maven Archetype to simplify the task to create a new resource integration. Archetypes are project templates that contain some of the standard components you'll need for your project.

  1. Open a command prompt and navigate to your Extensions Directory.
  2. Run the following command to create an Integration project:
    mvn archetype:generate -DarchetypeArtifactId=ep-cortex-resource-integration-archetype -DarchetypeGroupId=com.elasticpath.cortex.dce -DarchetypeVersion=<your-artifact-version>
    Tip: Troubleshooting Tip

    Build fails when generating the archetype? See: Build Troubleshooting.

  3. Tip: Stack Trace Tip

    You may see a stack trace preceded by a warning similar to the following:

    [WARNING] Error reading archetype catalog http://repo1.maven.org/maven2
    org.apache.maven.wagon.TransferFailedException: Error transferring file: Connection timed out: connect
                

    This can occur if you are operating Maven in online mode. It can be safely ignored.

  4. Enter the variables for your project as prompted (i.e: groupId, version and artifactId).
  5. Change to the newly created project directory and execute the following command to build the resource integration JAR file.
    mvn install

Import the New Resource Integration into Eclipse

Next, you need to import your Resource Integration project into Eclipse as a Maven project.

  1. In Eclipse, choose File -> Import -> Existing Maven Projects into Workspace, and click Next.
  2. Click Browse and select the resource integration directory.
  3. Make sure the project is selected in the list of projects and click Finish.

Add the Resource Integration's Dependency

Once our base project is set up, we need to add the appropriate rest resource dependency to the project's pom.xml.

Why do you need this dependency?

We need to implement the authentication resource's strategy interfaces in order for Cortex API to communicate with your custom Identity Management System. Therefore, we need to add this as a dependency to our project so we can access these methods.

To add the dependency:

  1. In Eclipse, open your project's pom.xml.
  2. Add the following code beneath the <description> element:
    ...
    <dependencies>
    	    <dependency>
        <groupId>com.elasticpath.rest.relos.rs.authentication</groupId>
        <artifactId>ep-rs-authentication</artifactId>
        <version>${cortex.version}</version>
    </dependency>
    	</dependencies>
  3. Save the pom.xml.
  4. Right-click the project and select Maven -> Update Project Configuration, to update your project's dependencies and rebuild.

Implementing the Interfaces

Now that we've created the project and added the appropriate dependency, we're going to implement the authentication strategy's interfaces

There are four interfaces we need to implement to make the appropriate service calls to the custom IdM.

Interface Purpose
UserAuthenticationStrategy Authenticates a user against the Identity Management system based on given user credentials.
PostUserAuthenticationStrategy Any operations to be performed after a user is authenticated.
UserPrincipalLookupStrategy Retrieves information about the user, such as whether the user account is still active.
RealmValidator Validates rather the given scope of a request URI is valid.

UserAuthenticationStrategy

This interface lives under the package com.elasticpath.rest.relos.rs.authentication and provides the following method declaration:

ExecutionResult<AuthenticationResponseDto> authenticate(String scope, String username, String password, String role);

The parameters are the user credentials passed down from the OAuth2 endpoint. The custom Identity Management system uses these credentials to authenticate the user. The AuthenticationResponseDto object returned by the method is a DTO.

AuthenticationResponseDto Fields:

Field Usage
Id The Identity Management system's unique identifier for the user.
Scope The requested scope
Role The requested role

An example implementation could look like the following:

public ExecutionResult<AuthenticationResponseDto> authenticate(final String scope,
            final String username,
            final String password,
            final String role) {

		User user = identityManagementService.authenticate(username, password, scope, role);		

		AuthenticationResponseDto dto = ResourceTypeFactory.createResourceEntity(AuthenticationResponseDto.class)
                        .setId(user.getUserId())
                        .setScope(user.getScope())
                        .setRole(role);
}

This interface lives under the package com.elasticpath.rest.relos.rs.authentication, and provides the following method declaration:

ExecutionResult<Void> execute(AuthHeaderDto authHeaderDto, AuthenticationResponseDto authenticationResponseDto)

AuthHeaderDto is a DTO object containing the information of the current user making the authentication call.

AuthenticationResponsetDto is the DTO object created from the authenticate() method call in UserAuthenticationStrategy, and holds information of the authenticated user.

If you have any additional operations you wish to perform on the authenticated user, post authentication, then you can implement that logic here.

The method should return an ExecutionResult object with a successful status, if all operations are successful.

This interface lives under com.elasticpath.rest.relos.rs.authentication, and provides the following method declaration:

ExecutionResult<UserPrincipalDto> getUserPrincipal(Collection<String> scopes, String userId, Collection<String> roles)

The parameters are the user's unique identifier for the Custom Identity Management system, along with the requested scopes and roles of the user.

This method should return a UserPrincipalDto object, that holds following information about the user:

Field Usage
AccountEnabled Is user account enabled?
AccountLocked Is user account locked?
AccountExpired Has user account expired?
UserIdentifier The unique identifier of the user on the Custom Identity Management system
Username The user's username
CredentialsExpired Has user's credentials expired?
Scope The scope accessible by the user.
Roles The roles of the user.

An example implementation could look like the following:

public ExecutionResult<UserPrincipalDto> getUserPrincipal(Collection<String> scopes, String userId, Collection<String> roles) {
		
	UserPrincipalDto userPrincipalDto = ResourceTypeFactory.createResourceEntity(UserPrincipalDto.class);		
 
	User user = identityManagementService.findUser(userId, scopes, roles);

	userPrincipalDto.setAccountEnabled(user.isEnabled())
		.setAccountExpired(false)
		.setAccountLocked(false)
		.setUserIdentifier(userId)
		.setUsername(user.getUserName())
		.setCredentialsExpired(false)
		.setScope(user.getScope())
		.setRoles(user.getRoles());
		
	return ExecutionResultFactory.createReadOK(userPrincipalDto);
}

This interface contains two methods:

ExecutionResult<String> validate(String realm)

This method validates that the given realm is valid and exists in the integrated system.

Boolean isRealmActive(String realm)

This method validates that the requested realm is still active.

Export your Code for OSGI to Consume

Inside theCortex API's Web App, the Cortex API runs in an OSGi framework. We need to export our code in a way OSGi can be aware of it and consume it.

To export your code for OSGi:

Declare the following in your project's OSGI-INF/blueprint/example-integration-blueprint.xml:

<blueprint
		xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
	...

	<service ref="userAuthenticationStrategy" 		 		
		interface="com.elasticpath.rest.relos.rs.authentication.UserAuthenticationStrategy" />  	
	<service ref="userPrincipalLookup"
 		interface="com.elasticpath.rest.relos.rs.authentication.UserPrincipalLookupStrategy" />  		 	
	<service ref="postUserAuthenticationStrategy" 		
		interface="com.elasticpath.rest.relos.rs.authentication.PostUserAuthenticationStrategy" />  		 	
	<service ref="realmValidator"  		
		interface="com.elasticpath.rest.relos.rs.authentication.RealmValidator" />	
</blueprint>

Next, add the following declaration to your project's spring/applicationContext-example-integration.xml:

 <beans
	...
	<context:component-scan base-package{project.package} scope-resolver="org.springframework.context.annotation.Jsr330ScopeMetadataResolver"/>
</beans>

Where ''{project.package}" is the root package of your project.

After you've made these changes, you'll build your integration project and install it in your local Maven repository. From a command line, change directories to the root of your integration project and execute:

mvn install

Override the Old Identity Management Integration with the Custom Identity Management Integration

This lesson teaches you how to override the old identify managment integration with a new one. To make this change, you need to shut down Cortex API web application, modify the web application's POM file, and then restart the web application.

In this lesson, you are modifying the following XML elements in the Cortex API web application's POM file that you created in Generate Cortex Projects.

  • <dependency> - Tells Maven to include your integration project's jar as a dependency during build.
  • <execution> - Execution groups configure the goals for the plugin. In this tutorial, we are going to configure the Cortex API Web App POM to override the out-of-the-box resource asset's <execution> group. For more information on POMs, see Cortex Web Application POMs.
  1. Shut down Cortex API web application.
  2. With a text editor, open the Cortex API web application's pom.xml.
  3. Add your com.customer.identity.management as a <dependency> and configure the :copy-oauth2-OSGi-bundles <execution> group following the example below:
    ...
    <dependencies>
    		<!-- Add Extension resources or Integration modules as maven dependencies here. -->
    		<dependency>
    			<groupId>com.customer.identity.management</groupId> 		
    			<artifactId>custom-identity-management-integfration</artifactId> 
    			<version>1.0-SNAPSHOT</version>
    			<scope>provided</scope>
    	</dependency>
    </dependencies>
    ...
    <plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-dependency-plugin</artifactId>
    				<executions>
    					<!-- Override Assets CE Integration and use an example integration instead. -->
    						<execution>
    									<id>copy-oauth2-OSGi-bundles</id>
    									<phase>prepare-package</phase>
    									<goals>
    										<goal>copy</goal>
    									</goals>
    									<configuration>
    										<outputDirectory>${war-bundle-directory}</outputDirectory>
    										<artifactItems>
    											<artifactItem>
    												<groupId>com.elasticpath.rest.relos.rs.authentication</groupId>
    												<artifactId>ep-rs-authentication-client</artifactId>
    											</artifactItem>
    											<artifactItem>
    												<groupId>com.elasticpath.rest.relos.rs.authentication</groupId>
    												<artifactId>ep-rs-authentication-spring-oauth2</artifactId>
    											</artifactItem>
    											<artifactItem>
    												<groupId>com.customer.identity.management</groupId>
    												<artifactId>custom-identity-management-integfration</artifactId>
    											</artifactItem>
    										</artifactItems>
    									</configuration>
    								</execution>
  4. On command line, change to your Cortex API web application directory and run the following:
    mvn clean install -DskipAllTests

Run and Test the Custom Identity Management Integration

Startup your web application and attempt to authenticate using credentials available in your Custom Identity Management system.