From version 5.1
edited by Thomas Warren
on 2020/01/23 13:26
To version 6.1
edited by Thomas Warren
on 2020/01/23 13:26
Change comment: There is no comment for this version

Summary

Details

Page properties
Content
... ... @@ -1,289 +1,289 @@
1 -`## Overview`
1 +##~#~# Overview##
2 2  
3 -`---`
3 +##~-~--##
4 4  
5 -`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.`
5 +##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.##
6 6  
7 -`## Swagger documentation`
7 +##~#~# Swagger documentation##
8 8  
9 -`---`
9 +##~-~--##
10 10  
11 -`* [VasPublicPaymentApi](https://stage-evc.payex.com/payment-api/swagger-ui.html)`
11 +##* [VasPublicPaymentApi](https:~/~/stage-evc.payex.com/payment-api/swagger-ui.html)##
12 12  
13 -`# Public Payment API Client`
13 +### Public Payment API Client##
14 14  
15 -`---`
15 +##~-~--##
16 16  
17 -`## Prerequisites`
17 +##~#~# Prerequisites##
18 18  
19 -`---`
19 +##~-~--##
20 20  
21 -`* Java 11
22 -* VueJS
23 -* Maven
24 -* Postgres`
21 +##* Java 11
22 +~* VueJS
23 +~* Maven
24 +~* Postgres##
25 25  
26 -`## Project setup`
26 +##~#~# Project setup##
27 27  
28 -`---`
28 +##~-~--##
29 29  
30 -` vas-payment-api-client
31 - ├─┬ backend → backend module with Spring Boot code
32 - │ ├── src
33 - │ └── pom.xml
34 - ├─┬ frontend → frontend module with Vue.js code
35 - │ ├── src
36 - │ └── pom.xml
37 - └── pom.xml → Maven parent pom managing both modules`
30 +## vas-payment-api-client
31 + ├─┬ backend → backend module with Spring Boot code
32 + │ ├── src
33 + │ └── pom.xml
34 + ├─┬ frontend → frontend module with Vue.js code
35 + │ ├── src
36 + │ └── pom.xml
37 + └── pom.xml → Maven parent pom managing both modules##
38 38  
39 -`## Security`
39 +##~#~# Security##
40 40  
41 -`---`
41 +##~-~--##
42 42  
43 -`<details>
44 -<summary>Oauth2:</summary>`
43 +##<details>
44 +<summary>Oauth2:</summary>##
45 45  
46 -`VasPublicPaymentApi requires an OAuth2 access token for interaction.
47 -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).
48 -Configuration values are set in [application.yml](https://github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/resources/application.yml): `
46 +##VasPublicPaymentApi requires an OAuth2 access token for interaction.
47 +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).
48 +Configuration values are set in [application.yml](https:~/~/github.com/PayEx/vas-payment-api-client/blob/master/backend/src/main/resources/application.yml): ##
49 49  
50 -````yaml
51 -# "XXX" Should be replaced by value provided by PayEx
52 -# CLIENT_ID/CLIENT_SECRET/VAS_AUTH_SERVER_URL can also be set in docker-compose.yml as environment variables if running with docker
53 -# The application will see if environment variables are present, if not fall back to "XXX" values.
54 -vas-payment-api:
55 - oauth2:
56 - client:
57 - grantType: client_credentials
58 - clientId: "${CLIENT_ID}:XXX"
59 - clientSecret: "${CLIENT_SECRET}:XXX"
60 - accessTokenUri: "${VAS_AUTH_SERVER_URL}:XXX"
61 - scope: publicapi
62 -
63 -````
50 +##```yaml
51 +# "XXX" Should be replaced by value provided by PayEx
52 +# CLIENT_ID/CLIENT_SECRET/VAS_AUTH_SERVER_URL can also be set in docker-compose.yml as environment variables if running with docker
53 +# The application will see if environment variables are present, if not fall back to "XXX" values.
54 +vas-payment-api:
55 + oauth2:
56 + client:
57 + grantType: client_credentials
58 + clientId: "${CLIENT_ID}:XXX"
59 + clientSecret: "${CLIENT_SECRET}:XXX"
60 + accessTokenUri: "${VAS_AUTH_SERVER_URL}:XXX"
61 + scope: publicapi
62 +
63 +```##
64 64  
65 -`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):`
65 +##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):##
66 66  
67 -````java
68 -public class Oauth2RestTemplateConfiguration {
69 - //...
70 - @Bean
71 - @ConfigurationProperties("vas-payment-api.oauth2.client")
72 - protected ClientCredentialsResourceDetails oAuthDetails() {
73 - return new ClientCredentialsResourceDetails();
74 - }`
67 +##```java
68 +public class Oauth2RestTemplateConfiguration {
69 + ~/~/...
70 + @Bean
71 + @ConfigurationProperties("vas-payment-api.oauth2.client")
72 + protected ClientCredentialsResourceDetails oAuthDetails() {
73 + return new ClientCredentialsResourceDetails();
74 + }##
75 75  
76 -` @Bean
77 - protected RestTemplate restTemplate() {
78 - var restTemplate = new OAuth2RestTemplate(oAuthDetails());
79 - restTemplate.setInterceptors(ImmutableList.of(externalRequestInterceptor()));
80 - restTemplate.setRequestFactory(httpRequestFactory());
81 - return restTemplate;
82 - }
83 - //...
84 -}
85 -```
86 -</details>`
76 +## @Bean
77 + protected RestTemplate restTemplate() {
78 + var restTemplate = new OAuth2RestTemplate(oAuthDetails());
79 + restTemplate.setInterceptors(ImmutableList.of(externalRequestInterceptor(~)~)~);
80 + restTemplate.setRequestFactory(httpRequestFactory());
81 + return restTemplate;
82 + }
83 + ~/~/...
84 +}
85 +```
86 +</details>##
87 87  
88 -`<details>`
88 +##<details>##
89 89  
90 -`<summary>HMAC:</summary>`
90 +##<summary>HMAC:</summary>##
91 91  
92 -`The API also requires HMAC authentication to be present in a request.
93 -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)`
92 +##The API also requires HMAC authentication to be present in a request.
93 +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)##
94 94  
95 -`HMAC is implemented using SHA-512 secure hash algorithm. `
95 +##HMAC is implemented using SHA-512 secure hash algorithm. ##
96 96  
97 -`Expected `Hmac` header format is:`
97 +##Expected `Hmac` header format is:##
98 98  
99 -````text
100 -HmacSHA512 <user>:<nonce>:<digest>
101 -````
99 +##```text
100 +HmacSHA512 <user>:<nonce>:<digest>
101 +```##
102 102  
103 -`where `digest` is a Base64 formatted HMAC SHA512 digest of the following string: `
103 +##where `digest` is a Base64 formatted HMAC SHA512 digest of the following string: ##
104 104  
105 -````text
106 -METHOD\n
107 -RESOURCE\n
108 -USER\
109 -NONCE\n
110 -DATE\n
111 -PAYLOAD\n
112 -````
105 +##```text
106 +METHOD\n
107 +RESOURCE\n
108 +USER\
109 +NONCE\n
110 +DATE\n
111 +PAYLOAD\n
112 +```##
113 113  
114 -``METHOD` (mandatory) the requested method (in upper case) `RESOURCE` (mandatory) the path to desired resource (without hostname and any query parameters)
115 -`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 `
114 +##`METHOD` (mandatory) the requested method (in upper case) `RESOURCE` (mandatory) the path to desired resource (without hostname and any query parameters)
115 +`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 ##
116 116  
117 -`Example request:`
117 +##Example request:##
118 118  
119 -````bash
120 -curl -X POST \
121 - https://stage-evc.payex.com/payment-api/api/payments/payment-account/balance \
122 - -H 'Accept: */*' \
123 - -H 'Agreement-Merchant-Id: XXX' \
124 - -H 'Authorization: Bearer XXX' \
125 - -H 'Hmac: HmacSHA512 user:21a0213e-30eb-85ab-b355-a310d31af30e:oY5Q5Rf1anCz7DRm3GyWR0dvJDnhl/psylfnNCn6FA0NOrQS3L0fvyUsQ1IQ9gQPeLUt9J3IM2zwoSfZpDgRJA==' \
126 - -H 'Transmission-Time: 2019-06-18T09:19:15.208257Z' \
127 - -H 'Session-Id: e0447bd2-ab64-b456-b17b-da274bb8428e' \
128 - -d '{
129 - "accountIdentifier": {
130 - "accountKey": "7013369000000000000",
131 - "cvc": "123",
132 - "expiryDate": "2019-12-31",
133 - "instrument": "GC"
134 - }
135 -}'
136 -````
119 +##```bash
120 +curl -X POST \
121 + https:~/~/stage-evc.payex.com/payment-api/api/payments/payment-account/balance \
122 + -H 'Accept: */*' \
123 + -H 'Agreement-Merchant-Id: XXX' \
124 + -H 'Authorization: Bearer XXX' \
125 + -H 'Hmac: HmacSHA512 user:21a0213e-30eb-85ab-b355-a310d31af30e:oY5Q5Rf1anCz7DRm3GyWR0dvJDnhl/psylfnNCn6FA0NOrQS3L0fvyUsQ1IQ9gQPeLUt9J3IM2zwoSfZpDgRJA==' \
126 + -H 'Transmission-Time: 2019-06-18T09:19:15.208257Z' \
127 + -H 'Session-Id: e0447bd2-ab64-b456-b17b-da274bb8428e' \
128 + -d '{
129 + "accountIdentifier": {
130 + "accountKey": "7013369000000000000",
131 + "cvc": "123",
132 + "expiryDate": "2019-12-31",
133 + "instrument": "GC"
134 + }
135 +}'
136 +```##
137 137  
138 -`In this example `USER` is user and `SECRET` is secret. `
138 +##In this example `USER` is user and `SECRET` is secret. ##
139 139  
140 -`The plain string to `digest` would then be:`
140 +##The plain string to `digest` would then be:##
141 141  
142 -````text
143 -POST
144 -/payment-api/api/payments/payment-account/balance
145 -user
146 -21a0213e-30eb-85ab-b355-a310d31af30e
147 -2019-06-18T09:19:15.208257Z
148 -{
149 - "accountIdentifier": {
150 - "accountKey": "7013360000000000000",
151 - "cvc": "123",
152 - "expiryDate": "2020-12-31",
153 - "instrument": "CC"
154 - }
155 -}
156 -````
142 +##```text
143 +POST
144 +/payment-api/api/payments/payment-account/balance
145 +user
146 +21a0213e-30eb-85ab-b355-a310d31af30e
147 +2019-06-18T09:19:15.208257Z
148 +{
149 + "accountIdentifier": {
150 + "accountKey": "7013360000000000000",
151 + "cvc": "123",
152 + "expiryDate": "2020-12-31",
153 + "instrument": "CC"
154 + }
155 +}
156 +```##
157 157  
158 -`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.`
158 +##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.##
159 159  
160 -`Final `Hmac` header value: `
160 +##Final `Hmac` header value: ##
161 161  
162 -````text
163 -HmacSHA512 user:21a0213e-30eb-85ab-b355-a310d31af30e:oY5Q5Rf1anCz7DRm3GyWR0dvJDnhl/psylfnNCn6FA0NOrQS3L0fvyUsQ1IQ9gQPeLUt9J3IM2zwoSfZpDgRJA==
164 -````
162 +##```text
163 +HmacSHA512 user:21a0213e-30eb-85ab-b355-a310d31af30e:oY5Q5Rf1anCz7DRm3GyWR0dvJDnhl/psylfnNCn6FA0NOrQS3L0fvyUsQ1IQ9gQPeLUt9J3IM2zwoSfZpDgRJA==
164 +```##
165 165  
166 -`#### Postman example script`
166 +##~#~#~#~# Postman example script##
167 167  
168 -`In pre-request script copy/paste the following snippet:`
168 +##In pre-request script copy/paste the following snippet:##
169 169  
170 -````javascript`
170 +##```javascript##
171 171  
172 -`var user = 'user';
173 -var secret = 'secret';
174 -var transmissionTime = (new Date()).toISOString();
175 -var sessionId = guid();`
172 +##var user = 'user';
173 +var secret = 'secret';
174 +var transmissionTime = (new Date()).toISOString();
175 +var sessionId = guid();##
176 176  
177 -`var hmac = generateHMAC(user, secret, transmissionTime);
178 -console.log('hmac: ' + hmac);`
177 +##var hmac = generateHMAC(user, secret, transmissionTime);
178 +console.log('hmac: ' + hmac);##
179 179  
180 -`//Set header values
181 -pm.request.headers.add({key: 'Hmac', value: hmac });
182 -pm.request.headers.add({key: 'Transmission-Time', value: transmissionTime });
183 -pm.request.headers.add({key: 'Session-Id', value: sessionId });`
180 +##~/~/Set header values
181 +pm.request.headers.add({key: 'Hmac', value: hmac });
182 +pm.request.headers.add({key: 'Transmission-Time', value: transmissionTime });
183 +pm.request.headers.add({key: 'Session-Id', value: sessionId });##
184 184  
185 -`function generateHMAC(user, secret, transmissionTime) {`
185 +##function generateHMAC(user, secret, transmissionTime) {##
186 186  
187 -` var algorithm = "HmacSHA512";
188 - var separator = ":";
189 - var method = request.method.toUpperCase();
190 - var nonce = generateNonce(); //UUID
191 - var date = transmissionTime;
192 -
193 - var uri_path = replaceRequestEnv(request.url.trim()).trim().replace(new RegExp('^https?://[^/]+/'), '/'); // strip hostname
194 - uri_path = uri_path.split("?")[0]; //Remove query paramters
195 - var payload = _.isEmpty(request.data) ? "" : request.data;
196 - var macData = method + '\n'
197 - + uri_path + '\n'
198 - + user + '\n'
199 - + nonce + '\n'
200 - + date + '\n'
201 - + payload + '\n';`
187 +## var algorithm = "HmacSHA512";
188 + var separator = ":";
189 + var method = request.method.toUpperCase();
190 + var nonce = generateNonce(); ~/~/UUID
191 + var date = transmissionTime;
192 +
193 + var uri_path = replaceRequestEnv(request.url.trim()).trim().replace(new RegExp('^https?:~/~/[^/]+/'), '/'); ~/~/ strip hostname
194 + uri_path = uri_path.split("?")[0]; ~/~/Remove query paramters
195 + var payload = _.isEmpty(request.data) ? "" : request.data;
196 + var macData = method + '\n'
197 + + uri_path + '\n'
198 + + user + '\n'
199 + + nonce + '\n'
200 + + date + '\n'
201 + + payload + '\n';##
202 202  
203 -` macData = replaceRequestEnv(macData);
204 - console.log('data to mac: ' + macData);`
203 +## macData = replaceRequestEnv(macData);
204 + console.log('data to mac: ' + macData);##
205 205  
206 -` var hash = CryptoJS.HmacSHA512(macData, secret);
207 - var digest = CryptoJS.enc.Base64.stringify(hash);
208 - return algorithm + " " + user + separator + nonce + separator + digest;
209 -}`
206 +## var hash = CryptoJS.HmacSHA512(macData, secret);
207 + var digest = CryptoJS.enc.Base64.stringify(hash);
208 + return algorithm + " " + user + separator + nonce + separator + digest;
209 +}##
210 210  
211 -`function replaceRequestEnv(input) { //manually set environments to they are populated before hashing
212 - return input.replace(/{{([^)]+)}}/g, function (str, key) {
213 - var value = pm.environment.get(key);
214 - return value === null ? pm.varables.get(key) : value;
215 - });
216 -}`
211 +##function replaceRequestEnv(input) { ~/~/manually set environments to they are populated before hashing
212 + return input.replace(/~{~{([^)]+)}}/g, function (str, key) {
213 + var value = pm.environment.get(key);
214 + return value === null ? pm.varables.get(key) : value;
215 + });
216 +}##
217 217  
218 -`function generateNonce() {
219 - return guid();
220 -}`
218 +##function generateNonce() {
219 + return guid();
220 +}##
221 221  
222 -`function guid() {
223 - function s4() {
224 - return Math.floor((1 + Math.random()) * 0x10000)
225 - .toString(16)
226 - .substring(1);
227 - }`
222 +##function guid() {
223 + function s4() {
224 + return Math.floor((1 + Math.random()) * 0x10000)
225 + .toString(16)
226 + .substring(1);
227 + }##
228 228  
229 -` return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
230 - s4() + '-' + s4() + s4() + s4();
231 -}`
229 +## return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
230 + s4() + '-' + s4() + s4() + s4();
231 +}##
232 232  
233 -````
234 -</details>`
233 +##```
234 +</details>##
235 235  
236 -`### Security documentation`
236 +##~#~## Security documentation##
237 237  
238 -`---`
238 +##~-~--##
239 239  
240 -`* [OAuth2](https://oauth.net/2/)
241 -* [Client Credentials](https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/)
242 -* [The RESTful CookBook: HMAC](http://restcookbook.com/Basics/loggingin/)
243 -* [HMAC - Wikipedia](https://en.wikipedia.org/wiki/HMAC)`
240 +##* [OAuth2](https:~/~/oauth.net/2/)
241 +~* [Client Credentials](https:~/~/www.oauth.com/oauth2-servers/access-tokens/client-credentials/)
242 +~* [The RESTful CookBook: HMAC](http:~/~/restcookbook.com/Basics/loggingin/)
243 +~* [HMAC - Wikipedia](https:~/~/en.wikipedia.org/wiki/HMAC)##
244 244  
245 -`## First App run`
245 +##~#~# First App run##
246 246  
247 -`---`
247 +##~-~--##
248 248  
249 -`**NB! The application expects a PostgreSQL server to be running on localhost with a username `test` and password `test` to exist.**
250 -**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)).**`
249 +##~*~*NB! The application expects a PostgreSQL server to be running on localhost with a username `test` and password `test` to exist.~*~*
250 +~*~*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)).~*~*##
251 251  
252 -`Inside the root directory, do a: `
252 +##Inside the root directory, do a: ##
253 253  
254 -````bash
255 -mvn clean install
256 -````
254 +##```bash
255 +mvn clean install
256 +```##
257 257  
258 -`Run the Spring Boot App:`
258 +##Run the Spring Boot App:##
259 259  
260 -````bash
261 -mvn --projects backend spring-boot:run
262 -````
260 +##```bash
261 +mvn ~-~-projects backend spring-boot:run
262 +```##
263 263  
264 -`Now go to <http://localhost:8080/> and have a look at your new client.`
264 +##Now go to <http:~/~/localhost:8080/> and have a look at your new client.##
265 265  
266 -`## Testing application`
266 +##~#~# Testing application##
267 267  
268 -`---`
268 +##~-~--##
269 269  
270 -`1. Add a new card with provided details from PayEx.
271 -1. Click on newly added Card
272 -1. Click on "initiate payment" to create a new transaction`
270 +##1. Add a new card with provided details from PayEx.
271 +~1. Click on newly added Card
272 +~1. Click on "initiate payment" to create a new transaction##
273 273  
274 -`## Build docker image:`
274 +##~#~# Build docker image~:##
275 275  
276 -`---`
276 +##~-~--##
277 277  
278 -````bash
279 -mvn --projects backend clean compile jib:dockerBuild
280 -````
278 +##```bash
279 +mvn ~-~-projects backend clean compile jib:dockerBuild
280 +```##
281 281  
282 -`## Deploy to local docker:`
282 +##~#~# Deploy to local docker:##
283 283  
284 -`---`
284 +##~-~--##
285 285  
286 -````bash
287 -docker-compose up -d
288 -````
286 +##```bash
287 +docker-compose up -d
288 +```##
289 289  

Tips

Did you know that you can improve XWiki? Take 5 minutes to fill this survey and help this open source project!

Need help?

If you need help with XWiki you can contact: