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

## Introduction {#introduction}

This tutorial helps you create a simple Java application that makes an API call to the User Account Administration service in the Sandbox environment.

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

By the end of this tutorial, 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.
* A Mastercard Developers account with access to the User Account Administration API.
* User Account Management Open API specification.
  * Refer to the [API Reference](https://developer.mastercard.com/presentment/documentation/api-reference/index.md) section for details.

## Environment setup {#environment-setup}

### Create a Maven project {#create-a-maven-project}

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

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

### Add resources {#add-resources}

1. Add the User Account Administration API specification to your Maven project resources folder.
2. 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.
3. Your Maven project directory structure displays as: ![alt text](https://static.developer.mastercard.com/content/presentment/uploads/maven-project-directory.png "Maven project directory")

### Update pom.xml file {#update-pomxml-file}

1. 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.

2. 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>
```

3. 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 you use the OpenAPI Generator to create an API client library, you have two options:

1. You can generate the client at build time -- You include the necessary dependencies when you configure your project to automatically generate the client code during the build process.
2. You can generate and publish to the Maven repository -- You generate the client code once, publish it to a Maven repository, and then include it as a regular dependency for the published client library.

You include the dependency for one of the Mastercard OAuth1 Signer libraries. Mastercard offers OAuth1 Signer Libraries that are developed and maintained by Mastercard's API team. These libraries offer code helpers targeting the HTTP clients used by the different OpenAPI Generator Library templates. The libraries are hosted 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/getting-started-with-mastercard-apis/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.

1. 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/project-root-directory.png "Project root directory")

![alt text](https://static.developer.mastercard.com/content/presentment/uploads/run-mvn-clean-install.png "Run mvn clean install from 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/root-directory-run-mvn-clean-install.png "Run mvn clean install from 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/target-folder-generated-classes.png "Generated classes within target folder")

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

### Create a Java file {#create-a-java-file}

1. Under the `src/main/java/` folder path, create a Java file named `RestClientConfig.java`.

### Enable OAuth credentials {#enable-oauth-credentials}

1. To make the API call, you need to make your OAuth credentials available to the program for use.

* A PrivateKey is created with the provided credentials for later 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/OffersforPublishersWithPCIService-production-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=GTBC2cqRjwSHv0px1ndEfQuXwF-cOM6an-QlZe5D5a4858c9!34d8cd73e52f458f8f7a31e4b1c393450000000000000000

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

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

# 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/public_key_to_encrypt.pem

#path to certificate (PEM) file whose private key will be used to decrypt the encrypted response received from mastercard api.
#Convert .p12 to .pem file and extract the private key.
client.decryption.pem.path=src/main/resources/private_key_to_decrypt.pem

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

### Convert your Mastercard encryption key PKCS#12 key as an RSA key {#convert-your-mastercard-encryption-key-pkcs12-key-as-an-rsa-key}

1. Convert the Mastercard encryption key .p12 file downloaded from Mastercard Developers during encryption file generation using this command:

```java
openssl pkcs12 -in '<location of the .p12 file>' | openssl rsa -out <Filename of the key generated ending with .key>
```

2. Use the password and passphrase values of your Mastercard encryption key .p12 file, which you set up when generating the encryption file from Mastercard Developers.

![alt text](https://static.developer.mastercard.com/content/presentment/uploads/password-passphrase-p12.png ".p12 file password and passphrase")
Tip: Refer to this [tutorial](https://developer.mastercard.com/presentment/documentation/tutorials-and-guides/create-sandbox-project-tutorial/index.md) to generate the keys that are used in the application.properties file.

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

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

<br />

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

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

1. 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}

1. Instantiate a client with your authentication credentials and configuration object as interceptors before you can send it.

```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 ApiClientConfiguration.java {#contents-of-apiclientconfigurationjava}

```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.api.p12.path}")
  private String signingKeyPkcs12FileName;

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

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

  @Value("${mastercard.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));
      }

      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's 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}

1. 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/reference-application/index.md) section for details.
