Payment API Client

 Overview

-

This API is a gateway for receiving payments through our system. It's ment to simplify external integration between different domains such as credit cards, prepaid cards and value codes.

 Swagger documentation

-

# Public Payment API Client

-

 Prerequisites

-

  • Java 11
  • VueJS
  • Maven
  • Postgres

 Project setup

-

    vas-payment-api-client
    ├─┬ backend     → backend module with Spring Boot code
    │ ├── src
    │ └── pom.xml
    ├─┬ frontend    → frontend module with Vue.js code
    │ ├── src
    │ └── pom.xml
    └── pom.xml     → Maven parent pom managing both modules

 Security

-

<details>
<summary>Oauth2:</summary>

VasPublicPaymentApi requires an OAuth2 access token for interaction.  
This application automatically handles token fetching and refreshing by using [Spring Security](https://docs.spring.io/spring-security-oauth2-boot/docs/current/reference/htmlsingle/#boot-features-security-custom-user-info-client).  
Configuration values are set in [application.yml](https://github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/resources/application.yml): 

```yaml
# "XXX" Should be replaced by value provided by PayEx
# CLIENT_ID/CLIENT_SECRET/VAS_AUTH_SERVER_URL can also be set in docker-compose.yml as environment variables if running with docker
# The application will see if environment variables are present, if not fall back to "XXX" values.
vas-payment-api:
    oauth2:
        client:
            grantType: client_credentials
            clientId: "${CLIENT_ID}:XXX"
            clientSecret: "${CLIENT_SECRET}:XXX"
            accessTokenUri: "${VAS_AUTH_SERVER_URL}:XXX"
            scope: publicapi
           
```

And the implementation of these are located in [Oauth2RestTemplateConfiguration.java](https://github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/java/com/payex/vas/demo/config/security/Oauth2RestTemplateConfiguration.java):

```java
public class Oauth2RestTemplateConfiguration {
   ...
    @Bean
    @ConfigurationProperties("vas-payment-api.oauth2.client")
    protected ClientCredentialsResourceDetails oAuthDetails() {
        return new ClientCredentialsResourceDetails();
    }

    @Bean
    protected RestTemplate restTemplate() {
        var restTemplate = new OAuth2RestTemplate(oAuthDetails());
        restTemplate.setInterceptors(ImmutableList.of(externalRequestInterceptor()));
        restTemplate.setRequestFactory(httpRequestFactory());
        return restTemplate;
    }
   ...
}
```
</details>

<details>

<summary>HMAC:</summary>

The API also requires HMAC authentication to be present in a request.  
In this client the HMAC value is automatically calculated by [HmacSignatureBuilder.java](https://github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/java/com/payex/vas/demo/config/security/HmacSignatureBuilder.java) and added to all outgoing requests in [ExternalRequestInterceptor.java](https://github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/java/com/payex/vas/demo/config/ExternalRequestInterceptor.java)

HMAC is implemented using SHA-512 secure hash algorithm. 

Expected `Hmac` header format is:

```text
HmacSHA512 <user>:<nonce>:<digest>
```

where `digest` is a Base64 formatted HMAC SHA512 digest of the following string: 

```text
METHOD\n
RESOURCE\n
USER\
NONCE\n
DATE\n
PAYLOAD\n
```

`METHOD` (mandatory) the requested method (in upper case) `RESOURCE` (mandatory) the path to desired resource (without hostname and any query parameters)  
`NONSE` (mandatory) a unique value for each request ([UUID](https://tools.ietf.org/rfc/rfc4122.txt)) `DATE`(optional) same as `Transmission-Time` if provided as seperate header. Uses [ISO8601 standard](https://en.wikipedia.org/wiki/ISO_8601) `PAYLOAD` (optional) body of request 

Example request:

```bash
curl -X POST \
 https://stage-evc.payex.com/payment-api/api/payments/payment-account/balance \
  -H 'Accept: */*' \
  -H 'Agreement-Merchant-Id: XXX' \
  -H 'Authorization: Bearer XXX' \
  -H 'Hmac: HmacSHA512 user:21a0213e-30eb-85ab-b355-a310d31af30e:oY5Q5Rf1anCz7DRm3GyWR0dvJDnhl/psylfnNCn6FA0NOrQS3L0fvyUsQ1IQ9gQPeLUt9J3IM2zwoSfZpDgRJA==' \
  -H 'Transmission-Time: 2019-06-18T09:19:15.208257Z' \
  -H 'Session-Id: e0447bd2-ab64-b456-b17b-da274bb8428e' \
  -d '{
 "accountIdentifier": {
  "accountKey": "7013369000000000000",
  "cvc": "123",
  "expiryDate": "2019-12-31",
  "instrument": "GC"
 }
}'
```

In this example `USER` is user and `SECRET` is secret. 

The plain string to `digest` would then be:

```text
POST
/payment-api/api/payments/payment-account/balance
user
21a0213e-30eb-85ab-b355-a310d31af30e
2019-06-18T09:19:15.208257Z
{
 "accountIdentifier": {
  "accountKey": "7013360000000000000",
  "cvc": "123",
  "expiryDate": "2020-12-31",
  "instrument": "CC"
 }
}
```

The plain `digest` string is then hashed with `HmacSHA512` algorithm and the `SECRET`. Finally we Base64 encode the hashed value. This is the final `digest` to be provided in the `Hmac` header.

Final `Hmac` header value: 

```text
HmacSHA512 user:21a0213e-30eb-85ab-b355-a310d31af30e:oY5Q5Rf1anCz7DRm3GyWR0dvJDnhl/psylfnNCn6FA0NOrQS3L0fvyUsQ1IQ9gQPeLUt9J3IM2zwoSfZpDgRJA==
```

 Postman example script

In pre-request script copy/paste the following snippet:

```javascript

var user = 'user';
var secret = 'secret';
var transmissionTime = (new Date()).toISOString();
var sessionId = guid();

var hmac = generateHMAC(user, secret, transmissionTime);
console.log('hmac: ' + hmac);

Set header values
pm.request.headers.add({key: 'Hmac', value: hmac });
pm.request.headers.add({key: 'Transmission-Time', value: transmissionTime });
pm.request.headers.add({key: 'Session-Id', value: sessionId });

function generateHMAC(user, secret, transmissionTime) {

    var algorithm = "HmacSHA512";
    var separator = ":";
    var method = request.method.toUpperCase();
    var nonce = generateNonce(); UUID
    var date = transmissionTime;
   
    var uri_path = replaceRequestEnv(request.url.trim()).trim().replace(new RegExp('^https?:
[^/]+/'), '/');  strip hostname
    uri_path = uri_path.split("?")[0]; 
Remove query paramters
    var payload = _.isEmpty(request.data) ? "" : request.data;
    var macData = method + '\n'
        + uri_path + '\n'
        + user + '\n'
        + nonce + '\n'
        + date + '\n'
        + payload + '\n';

    macData = replaceRequestEnv(macData);
    console.log('data to mac: ' + macData);

    var hash = CryptoJS.HmacSHA512(macData, secret);
    var digest = CryptoJS.enc.Base64.stringify(hash);
    return algorithm + " " + user + separator + nonce + separator + digest;
}

function replaceRequestEnv(input) { manually set environments to they are populated before hashing
    return input.replace(/{{([^)]+)}}/g, function (str, key) {
        var value = pm.environment.get(key);
        return value === null ? pm.varables.get(key) : value;
    });
}

function generateNonce() {
    return guid();
}

function guid() {
    function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
            .toString(16)
            .substring(1);
    }

    return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
        s4() + '-' + s4() + s4() + s4();
}

```
</details>

# Security documentation

-

 First App run

-

NB! The application expects a PostgreSQL server to be running on localhost with a username `test` and password `test` to exist.  
This can automatically be configured if PostgreSQL server is started in docker with environment variables `POSTGRES_USER=test` and `POSTGRES_PASSWORD=test` are set (See [docker-compose.yml](https://github.com/PayEx/vas-payment-api-client/blob/master/docker-compose.yml)).**

Inside the root directory, do a: 

```bash
mvn clean install
```

Run the Spring Boot App:

```bash
mvn projects backend spring-boot:run
```

Now go to <http://localhost:8080/> and have a look at your new client.

 Testing application

-

  1. Add a new card with provided details from PayEx.
  2. Click on newly added Card
  3. Click on "initiate payment" to create a new transaction

 Build docker filename

-

```bash
mvn projects backend clean compile jib:dockerBuild
```

 Deploy to local docker:

-

```bash
docker-compose up -d    
```

Created by Thomas Warren on 2020/01/23 13:25

Tips

You can click on the arrows next to the breadcrumb elements to quickly navigate to sibling and children pages.

Need help?

If you need help with XWiki you can contact: