10-31-2022 9:48 AM
Anyone had experience of calling UK bank Confirmation of Payee (CoP) service from SAP ECC using ABAP with external HTTP REST interfaces?
10-31-2022 10:29 AM
How to call a Web service from ABAP has been asked lots of times, so it's been already answered. Do you have a specific issue?
10-31-2022 10:45 AM
Hi,
The question is specific to the UK Banking Confirmation of Payee (CoP) service interface. I'm asking if there is anybody out there that has experience of implementing this particular interface that may be able to assist with some ABAP code snippets (anonymised of course).
10-31-2022 11:40 PM
You mean, you want to use the basic class CL_HTTP_CLIENT for calling that interface -- or some "higher level" framework? Also do you have a link to an interface description? I could then provide an example of how to call that from SAP BC (which would then be called from ABAP via CALL FUNCTION statement).
11-01-2022 10:47 AM
Hi,
Thanks for responding.
It's a JSON interface and I was assuming it would use CL_REST_HTTP_CLIENT but now I'm not so sure? Might be CL_HTTP_CLIENT.
I've picked out some details from the tech spec provided by the bank. Grateful for any advice you can provide:
[There is a whole section on MLS & TLS certificates which I won't include here]
The data formats for APIs are JSON, we expect
the inbound requests to be in this format and
subsequently responses back for us will also be JSON.
Responses from the COP API will be in the form of a COPAPIResponse, errorResponse or
gatewayErrorResponse.
Expected Headers:
Content-Type - application/json
x-lbg-origin-client-id - A unique client ID is provided for each
client.
Ocp-Apim-Subscription-Key - A unique subscription key is provided
for each client.
x-jws-signature - A signature that is generated using the payload,
KID and private key of the MLS
certificate.
The format of the x-jws-signature should be:
[base64UrlEncode(Header)]..[base64UrlEncode(JSONWebSignature)] i.e. xyz..zyx (
Omitting the
payload )
Example expected Payload to send:
{ "
account": {
"sortCode": "404040",
"accountNumber": "40404040",
"name": "Fred
Bloggs",
"accountType": "Personal",
"identifier": "1234567890123456"
}
}
Identifier field is optional.
In order to verify the authenticity of
requests to use we require that they are signed using the MLS
certificate. The generated signature is then included using the header key
x-jws-signature. The order
of attributes in the payload and the signed payload in the x-jws-signature
must be identical.
Example Of Signature Generation in Javascript (Node.js) ==>
const jws = require('jws');
const { readFileSync } = require('fs');
const privateKey = readFileSync('./mlsPrivateKey.pem', 'utf8');
const payload = {
"account": {
"sortCode": "404040",
"accountNumber": "40404040",
"name": "Fred
Bloggs",
"accountType": "Personal",
"identifier": "1234567890123456"
}
} c
onst header = {
"alg": "RS256",
"kid": "KID_PLACEHOLDER"
}
const signature = jws.sign({ header, privateKey, payload, passPhrase)};
console.info(signature);
---
in C# ==>
using System.Security.Cryptography;
using Jose;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
var payloadData = new Dictionary<string,
object>()
{
{ "sortCode", "123456" },
{ "accountNumber", "12345678" },
{ "name", "Fred Bloggs" },
{ "accountType", "Personal" }
};
var payload = new Dictionary<string, object>()
{
{ "account", payloadData }
};
var headers = new Dictionary<string, object>()
{
{ "kid", "kid_value" }
};
public static String CreateToken(Dictionary<string,
object> headers,
Dictionary<string, object> payload,
string privateRsaKey)
{
RSAParameters rSAParameters;
AsymmetricCipherKeyPair keyPair;
using (var reader = new StreamReader(privateRsaKey))
{
keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
var privateRsaParams = keyPair.Private as RsaPrivateCrtKeyParameters;
rSAParameters = DotNetUtilities.ToRSAParameters(privateRsaParams);
} u
sing var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rSAParameters);
return JWT.Encode(payload, rsa, JwsAlgorithm.RS256, headers);
} v
ar token =
CreateToken(headers, payload, privateKey);
string[] jwsParts = token.Split('.');
var detachedToken = jwsParts[0] + ".." + jwsParts[2];
Note: Above code assumes the private key is in the PKCS#1 RSA format
---
JAVA ==>
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import com.nimbusds.jose.util.Base64URL;
public static RSAPrivateKey readPrivateKey(File
file) throws Exception {
String key = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UT
String privateKeyPEM = key
.replace("-----BEGIN
PRIVATE KEY-----", "")
.replaceAll(System.lineSeparator(), "")
.replace("-----END PRIVATE
KEY-----", "");
byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
KeyFactory keyFactory =
KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} p
ublic static String sign(String kid, RSAPrivateKey keyRsa, String
payload) {
String signString = "";
try {
String jsonHeaders = "{\"alg\":\"RS256\",\"kid\":\"" + kid + "\"}";
String hdr =
Base64URL.encode(jsonHeaders).toString();
String payl =
Base64URL.encode(payload).toString();
String hdrPaylCombine = hdr + "." + payl;
String signature =
createSignature(hdrPaylCombine, keyRsa);
//Return signed string in JWKS format
return signString = hdr
+ ".." + signature;
} catch (Exception e) {
System.out.print("Exception
signing data: " + e);
}
return signString;
}
---
None of the above makes much sense to me as an ABAP programmer.
I created an RFC destination ZBANKRFC (type G) and had a go at putting some code together but I have no idea if it's correct?
11-01-2022 10:48 AM
ENDFORM.
11-24-2022 3:10 PM
As you already have Java code that performs these tasks, implementing it in the SAP Business Connector would be the perfect choice. Especially since one requirement is to apply a digital signature to the output document, and the SAP BC already has the necessary built-in tools for digitally signing documents.
(I am not sure, whether ABAP has standard classes that can perform digital signatures?)
The way to implement the requirement using SAP BC would then be:
I think that if you can use all the above built-in tools of the SAP BC, implementing such a Flow would be a matter of a few minutes. If you have to use some of the above custom Java coding (because of special requirements not covered by the standard tools), it may take a bit more time.
For download and documentation of the SAP BC tool, see https://support.sap.com/sbc-download and https://support.sap.com/en/product/connectors/bc/details.html