Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
asutoshmaharana2326
Active Participant
11,963

Introduction


While exposing SAP GW OData services via SAP APIM (API management), we have encountered one simple requirement to enable server to server authentication between S/4 Hana and SAP APIM system. So that the API consumers will not have to know backend system credentials and they can use policy based APIKey or OAuth 2.0 kind of authentication from Developer portal. Whenever we will make POST, PUT and DELETE HTTP verb, it will require CSRF token validation from backend, so we will try to automate that as well from API management layer.

Main


I will not explain how to expose OData service using SAP APIM in this blog. Those are well documented in other blog by benno_grimm. There are many other blogs as well you can refer.

So, let’s see the policies required to enable backend authentication from APIM.

  • Key value map:


We have created a Key value map for storing credential of backend system.


Key Value Map for Backend Credential




  • Then we will implement below 4 policies in target endpoint.



Policy




  • kvmFetch (KeyValueMapOperations):


This policy will help to retrieve username and password from key value map and assign them to private variables. No condition string required for this policy.
<KeyValueMapOperations mapIdentifier="ES5Credential" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
<Get assignTo="private.BasicAuthUsername" index='1'>
<Key><Parameter>Username</Parameter></Key>
</Get>
<Get assignTo="private.BasicAuthPassword" index='1'>
<Key><Parameter>Password</Parameter></Key>
</Get>
<Scope>environment</Scope>
</KeyValueMapOperations>


  • baAuth (BasicAuthentication):


This policy will help to encode the username and password in Base64 and assign that to Authorization header. No condition string required for this policy.
<BasicAuthentication continueOnError='false' enabled='true' xmlns='http://www.sap.com/apimgmt'>
<Operation>Encode</Operation>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<User ref='private.BasicAuthUsername'></User>
<Password ref='private.BasicAuthPassword'></Password>
<AssignTo createNew="true">request.header.Authorization</AssignTo>
</BasicAuthentication>


  • scCSRF (ServiceCallout):


This policy will help to fetch CSRF token from backend call. Please put below as Condition string. I have used an API provider named ES5 for backend connection in APIM.
(request.verb = "POST" OR request.verb = "PUT" OR request.verb = "DELETE")

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="true" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
<Request>
<Set>
<Headers>
<Header name="x-csrf-token">fetch</Header>
<Header name="Authorization">{request.header.Authorization}</Header>
</Headers>
<Verb>GET</Verb>
</Set>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</Request>
<Response>callOutResponse</Response>
<Timeout>30000</Timeout>
<HTTPTargetConnection>
<APIProvider>ES5</APIProvider>
<Path>sap/opu/odata/IWFND/CATALOGSERVICE/ServiceCollection</Path>
</HTTPTargetConnection>
</ServiceCallout>


  • amCSRF (AssignMessage):


This policy will help to assign CSRF token and cookies to the request message. Please put below as Condition string.
(request.verb = "POST" OR request.verb = "PUT" OR request.verb = "DELETE")

<!-- This policy can be used to create or modify the standard HTTP request and response messages -->
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
<!-- Sets a new value to the existing parameter -->
<Set>
<Headers>
<Header name="x-csrf-token">{callOutResponse.header.x-csrf-token}</Header>
<Header name="Cookie">{callOutResponse.header.Set-Cookie.1};{callOutResponse.header.Set-Cookie.2};{callOutResponse.header.Set-Cookie.3}</Header>
</Headers>
</Set>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<AssignTo createNew="false" type="request">request</AssignTo>
</AssignMessage>


  • Test


We can call from postman.


Testing



Conclusion


I have tried to replicate the same for On-Premises API provided but the service callout policy was failing, but I have used local proxy call in service callout policy and it started working.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="true" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
<Request>
<Set>
<Headers>
<Header name="x-csrf-token">fetch</Header>
<Header name="Authorization">{request.header.Authorization}</Header>
</Headers>
<Verb>GET</Verb>
</Set>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</Request>
<Response>callOutResponse</Response>
<Timeout>30000</Timeout>
<LocalTargetConnection>
<Path><API Base Path></Path>
</LocalTargetConnection>
</ServiceCallout>

 

 
26 Comments
prachetas
Participant
0 Kudos
Great blog Asutosh.
0 Kudos
Asutosh,

thank you for your post - it really helps, but I'm facing the issue when trying to send POST request to SAP on-premise system:

{"fault":{"faultstring":"Invalid access token","detail":{"errorcode":"oauth.v2.InvalidAccessToken"}}}

I set Path in the ServiceCallout Policy, but still have a problem. Do you have any ideas how this can be solved?

Regards,

Olesya
asutoshmaharana2326
Active Participant
Dear Olesya,

I think whatever base path you have mentioned in the service callout policy that might contain a "VerifyAccessToken" OAuth2.0 policy in pre-flow. So you are getting the invalid access token error. you can try assiging the OAuth token first in a variable like below screenshot.


Then you can just basically set up that variable as header in service callout policy.


Please let me know if this solution helps.

BR,

Asutosh Maharana
0 Kudos
Asutosh, thank you for your quick answer.

I added what you wrote, but now have an error:

"Unresolved variable : request.header.OAuthToken"


and



May be something wrong with any other settings?



Best Regards,

Olesya
asutoshmaharana2326
Active Participant
Dear Olesya,

You have done a little bit wrong. in the amOAuthToken policy you are changing the "response". Kindly put below xml.
<!-- This policy can be used to create or modify the standard HTTP request and response messages -->
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>

<!-- Sets a new value to the existing parameter -->
<Set>
<Headers>
<Header name="OAuthToken">{request.header.Authorization}</Header>
</Headers>
</Set>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<AssignTo createNew="false" type="request">request</AssignTo>
</AssignMessage>

Check the "AssignTo" in the xml.

BR,

Asutosh Maharana
0 Kudos
Asutosh, thank you.

I changed the xml as you mentioned,

but now in Postman i am getting:

{

    "fault": {

        "faultstring": "Execution of ServiceCallout scCSRF failed. Reason: ResponseCode 401 is treated as error",

        "detail": {

            "errorcode": "steps.servicecallout.ExecutionFailed"

        }

    }

}

And in the debug I see the following:



May by Api base path is wrong


Regards,

Olesya
asutoshmaharana2326
Active Participant
Dear Olesya,

Can you use the same base path of your API proxy in the service callout (if you are putting service callout in API Proxy "A" then put the base path of API proxy "A" in the service call out policy ...Kind of a loopback). Please do not use any other API Proxy. and the error you are getting is due to the api proxy base path you are using is not part of any product.

BR,

Asutosh Mahrana
0 Kudos

Asutosh, I have created a new product and assigned my api proxy.

I am still struggling with the error:

{
    "fault": {
        "faultstring": "Execution of ServiceCallout scCSRF failed. Reason: ResponseCode 401 is treated as error",
        "detail": {
            "errorcode": "steps.servicecallout.ExecutionFailed"
        }
    }
}
Here is my settings:

I use in the "Path" field in Policy "Service Callout" the Path from "Overview" tab of my API. Is it right?

 

Regards,

Olesya

asutoshmaharana2326
Active Participant
0 Kudos
Dear Olesya,

Add the "OAuth Token Generator" API Proxy as well in that new product and use the application (clientid and client secret) which ever you have subcribed to that new product in dev portal.

BR,

Asutosh Maharana
asutoshmaharana2326
Active Participant
0 Kudos
API Base path with /

Do not remove / while putting it in Service callout.
0 Kudos
Asutosh, thank you!

I use exactly like in overview tab - with /

I have product with "OAuth Token generator" and I used it when i didn't add policies about x-csrf-token and it worked fine. But now still have 401

 

Regards,

Olesya
asutoshmaharana2326
Active Participant
0 Kudos
Dear Olesya,

it's working fine for me. Please do the following.

  1. assign your Oauth Generator and oauth verifier api proxy to the same product.

  2. use the csrf token handling policies to oauth verifier flow. with service call out base path as the oauth verifier api proxy. and please assign oauth verifier policy and the assign message policy in the proxy endpoint preflow.

  3. create appication for that product.

  4. use that app keys to generate the oauth token.

  5. then use that token to make call to the oauth verifier api proxy.


I have done the same and it was working fine.

if issues kindly connect me over linkedin i may help you.

BR,

asutosh maharana
0 Kudos
Asutosh, thank you very much.

It really helped.

The problem was solved by adding the resource in the API base path.

 

Kind regards,

Olesya.
former_member793291
Discoverer
0 Kudos

Hi Asutosh,

Thank you very much for the detailed guide. I am facing some difficulty with a POST call.

I am encountering the following error:

error:Execution of ServiceCallout scCSRF failed. Reason: ResponseCode 404 is treated as error
type:ErrorPoint
state:TARGET_REQ_FLOW
error.class:com.apigee.kernel.exceptions.spi.UncheckedException
error.cause:ResponseCode 404 is treated as error

 

Using the debugger I found the following error:

Would you be able to help here? The error is not encountered for GET calls and only POST calls (as expected)

Best regards,

Chamode

sudhiryesu
Explorer
0 Kudos
Hi asutoshmaharana2326,

Thanks for the post. After deploying with the policies, API can be accessed without any credentials (bypassing the credentials in the request). Could you please provide a solution to validate the  credentials in the request.

Thanks,

Sudhir Yesu
TiagoRibeiro
Product and Topic Expert
Product and Topic Expert
0 Kudos
Hello dear Asutosh, thank you for the blog.

It's interesting and solves the problem to use APIs to POST actions.

However, what should be used in case we deploy a standard API from a public S/4HANA Cloud instance? I haven't used an API Provider for such.

What should we define in the Policy for the CSRF bypass?

 

Thank you

Tiago Ribeiro
asutoshmaharana2326
Active Participant
Dear Sudhir,

You can try removing below 2 policies, then you have to send the credentials from Client side.

kvmFetch  and baAuth

 

Let me know if you have any issues.

Thanks,

Asutosh

 
asutoshmaharana2326
Active Participant
Dear Tiago,

you can use the service callout policy with "HTTPTargetConnection/URL" element instead of using "HTTPTargetConnection/APIProvider" element. Please go through the below SAP Documentation. Check example 2.

Service callout policy

Thanks,

Asutosh
TiagoRibeiro
Product and Topic Expert
Product and Topic Expert
0 Kudos

Thank once again Asutosh. I've checked the help document but was not sure which URL to use.

The API Proxy endpoint or the real api service endpoint? 

Another question is if all the 4 policies will be incoming request or outgoing-incoming-outgoing-incoming. 

Will try with the element you mentioned.

Thank you

Tiago Ribeiro

sudhiryesu
Explorer
0 Kudos
Thanks Asutosh. Now, it is working as expected.
Keerthana
Participant
0 Kudos
Hi chamode ,

Did you solve this? I am also facing the same issue.If you resolved it,could you please guide me.

Thanks & Regards,
Keerthana
vamsi_dhar_reddy
Explorer
0 Kudos
Hello asutoshmaharana2326,

 

thanks for the great blog. I'm facing an issue while connecting with sap cpi using CSRF. In service callout, I'm getting an error. Thanks in advance

asutoshmaharana2326
Active Participant
0 Kudos
Dear,

Please remove this variable from amCSRF (AssignMessage) policy. Just like Below. May be your Backend is only giving 2 cookies.

 
<!-- This policy can be used to create or modify the standard HTTP request and response messages -->
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
<!-- Sets a new value to the existing parameter -->
<Set>
<Headers>
<Header name="x-csrf-token">{callOutResponse.header.x-csrf-token}</Header>
<Header name="Cookie">{callOutResponse.header.Set-Cookie.1};{callOutResponse.header.Set-Cookie.2</Header>
</Headers>
</Set>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<AssignTo createNew="false" type="request">request</AssignTo>
</AssignMessage>
vamsi_dhar_reddy
Explorer
0 Kudos

Hello,

I have changed it and now it's working fine.

 

Thank you so much!!

0 Kudos
How to use CSRF token code when we are calling multiple target endpoints(regional systems) in a single API.
As we have a <http target connection> tag in service callout policy where we mention the target systems.
sa48907
Explorer
0 Kudos

Hi @asutoshmaharana2326 

I am trying as per your blog I am calling S4 HANA Standard Purchase Order API. WHen am testing direct S4 host name and testing API am getting JSON response for below URL

Kindly guide me why am getting SAML error. When am calling same ODATA service from CPI its working and also I linked CPI Iflow to APIM and that also worked. Only not working is when am testing from APIM to S/4 via cloud connector. Please help me and do the needful.

https://host:443/sap/opu/odata/sap/API_PURCHASEORDER_PROCESS_SRV/A_PurchaseOrder?&sap-client=120$for... eq '4200004060'

Hence I tried now in APIM configuration as per below

base path : /API_PURCHASEORDER_PROCESS_SRV and even i tried /sap/opu/odata as per ur blog copy pasted same error SAML error.

URL : i tried both --> /sap/opu/odata/sap/ and also I tried another default URL came from config --> /sap/opu/odata/sap/API_PURCHASEORDER_PROCESS_SRV

amarseli001_0-1727363682193.png

 

Both cases same error. Remaining all policies I configured correctly.

Am getting this error:

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no"><meta http-equiv="pragma" content="no-cache" /></head><body style="background-color:#FFFFFF" onload="var url=window.location.hash;if(url&&0!==url.length){var anchorCookie='oucrsqvipoosrjhvjuaehbyns_anchor=&quot;' + encodeURIComponent(url) + '&quot;';anchorCookie=anchorCookie+'; Secure; SameSite=None';document.cookie=anchorCookie}document.forms[0].submit()"><p><script language="javascript">document.write("Please wait ...");</script></p><noscript><p>Note: Your browser does not support JavaScript or it is turned off. Press the button to proceed.</p></noscript><form method="post" action="https://accounts.sap.com/saml2/idp/sso"><input type="hidden" name="SAMLRequest" value="X509 certificate string "/><input type="hidden" name="RelayState" value="oucrsqvipoosrjhvjuaehbyns"/><noscript><input type="submit" value="Continue"/></noscript></form></body></html>

Labels in this area