Previously, communication from cloud to on-premise via a technical communication user was only possible via basic authentication. Here, I try to cover a new, more secure means to achieve this using OAuth and x.509 certificates.
. That way, I do not have to share any credentials of the on-premise system with the cloud environment. Additionally I can use either secret based or mTLS based authentication mechanisms to obtain the access token, where the latter is generally considered more secure than basic authentication. We cover the mTLS based authentication mechanism in this blog.
Learn more here (Authenticating Users against On-Premise Systems | SAP Help Portal).
The following diagram depicts the flow from SAP S/4HANA Cloud, Public Edition.
For general information on what OAuth with mTLS means, refer https://oauth.net/2/mtls/ and https://datatracker.ietf.org/doc/html/rfc8705 . If you are unaware of how mTLS works, it is recommended to read through the above links before continuing.
Here, I consume an OData service and a SOAP service from an on-premise ABAP system via technical user propagation using OAuth with mTLS (Certificate based authentication). I
For OData, we choose the standard product master service available with “/sap/opu/odata/SAP/API_PRODUCT_SRV/”. For SOAP, we use a custom SQRT service. However, both of these are just examples and the process should be the same for any other OData/SOAP services.
All steps of the blog would be applicable for both SAP S/4HANA cloud public edition and SAP BTP ABAP Environment unless stated otherwise.
Persona: Developer in the ABAP system hosted on SAP BTP ABAP Environment or Developer in SAP S/4HANA Public Cloud system (using SAP S/4HANA Cloud ABAP Environment aka Embedded Steampunk)
First set up the code to read data from an on-premise system. Here, I consume the standard product OData service and a custom SOAP service that calculates square root. This blog focuses on the security aspects when consuming services from on-premise systems.
Create a new service consumption model object
Choose the Remote Consumption Mode as OData and provide a suitable name, description
Upload the service metadata of the standard product API
Follow through the wizard to have the required objects generated
The path to the standard Product OData service can be found from the SEGW transaction or the SAP Gateway client in the on-premise system.
On the ABAP system on the SAP BTP ABAP Environment or SAP S/4HANA Cloud, Create an outbound service in ADT with type HTTP and provide the default path prefix as identified above.
Now, we need to expose the service for communication. Here, we create a communication scenario with ADT
Under the outbound tab, add the outbound service created above, ensure and publish the communication scenario
CLASS zcl_product DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_PRODUCT IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA:
lt_business_data TYPE TABLE OF za_product,
lo_http_client TYPE REF TO if_web_http_client,
lo_client_proxy TYPE REF TO /iwbep/if_cp_client_proxy,
lo_request TYPE REF TO /iwbep/if_cp_request_read_list,
lo_response TYPE REF TO /iwbep/if_cp_response_read_lst.
TRY.
" Create http client
DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_COM_PROD'
comm_system_id = 'S4H_1909_CAL'
service_id = 'Z_PRODUCT_ROOT_REST' ).
lo_http_client = cl_web_http_client_manager=>create_by_http_destination( lo_destination ).
ASSERT lo_http_client IS BOUND.
" If you like to use IF_HTTP_CLIENT you must use the following factory: /IWBEP/CL_CP_CLIENT_PROXY_FACT
lo_client_proxy = cl_web_odata_client_factory=>create_v2_remote_proxy(
EXPORTING
iv_service_definition_name = 'Z_SCM_PRODUCT'
io_http_client = lo_http_client
iv_relative_service_root = '' ).
" Navigate to the resource and create a request for the read operation
lo_request = lo_client_proxy->create_resource_for_entity_set( 'A_PRODUCT' )->create_request_for_read( ).
lo_request->set_top( 50 )->set_skip( 0 ).
" Execute the request and retrieve the business data
lo_response = lo_request->execute( ).
lo_response->get_business_data( IMPORTING et_business_data = lt_business_data ).
out->write( lt_business_data ).
CATCH /iwbep/cx_cp_remote INTO DATA(lx_remote).
" Handle remote Exception
" It contains details about the problems of your http(s) connection
out->write( lx_remote->get_longtext( ) ).
CATCH /iwbep/cx_gateway INTO DATA(lx_gateway).
" Handle Exception
out->write( lx_gateway->get_longtext( ) ).
CATCH cx_web_http_client_error INTO DATA(lx_web_http_client_error).
" Handle Exception
out->write( lx_web_http_client_error->get_longtext( ) ).
CATCH cx_http_dest_provider_error INTO DATA(lx_destination).
"handle exception
out->write( lx_destination->get_longtext( ) ).
ENDTRY.
ENDMETHOD.
ENDCLASS.
Choose the Remote Consumption Mode as Web Service and provide a suitable name/description
Upload the WSDL metadata of the SOAP service
Follow through the wizard to have the required objects generated
Identify the request URI for the SOAP service from the SOAMANAGER transaction on the on-premise system
Identify the service interface. This is the proxy class in the service consumption model created for the SOAP service
Create an outbound service using ADT with type SOAP in the ABAP system on the SAP BTP ABAP Environment or SAP S/4HANA Cloud, public edition
Now, we need to expose the service for communication. Here, we create a communication scenario with ADT
Under the outbound tab, add the outbound service created above, ensure for authentication with grant type “Client Credentials” and publish the communication scenario
CLASS zcl_soap_sqrt DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_SOAP_SQRT IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
try.
data(destination) = cl_soap_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_COM_SQRT_SOAP'
).
data(proxy) = new zco_z_sqrt_srv(
destination = destination
).
data(request) = value zsqrt_fm( input_num = 4 ).
proxy->zsqrt_fm(
exporting
input = request
importing
output = data(response)
).
out->write( response-result ).
"handle response
catch cx_soap_destination_error INTO DATA(destination_ex).
"handle error
out->write( destination_ex->get_longtext( ) ).
catch cx_ai_system_fault INTO DATA(system_ex).
"handle error
out->write( system_ex->get_longtext( ) ).
catch zcx_zsqrt_fm_exception INTO DATA(fm_ex).
"handle error
out->write( fm_ex->get_longtext( ) ).
endtry.
ENDMETHOD.
ENDCLASS.
Persona: Sub account administrator or space developer on SAP Business Technology Platform
I first need to obtain an OAuth client that is provided by an authorization server. This is trusted by the SAP Cloud Connector (trust established by connecting the Cloud Connector to a sub account).
One way to do so is by creating an instance of the Authorization and Trust Management service in the sub account connected to the Cloud Connector, which results in an OAuth client, which can be used to obtain access tokens. This is done in the sub account connected to the SAP BTP ABAP Environment system or to SAP S/4HANA Cloud
Search for the Authorization and Trust Management Service
Persona: Subaccount administrator or space developer on SAP BTP, administrator on the ABAP system on SAP BTP ABAP Environment/SAP S/4HANA Cloud
To be able to use a client certificate for the OAuth flow, we need to map the certificate of the ABAP system to the OAuth Client (XSUAA instance) we just created.
{
"credential-type": "x509",
"x509": {
"certificate": "<public key>",
"certificate-pinning": false
}
}
Persona: Administrator of the ABAP system hosted on SAP BTP ABAP Environment or Administrator in the SAP S/4HANA Public Cloud system
The Communication System is used to pass the OAuth client details to the ABAP system and to configure how and where the access token should be transported.
Persona: Administrator of the ABAP system hosted on SAP BTP ABAP Environment or Administrator in the SAP S/4HANA Public Cloud system
Persona: Cloud connector administrator
Documentation: Configure Subject Patterns for Principal Propagation | SAP Help Portal
To define how the OAuth access token shall be handled in the Cloud Connector and how a resulting client certificate should look like, we define a pattern, which is applied to the incoming access token.
In our example we take the client id and put it into the CN of the subject name.
Persona: Administrator
To be able to authenticate a user with the certificate issued by the Cloud Connector, we map the Subject (OAuth Client ID) and Issuer (Cloud Connector) combination to an actual user in the on premise system.
Persona: Developer, Cloud connector administrator, Subaccount administrator/space developer
Run the classes implementing IF_OO_ADT_CLASSRUN that we defined above for the SOAP and OData services in ADT. Notice the output in the console.
To verify this call indeed happened with the technical user, check the most recent requests from cloud to on-premise in the cloud connector under the “Monitor” menu item. Notice the “User” column reflects the client ID
To verify at the on-premise system, use transaction STAD and filter with the technical user configured during the explicit mapping
Notice the calls indeed happened with this technical user