# User Account Administration integration and testing
source: https://developer.mastercard.com/presentment/documentation/tutorials-and-guides/user-account-admin-integration-and-testing-tutorial/index.md

## Introduction {#introduction}

This tutorial walks through the steps required to create a new User Account Administration project and how to gain access to the Sandbox environment.

* Integration and testing time: 30 minutes
* Technology used: Java, Maven, OpenAPI Generator

### What you will learn {#what-you-will-learn}

* How to set up the environment to develop a simple Java application
* How to generate an API client using the [OpenAPI Generator](https://openapi-generator.tech/)
* How to make an API call

## Tutorial prerequisites {#tutorial-prerequisites}

To complete this tutorial, you will need:

* [JDK 17](https://www.java.com/en/) access
* An integrated development environment (IDE) of your choice
* Mastercard Developers account with access to the **User Account Administration API**
* User Account Administration Open API specification
  * Refer to the [API Reference](https://developer.mastercard.com/presentment/documentation/api-reference/index.md) section for details

## Environment set up {#environment-set-up}

1. Create a Maven Project

* In the IDE, create a new Maven project, which sets your directory structure automatically.
* Provide an ArtifactId and a project name as per your choice.

![alt text](https://static.developer.mastercard.com/content/presentment/uploads/create-maven-project-screenshot-1.png "Create Maven project")

2. Add resources

* Add the User Account Administration API specification to your Maven project resources folder.
* Add the generated Sandbox key, known as the `.p12` file, and encryption cert, known as the `.pem` file, to your Maven project resources folder.

Note: This is generated while creating the project on Mastercard Developers.

* Your Maven project directory structure displays as:

![alt text](https://static.developer.mastercard.com/content/presentment/uploads/maven-project-directory-screenshot-2.png "Maven project directory")

3. Update the `pom.xml` file

* In your IDE, add the [OpenAPI Generator maven plugin](https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin) to your project `pom.xml` file. Use this Plugin configuration:

```java
<plugin>
				<groupId>org.openapitools</groupId>
				<artifactId>openapi-generator-maven-plugin</artifactId>
				<version>${openapitools.version}</version>
				<executions>
					<execution>
						<goals>
							<goal>generate</goal>
						</goals>
						<configuration>
							<inputSpec>${project.basedir}/src/main/resources/pci-api-service.yaml</inputSpec>
							<generatorName>java</generatorName>
							<apiPackage>com.mastercard.offers.developer.openapi.api</apiPackage>
							<modelPackage>com.mastercard.offers.developer.openapi.model</modelPackage>
							<generateApiTests>false</generateApiTests>
							<generateModelTests>false</generateModelTests>
							<generateModelDocumentation>false</generateModelDocumentation>
							<generateApiDocumentation>false</generateApiDocumentation>
							<skipValidateSpec>true</skipValidateSpec>
							<typeMappings>
								<typeMapping>OffsetDateTime=String</typeMapping>
								<typeMapping>LocalDate=String</typeMapping>
							</typeMappings>
							<importMappings>
								<importMapping>java.time.OffsetDateTime=java.lang.String</importMapping>
								<importMapping>java.time.LocalDate=java.lang.String</importMapping>
							</importMappings>

							<configOptions>
								<sourceFolder>src/gen/java/main</sourceFolder>
								<supportingFiles>false</supportingFiles>
								<dateLibrary>java8</dateLibrary>
								<developerEmail>test@test.com</developerEmail>
								<developerName>Mastercard</developerName>
								<developerOrganization>Mastercard</developerOrganization>
								<developerOrganizationUrl>http://mastercard.com</developerOrganizationUrl>
								<library>okhttp-gson</library>
								<serializationLibrary>gson</serializationLibrary>
							</configOptions>
						</configuration>
					</execution>
				</executions>
			</plugin>
```

Note: [OpenAPI Generator](https://openapi-generator.tech/) generates API client libraries using OpenAPI Specification. It provides multiple generators and library templates to support multiple languages and frameworks. This project uses the Java generator.

* Add these dependencies to your `pom.xml` file to add dependencies for the API client library generation and the Mastercard OAuth1 Signer library.

```java
<properties>
		<maven.test.skip>false</maven.test.skip>
		<java.version>17</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<okhttp.version>4.9.1</okhttp.version>
		<gson.version>2.8.6</gson.version>
		<gson-fire.version>1.8.5</gson-fire.version>
		<oauth1-signer.version>1.5.0</oauth1-signer.version>
		<openapitools.version>5.3.0</openapitools.version>
		<swagger-annotations.version>1.6.2</swagger-annotations.version>
		<code-findbugs.version>3.0.2</code-findbugs.version>
		<google-format-version>2.9</google-format-version>
		<sonar.coverage.exclusions>
			**/com/mastercard/developer/configuration/*Configuration.java,
			**/com/mastercard/developer/service/domain/*.java,
			**/com/mastercard/developer/usecases/*.java,
			**/com/mastercard/developer/Application.java
		</sonar.coverage.exclusions>
	</properties>

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.26</version>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
		</dependency>
		<!-- Additional dependency to ensure compatibility -->
		<dependency>
			<groupId>com.google.code.findbugs</groupId>
			<artifactId>jsr305</artifactId>
			<version>${code-findbugs.version}</version>
		</dependency>
		<dependency>
			<groupId>com.squareup.okhttp3</groupId>
			<artifactId>okhttp</artifactId>
			<version>${okhttp.version}</version>
		</dependency>
		<dependency>
			<groupId>com.squareup.okhttp3</groupId>
			<artifactId>logging-interceptor</artifactId>
			<version>${okhttp.version}</version>
		</dependency>
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>${gson.version}</version>
		</dependency>
		<dependency>
			<groupId>io.gsonfire</groupId>
			<artifactId>gson-fire</artifactId>
			<version>${gson-fire.version}</version>
		</dependency>
		<dependency>
			<groupId>com.mastercard.developer</groupId>
			<artifactId>oauth1-signer</artifactId>
			<version>${oauth1-signer.version}</version>
		</dependency>
		<dependency>
			<groupId>io.swagger</groupId>
			<artifactId>swagger-annotations</artifactId>
			<version>${swagger-annotations.version}</version>
		</dependency>
	</dependencies>
```

* Add these dependencies to your `pom.xml` file to encrypt and decrypt the requests using the using Mastercard Client Encryption library.

```java
<properties>
    <client-encryption-version>1.8.5</client-encryption-version>    
</properties>
<dependency>
	<groupId>com.mastercard.developer</groupId>
	<artifactId>client-encryption</artifactId>
	<version>${client-encryption-version}</version>
</dependency>
```

### Generate the API client library with OpenAPI Generator {#generate-the-api-client-library-with-openapi-generator}

When using OpenAPI Generator to generate the API client library, you have two options:

1. Generate and use the source files as needed
2. Generate and deploy the source files to a Maven repository

In this tutorial, you will generate the API client library as needed. Include the dependencies required to generate the library. If you deploy the source files to a Maven repository, include only the dependency for that repository.

Include a dependency for one of the Mastercard OAuth1 Signer libraries. Developed and maintained by Mastercard's API team, these libraries provide helper code for the HTTP clients used by the supported OpenAPI Generator library templates. The libraries are available on [GitHub](https://github.com/Mastercard?utf8=%E2%9C%93&q=oauth1-signer&type=&language=).

Refer to the [Generating and Configuring a Mastercard API Client](https://developer.mastercard.com/platform/documentation/developer-tools/generating-and-configuring-a-mastercard-api-client/) page for more information.

## Generate the API client {#generate-the-api-client}

Now that you have all the dependencies you need, you can generate the source code.

* Navigate to the project root directory within a terminal window and run mvn clean install.

![alt text](https://static.developer.mastercard.com/content/presentment/uploads/lifecycle-clean-screenshot-3.png "Project root directory")

![alt text](https://static.developer.mastercard.com/content/presentment/uploads/lifecycle-install-screenshot-4.png "Run mvn clean install from the project root directory within a terminal window")

* Alternatively, you can navigate to the root directory of the project within a terminal window and run mvn clean install.

![alt text](https://static.developer.mastercard.com/content/presentment/uploads/terminal-clean-install-screenshot-5.png "Run mvn clean install from the root directory of the project within a terminal window")

### Result {#result}

A folder named **target** is created within your root directory, which contains classes generated for the schemas and API calls defined within the OpenAPI Specification. The generated classes can be found in the target folder as shown in the screenshot.

![alt text](https://static.developer.mastercard.com/content/presentment/uploads/generated-classes-within-target-folder-screenshot-6.png "Generated classes within the target folder")

## Make an API call {#make-an-api-call}

1. Under the `src/main/java/` folder path, create a Java file named `RestClientConfig.java`.
2. To make the API call, make your OAuth credentials available to the program for use.

* A PrivateKey is created with the provided credentials for future use.
* AuthenticationUtils is provided by the Mastercard OAuth signing library.

```java
// Read these values from application.properties
@Value("${mastercard.api.key.alias}")
  private String signingKeyAlias;

  @Value("${mastercard.api.keystore.password}")
  private String signingKeyPassword;

  @Value("${mastercard.api.p12.path}")
  private String signingKeyPkcs12FileName;
```

You can include the encryption and signing information in the application's `application.properties` file as shown.

```java
# path to keystore (.p12). Uses Spring's resource strings.
# e.g : OffersforPublishersWithPCIService-production-signing.p12
mastercard.api.p12.path=src/main/resources/UAAReferenceApp-sandbox-signing.p12

# Consumer key. Copy this from "Sandbox/Production Keys" on your project page in https://developer.mastercard.com
# e.g. GTBC2cqRjwSHv0px1ndEfQuXwF-cOM6an-QlZe5D5a4858c9!34d8cd73e52f458f8f7a31e4b1c393450000000000000000
mastercard.api.consumer.key=JjCA9Az8oon8S-bJuojRFl9BYclFVBVH7E08oQdLf21eec91!000d53f292c04c3098519cb89ee00d5f0000000000000000

# key alias. Default key alias for sandbox is "keyalias" (without quotes).
mastercard.api.key.alias=keyalias1234

# keystore password. Default keystore password for sandbox project is "keystorepassword" (without quotes)
mastercard.api.keystore.password=keystorepassword1234

# basepath.
basePath=https://sandbox.api.mastercard.com/loyalty/offers

# path to certificate (PEM) file whose public key will be used to encrypt request payload before calling mastercard api.
# e.g : encryption-cert.pem
client.encryption.pem.path=src/main/resources/user-account-administration-clientenc1783706934039-client-encryption-key.pem

#path to the PKCS#12 (.p12) keystore whose private key will be used to decrypt the encrypted response received from mastercard api.
#The key is looked up inside the keystore using mastercard.encryption.api.key.alias and mastercard.encryption.api.keystore.password below.
client.decryption.p12.path=src/main/resources/user-account-administration-keyalias1234-mastercard-encryption-key.p12

#Encryption/decryption keystore alias and password (independent of the signing key alias/password above).
mastercard.encryption.api.key.alias=keyalias1234
mastercard.encryption.api.keystore.password=keystorepassword1234

# The SHA-256 hex-encoded digest of the key used to encrypt request payload
# e.g : f667458f6799b91e2476eef4639f1949a91155eff893c83672de916328017c99
mastercard.encryption.key.fingerprint=3b64aa2eefc5e5c62cb61fc34e621abd7355da7d4204e5290509a367d861f85f
```

Tip: Refer to this [tutorial](https://developer.mastercard.com/presentment/documentation/tutorials-and-guides/create-sandbox-project-tutorial/) to generate the keys that are used in the `application.properties` file.

### Create certificate object {#create-certificate-object}

A certificate object can be created from a file by calling EncryptionUtils.loadEncryptionCertificate. Supported certificate formats are PEM, DER.

`Certificate encryptionCertificate = EncryptionUtils.loadEncryptionCertificate("<insert certificate file path>");`

### Payload-level encryption {#payload-level-encryption}

Entire payloads can be encrypted using the "$" operator as the encryption path.

```java
jweConfig =
           JweConfigBuilder.aJweEncryptionConfig()
               .withEncryptionCertificate(encryptionCertificate)
               .withEncryptionPath("$", "$")
               .withEncryptedValueFieldName("encryptedData");
```

### Instantiate client with authentication and configuration {#instantiate-client-with-authentication-and-configuration}

Instantiate a client with your authentication credentials and configuration object as interceptors before sending.

```java
PrivateKey signingKey = AuthenticationUtils.loadSigningKey(signingKeyPkcs12FileName, signingKeyAlias, signingKeyPassword);
 apiClient = new ApiClient();
 apiClient.setBasePath("https://sandbox.api.mastercard.com");
 apiClient.setDebugging(true);

 OkHttpClient.Builder okHttpClientBuilder = apiClient.getHttpClient().newBuilder();
// Add the X-Public-Key-Fingerprint header interceptor first
     okHttpClientBuilder.addInterceptor(
         chain -> {
           Request originalRequest = chain.request();
           Request modifiedRequest =
               originalRequest
                   .newBuilder()
                   .header("X-Public-Key-Fingerprint", encryptionKeyFingerprint)
                   .build();
           return chain.proceed(modifiedRequest);
         });
 okHttpClientBuilder.addInterceptor(new OkHttpOAuth1Interceptor(consumerKey, signingKey));

 return apiClient.setHttpClient(okHttpClientBuilder.build());
```

Note: Only the minimal components required to initiate the API call are included in the initial example. The full contents of ApiClientConfiguration.java are provided in their entirety for reference.

### Contents of RestClientConfig.java {#contents-of-restclientconfigjava}

```java
package com.mastercard.offers.developer.config;

import com.mastercard.developer.encryption.JweConfigBuilder;
import com.mastercard.developer.interceptors.OkHttpJweInterceptor;
import com.mastercard.developer.interceptors.OkHttpOAuth1Interceptor;
import com.mastercard.developer.utils.AuthenticationUtils;
import com.mastercard.developer.utils.EncryptionUtils;
import com.mastercard.offers.developer.openapi.ApiClient;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.util.Objects;

@Service
@Slf4j
public class RestClientConfig {

 @Value("${mastercard.api.consumer.key}")
 public String consumerKey;

 @Value("${basePath}")
 private String basePath;

 @Value("${mastercard.api.key.alias}")
 private String signingKeyAlias;

 @Value("${mastercard.api.keystore.password}")
 private String signingKeyPassword;

 @Value("${mastercard.encryption.api.key.alias}")
 private String encryptionKeyAlias;

 @Value("${mastercard.encryption.api.keystore.password}")
 private String encryptionKeyPassword;

 @Value("${mastercard.api.p12.path}")
 private String signingKeyPkcs12FileName;

 @Value("${client.encryption.pem.path}")
 private String encryptionKeyPemFileName;

 @Value("${client.decryption.pem.path}")
 private String decryptionKeyP12;

 @Value("${client.encryption.key.fingerprint}")
 private String encryptionKeyFingerprint;

 private ApiClient apiClient = null;

 public ApiClient getApiClient() {
   createNewApiClient(true, true); // Enable both encryption and decryption for real API calls
   return apiClient;
 }

 public ApiClient createNewApiClient(boolean encryptRequest, boolean decryptRequest) {
   apiClient = new ApiClient();
   JweConfigBuilder jweConfig = null;
   try {
     PrivateKey signingKey =
         AuthenticationUtils.loadSigningKey(
             signingKeyPkcs12FileName, signingKeyAlias, signingKeyPassword);
     apiClient.setBasePath(basePath);
     apiClient.setDebugging(true);
     OkHttpClient.Builder okHttpClientBuilder = apiClient.getHttpClient().newBuilder();

     // Add the X-Public-Key-Fingerprint header interceptor first
     okHttpClientBuilder.addInterceptor(
         chain -> {
           Request originalRequest = chain.request();
           Request modifiedRequest =
               originalRequest
                   .newBuilder()
                   .header("X-Public-Key-Fingerprint", encryptionKeyFingerprint)
                   .build();
           return chain.proceed(modifiedRequest);
         });

     if (encryptRequest) {
       Certificate encryptionCertificate =
           EncryptionUtils.loadEncryptionCertificate(encryptionKeyPemFileName);

       jweConfig =
           JweConfigBuilder.aJweEncryptionConfig()
               .withEncryptionCertificate(encryptionCertificate)
               .withEncryptionPath("$", "$")
               .withEncryptedValueFieldName("encryptedData");
     }

     if (decryptRequest) {
       if (Objects.isNull(jweConfig)) {
         jweConfig = JweConfigBuilder.aJweEncryptionConfig();
       }
       jweConfig.withDecryptionPath("$.encryptedData", "$");
       jweConfig.withDecryptionKey(
           EncryptionUtils.loadDecryptionKey(
               decryptionKeyP12, encryptionKeyAlias, encryptionKeyPassword));
     }

     if (!Objects.isNull(jweConfig)) {
       okHttpClientBuilder.addInterceptor(new OkHttpJweInterceptor(jweConfig.build()));
     }

     okHttpClientBuilder.addInterceptor(new OkHttpOAuth1Interceptor(consumerKey, signingKey));

     return apiClient.setHttpClient(okHttpClientBuilder.build());
   } catch (Exception e) {
     log.error(e.getMessage());
   }
   return apiClient;
 }
}
```

In this block of code, the request is signed using the parameters from the `application.properties` file. The request is also encrypted if it is a POST call. Refer to the [API Basics](https://developer.mastercard.com/presentment/documentation/api-basics/index.md) section for signing and encryption details.

### Start using the APIs with generated classes {#start-using-the-apis-with-generated-classes}

Put everything together and you can start using the APIs by making use of the generated classes.

#### Controller {#controller}

```java
@RestController
@RequestMapping("/loyalty/offers/enrollments/users")
public class UsersController {

 private final UsersPCIService usersPCIService; 

@Autowired
 public UsersController(UsersPCIService usersPCIService) {
   this.usersPCIService = usersPCIService;
 }

 /**
  * Enroll an account for existing user
  *
  * @param xFid Interbank Card Association number
  * @param crk User Customer Random Key identifier
  * @param accountToEnroll Account enrollment details
  * @return EnrolledAccount
  * @throws ApiException If fail to call the API
  */
 @PostMapping("/{crk}/accounts")
 public ResponseEntity<EnrolledAccount> enrollAccount(
     @RequestHeader("X-Fid") Integer xFid,
     @PathVariable String crk,
     @RequestBody AccountToEnroll accountToEnroll)
     throws ApiException {
   EnrolledAccount result = usersPCIService.enrollAccount(xFid, crk, accountToEnroll);
   return ResponseEntity.ok(result);
 }
```

#### Service {#service}

```java
@Service
public class UsersPCIService {

@Autowired private RestClientConfig restClientConfig;

@Autowired
public UsersPCIService(RestClientConfig restClientConfig) {
  this.restClientConfig = restClientConfig;
}

/**
 * Allows for enrollment of an initial account Provides ability to enroll an account for existing
 * user.
 *
 * @param xFid Interbank Card Association number assigned by Mastercard
 * @param crk User Customer Random Key (CRK) identifier
 * @param accountToEnroll Account enrollment details
 * @return EnrolledAccount
 * @throws ApiException If fail to call the API
 */
public EnrolledAccount enrollAccount(Integer xFid, String crk, AccountToEnroll accountToEnroll)
    throws ApiException {
  ApiClient apiClient = restClientConfig.createNewApiClient(true, true);
  UsersApi usersApi = getUsersApi(apiClient);
  return usersApi.enrollAccount(xFid, crk, accountToEnroll);
}
```

Tip: Refer to the [Reference Application](https://developer.mastercard.com/presentment/documentation/developer-tools/reference-application/index.md) section for details. The Insomnia file uses `localhost` as the host for testing the User Account Administration APIs, enabling you to test the APIs directly from the reference application without configuring your own certificates. To use your own certificates, use the applicable Sandbox or Production URL instead.
