Friday, November 16, 2018

Beware: SAP Gateway services can default not be Cross-Domain / CORS accessed

In our business context we have non-SAP web applications that invoke SAP Gateway services to retrieve business data. This week I was involved in a rewrite of such application (the need for rewrite being that another consumed data source, namely a SharePoint List, was moved to a new destination, from on-premise SharePoint 2010 to Office 365 SharePoint Online). While testing the updated application codebase, I noticed that I unexpected run into data retrieval issues with getting the SAP data; on code that I did not even touch. After some investigation, the cause appeared to be a Cross Domain issue: the consumed SAP Gateway services are deployed on another domain as the application (whether run local via Node.js, or on the target webserver). The problem was known to application owner, and pragmatic solution to use the application only from Internet Explorer (IE); as that includes an option to disable the Cross Domain check. Mind you, I initially did my testing via Chrome and Edge; both browsers do not support to skip the Cross Domain check in their default usage behavior.
Having a developer and solution-aware mindset, I then thought to fix the application itself to enable Cross Domain data access. All browser support this via CORS. Change in the JavaScript codebase should be simple, call the service requests with Cross-Domain awareness: see Using CORS. However, even with this code change the application (or rather the browser) failed to retrieve the data from the SAP Gateway services. With developers tools I inspected the network traffic, and identified the problem. The PreFlight request issued by the browser for non-simple CORS data requests, are responded by the SAP Gateway application with HTTP 401.
This is not compliant with the CORS specification: Preflight requests must not include the user credentials. See the W3C Cross-Origin Resource Sharing specification, preflight request
All modern browsers obey to the CORS specification, and do intentionally not include Authorization in the Preflight OPTIONS request. SAP NetWeaver should respond with sending the CORS response, and next the succeeding actual http request (with GET, POST, PUT, or DELETE method) will include Authorization information: this is the call that actually goes into the SAP backend to access the stored business data.
The SAP Gateway specific cause is written in post How to Enable CORS on SAP NetWeaver Platform:
...why is the Preflight Request failing? The issue lies in how a Preflight Request is constructed. According to the CORS specification, the Preflight Request must NOT carry any user credential. As most applications on NetWeaver require user authentication, the Preflight Request will get an “HTTP 401 Unauthorized” error message, thus failing the request.
The post also describes an approach to resolve it directly on SAP Netweaver level, via combination of SICF configuration and ICM rewrite rules. Another approach can be to utilize a reverse proxy in the network infrastructure, and let that handle the CORS handling in front of the SAP NetWeaver destination.