cancel
Showing results for 
Search instead for 
Did you mean: 

Issue into convert XML using UDF

0 Kudos

My requirement:

I have scenario to develop SAP ECC<->PI/PO<->Third party API.

API will accept only encrypted data and encrypted Key and for Response it will send decrypted data and we need to decrypt data using same key that we have generated at request time.

Sample Request Json data

{"UserName": "demo.user@test.com","Password": "Text@XXXXX" }

After Encrypted Request Payload

{

"data": "dsDCgys2hVbVm7cMQbKwEDwZyjcD7mJnZ43w7/2j2DHJNwc93MZ5flWS3kM9YZ2Fdum rz/N+l4EhB7KOUSNP69JJ+318mnLD9x3i117itvhdIagznSTEWSyXBI62nykygIPg==",

"app_key": "VuvDyKRagUXBXC2Ikdx73RfVqrKJoKOHP/GSEhqU+NWasCwP/+5kE/ +RSJDk2kusVZokFMcHI0Ute+6cqjhnRrbMtpS2z284wziDspKJ4zZMl1Ms2aPgemt6TvYnRHMH/jaAjRZ8BivD38qBs6 NeD06u2DrD+ni4UDiJJ2AmbNvH8ui0SLU3K5EbzfbW72W05aQj3hZqpM97ZVAJuXaTDZg=="

}

Here data will contain encrypted format of username and password and app_key will contain encrypted AES 256-bit key.

And for Response Payload

{

"data": "4gfnGc0PVEZs5rPQojn9tZ2u8Gk+LuWoSyLYy2MWe1MfGylI2i7f9gv7zmFBjrYeOVpxVcqcvPEgsvAmkXSADWh2c5",

"status_cd": 1

}

Now need to decrypt with same key that generated at request time .

So finally I get response like below:

Decrypted Response Payload

{

"auth-token": "68f123a2fb7a5126b19c76870850135a4b16d4",

"expiry": 360

}

Development:

So I tried using REST lookup in UDF.

Encryption and decryption is working correctly in my code that I have checked using some testing tool.

But I got below error when I test mapping.

Mapping:

UDF :

  AbstractTrace trace = container.getTrace();
  // AbstractTrace trace = getTrace();
  String resultString = "";
  String data = "";
  String status_cd = "";
  String auth_token = "";
  try {
   String ECB = "AES/ECB/PKCS5Padding";
   byte[] skey1 = new byte[1000];
   String skeyString;
   Random r = new Random();
   int num = r.nextInt(10000);
   String knum = String.valueOf(num);
   byte[] knumb = knum.getBytes();
   skey1 = knumb;
   skeyString = new String(skey1);
   KeyGenerator kgen = KeyGenerator.getInstance("AES");
   SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
   sr.setSeed(knumb);
   kgen.init(256, sr); // 256 bits available
   SecretKey skey = kgen.generateKey();
   String encodedKey = Base64.getEncoder().encodeToString(skey.getEncoded());
   System.out.println("AES Symmetric Random key = " + encodedKey);
   // Encrypted AES key Using RSA public key certificate
   FileInputStream fin = new FileInputStream("F:\\RSA_CERTI\\DERX509.cer");
   // InputStream fin =
   // this.getClass().getClassLoader().getResourceAsStream("DERX509.cer");
   CertificateFactory f = CertificateFactory.getInstance("X.509");
   X509Certificate certificate = (X509Certificate) f.generateCertificate(fin);
   PublicKey pk = certificate.getPublicKey();
   Cipher rsa = Cipher.getInstance("RSA");
   rsa.init(Cipher.ENCRYPT_MODE, pk);
   byte[] ecryptedbtyekey = rsa.doFinal(encodedKey.getBytes("UTF-8"));
   String app_key_Input = Base64.getEncoder().encodeToString(ecryptedbtyekey);
   System.out.println("RSA Encrpted Key = " + app_key_Input);
   // input by payload channel
   String Auth_token = "";
   String Expiry = "";
   String Status_cd = "";
   // generate the input xml for rest look up
   String inputString = UserName[0]+Password[0];
   byte[] bytebase64input = inputString.getBytes();
   String BaseStringoutput = Base64.getEncoder().encodeToString(bytebase64input);
   //encrypt code
   byte[] test = BaseStringoutput.getBytes();
   Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
   cipher.init(Cipher.ENCRYPT_MODE, skey);
   byte[] byteEncyptoutput = cipher.doFinal(test);
   String data_Input = Base64.getEncoder().encodeToString(byteEncyptoutput);
   // System.out.println("AES Encerpted Output= "+data);
   // String loginxml = "<?xml version=\"1.0\"
   // encoding=\"UTF-8\"?><ns0:XXXXX_Request_MT
   // xmlns:ns0=\"http://XXXXXNamspace”> " +
   // "<data>"+data_Input+"</data>" +
   // "<app_key>"+app_key_Input+"</app_key></ns0:XXXXX _Request_MT>";
   
   /* create document for payload call */
   DocumentBuilderFactory factory1 = DocumentBuilderFactory.newInstance();
   DocumentBuilder builder1 = factory1.newDocumentBuilder();
   Document docOut2 = builder1.newDocument();
   TransformerFactory tf2 = TransformerFactory.newInstance();
   Transformer transform2 = tf2.newTransformer();
   Element root2, child5, child6;
   // Node textChild;
   root2 = docOut2.createElement("ns0:XXXXXX_Request_MT");
   root2.setAttribute("xmlns:ns0", "http://XXXXXXNameSpace");
   child5 = docOut2.createElement("data");
   child6 = docOut2.createElement("app_key");
   child5.setTextContent(data_Input);
   child6.setTextContent(app_key_Input);
   root2.appendChild(child5);
   root2.appendChild(child6);
   docOut2.appendChild(root2);
   transform2.setOutputProperty(OutputKeys.INDENT, "yes");
   transform2.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
   DOMSource source2 = new DOMSource(docOut2);
   StreamResult result2 = new StreamResult(new StringWriter());
   transform2.transform(source2, result2);
   String loginxml = result2.getWriter().toString();
   // perform the rest look up
   Channel channel = LookupService.getChannel("BC_Busine_comp", "CC_REST_Receiver_CC");
   // trace.addInfo(channel.toString());
   SystemAccessor accessor = null;
   accessor = LookupService.getSystemAccessor(channel);
   InputStream inputStream = new ByteArrayInputStream(loginxml.getBytes());
   Payload payload = LookupService.getXmlPayload(inputStream);
   Payload SOAPOutPayload = null;
   SOAPOutPayload = accessor.call(payload);
   InputStream inp = SOAPOutPayload.getContent();
   /*end payload call */
   
   /* read documents from payload input stream */ 
   DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   DocumentBuilder builder = factory.newDocumentBuilder();
   Document document = builder.parse(inp);
   // NodeList stats =
   // document.getElementsByTagName("ns0:XXXXX_Respo_MT");
   NodeList stats = document.getChildNodes();
   //get one by one node value
   for (int i = 0; i < stats.getLength(); i++) {
    Node node = stats.item(i);
    if (node != null) {
     if (node.getNodeName().equals("data"))
      data = node.getNodeValue();
     else if (node.getNodeName().equals("status_cd"))
      status_cd = node.getNodeValue();
    }
   }
   /* end read from xml document readed from payload */
   
   /* Base dncryption and docode */
   byte[] testdec = data.getBytes();
   byte[] BaseDecStringOut = Base64.getDecoder().decode(testdec);
   cipher.init(Cipher.DECRYPT_MODE, skey);
   byte[] byteDEcyptoutput = cipher.doFinal(BaseDecStringOut);
   String tessty = new String(byteDEcyptoutput);
   byte[] byteDecrptOutput = tessty.getBytes();
   byte[] BaseDECRYoutput = Base64.getDecoder().decode(byteDecrptOutput);
   String DecrptedOutput = new String(BaseDECRYoutput);
   /* end decryption */
   
   /* read auth key for auth token and expiry */
   String[] responsesplit = DecrptedOutput.split(",");
   String[] split1 = responsesplit[0].split(":");
   String[] split2 = responsesplit[1].split(":");
   
   String expiry = "";
   if (split1[0].contains("auth-token"))
    auth_token = split1[1];// .replace("\"", "");
   else if (split1[0].contains("expiry"))
    expiry = split1[1].replace("}", "");
   if (split2[0].contains("auth-token"))
    auth_token = split2[1];// .replace("\"", "");
   else if (split2[0].contains("expiry"))
    expiry = split2[1].replace("}", "");
   /* end auth key reading */
     
   /* create document for output xml */
   Document docOut = builder.newDocument();
   TransformerFactory tf = TransformerFactory.newInstance();
   Transformer transform = tf.newTransformer();
   Element rootOutput, expiryNode, authTokenNode, statusCdNode;
   
   // root=docOut.createElement("ns0:XXXX_Respo_MT");
   // root.setAttribute("xmlns:ns0","http://XXXXXXXNameSpace");
   authTokenNode = docOut.createElement("auth_token");
   expiryNode = docOut.createElement("expiry");
   statusCdNode = docOut.createElement("status_cd");
   authTokenNode.setTextContent(auth_token);
   expiryNode.setTextContent(expiry);
   statusCdNode.setTextContent(status_cd);
   // rootOutput.appendChild(child1); //on requirement bases
   // rootOutput.appendChild(child);
   // rootOutput.appendChild(child2);
   // docOut.appendChild(root);
   
   docOut.appendChild(authTokenNode);
   docOut.appendChild(expiryNode);
   docOut.appendChild(statusCdNode);
   transform.setOutputProperty(OutputKeys.INDENT, "yes");
   transform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
   DOMSource source = new DOMSource(docOut); 
   StreamResult result3 =   new StreamResult(new StringWriter()); 
   transform.transform(source,   result3); 
   resultString = result3.getWriter().toString();
   
   /* output xml document end */   
   /* if need to convert one by one node into result object */
   InputStream inputStream3 = new ByteArrayInputStream(resultString.getBytes()); 
   Document document3 =builder.parse(inputStream3);
   
   // NodeList listn1 = document3.getElementsByTagName("ns0:XXXX_Respo_MT");
   NodeList listn1 = document3.getChildNodes();
   
   for (int i = 0; i < listn1.getLength(); i++) {
    Node node1 = listn1.item(i);
    if (node1 != null)  {
     if(node1.getNodeName().equals("auth_token")) {
      result.addValue(  "<auth_token>"+node1.getNodeValue().trim()+"</auth_token>"); 
     }
     else if(node1.getNodeName().equals("expiry")) {
      result.addValue(  "<expiry>"+node1.getNodeValue().trim()+"</expiry>" ); 
     } else   if(node1.getNodeName().equals("status_cd")) {
     result.addValue("<status_cd>"+node1.getNodeValue().trim()+   "</status_cd>"); 
     }
    }
   }
   /* end document to convert one by one result value */
   /* if put directly into result value by hard code xml nodes */
   // result.addValue( "<auth_token>"+auth_token+"</auth_token>");
   // result.addValue( "<expiry>"+expiry+"</expiry>" );
   // result.addValue("<status_cd>"+status_cd+"</status_cd>");
   result.addValue(auth_token);
   result.addValue(expiry);
   result.addValue(status_cd);
   /* end hard coded nodes */
   
   /* xml output string added into result */
  //  result.addValue(resultString);
  // return auth_token;
  } catch (Exception exception) {
   getTrace().addDebugMessage(exception.getMessage() + exception.getLocalizedMessage());
   throw new StreamTransformationException(exception.getMessage() + exception.getLocalizedMessage());
  }
//   return ""; 

<br>

1.Please suggest me to solve error.

2.I also want to know how to get return three value form UDF and map to target structure.

Thanks and Regards

Jatin Sharma.

Accepted Solutions (0)

Answers (1)

Answers (1)

rasjoshi
Active Contributor
0 Kudos

Hi Jatin,

I think something wrong while creating target structure. Did you give it a try with parent node e.g. RECORDS ?

I was having a requirement to get access token from rest api and use it at header level while sending actual data.

I received access token in JSON format and stored it at dynamic attribute. Please check if below piece of code help you -

String token = "";

String id = "";

StringBuffer sb = new StringBuffer();

// 1. Get a system accessor for a channel.

String party = ""; // emtpy values cannot be passed from Directory to the mapping parameters.

Channel channel = LookupService.getChannel(party,"BC_*", "CC_RCVR_*_LOOKUP");

SystemAccessor accessor = LookupService.getSystemAccessor(channel);

getTrace().addInfo("Parameters for Token Lookup - Channel: "+channel);

try{

// 2. Create a payload according to the data type.

// Use service.getBinaryPayload() for binary payload,

// or service.getTextPayload() for text payloads.

InputStream inputStream;

String reqString ="grant_type=password&client_id=*****&client_secret=*****&username=******@**.com.*****&password=*******";

getTrace().addDebugMessage("Request: "+reqString);

inputStream = (InputStream) new ByteArrayInputStream(reqString.getBytes());

com.sap.aii.mapping.lookup.Payload payload = LookupService.getXmlPayload(inputStream);

// 3. Execute lookup.

com.sap.aii.mapping.lookup.Payload result = accessor.call(payload);

// 4. Parse result, could be better realized with a real JSON parser

byte[] b = new byte[4096];

for (int n; (n = result.getContent().read(b)) != -1;){

sb.append(new String(b,0,n));

}

getTrace().addDebugMessage("Response: "+sb);

int i =sb.indexOf("\"access_token\":\"")+16;

int j = sb.indexOf("\"instance_url\"");

token = sb.substring(i,j - 2);

getTrace().addInfo("Token: "+token);

}

catch (Exception e){

e.printStackTrace();

}

finally{

// 5. close the accessor in order to free resources.

if (accessor!=null) accessor.close();

}

// return token;

//Dynamic Configuration

getTrace().addInfo("Token: "+token);

//String namespace = "http://sap.com/xi/XI/System/REST";

//String AccessToken = "";

Map map = container.getTransformationParameters();

DynamicConfiguration conf = (DynamicConfiguration) map.get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);

if (conf != null) {

//getTrace().addInfo("Access_Token: "+Access_Token);

DynamicConfigurationKey confKey = DynamicConfigurationKey.create( "http://sap.com/xi/XI/System/REST", "Access_Token");

conf.put(confKey, token);

}

//getTrace().addInfo("Access_Token: "+Access_Token);

return "";

BR,

Rashmi

rasjoshi
Active Contributor
0 Kudos

Also dont know why you using execution type as Context...

0 Kudos

Hello Rashmi,

Thanks for your inputs, I have changed my approach to consume APIs, I am not using any lookup in that. further I have handled all the encryption and decryption in UDF and Also Global Variable to store value and used it same at response time.

Thanks and Regards,

Jatin Sharma