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