Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
manu_xu
Explorer

Background


SAC has delivered multi-actions public APIs in release 2023.15. The APIs can be used to trigger multi-actions execution and query the execution results afterwards. With this it offers a flexible way to integrate SAC workflows into external applications to realize various bussiness scenarios.


The APIs have been published to SAP Business Accelerator Hub: https://api.sap.com/api/MultiActions_API/overview. The introduction of APIs can also be found in SAC help: https://help.sap.com/docs/SAP_ANALYTICS_CLOUD/14cac91febef464dbb1efce20e3f1613/e5ade1ed7c274d929a18b...


This blog is supposed to highlight the essential preparations, and to provide some typical samples to try out the APIs meanwhile you can find more details of the API definitions in above pages.



Preparation


Authentication & Authorization


Multi-actions Public API is supposed to be conducted under business user context. The API user need to configure the authentication & authorization properly to specify the desired business user in SAC. Generally there're 2 major options to configure the authentication and authorization. (Please notice that auth type "client credentials" is not supported in multi-actions public APIs, since multi-actions cannot be conducted under technical user context for the time being.)



OAuth2 Authorization Code Workflow


See https://help.sap.com/docs/SAP_ANALYTICS_CLOUD/14cac91febef464dbb1efce20e3f1613/0c1fb5e6ef1f46acb8377..., the part Configuring OAuth 2.0 Authorization Code Grant Workflow (3-legged OAuth) illustrates how to authenticate and authorize the user following OAuth2 Authorization Code flow in SAC. (As multi-actions API is supposed to be conducted under business user context, select "Interactive Usage" as the "Purpose" of the OAuth client)



OAuth2 SAML Bearer Assersion Workflow


Besides the authorization code solution, you can leverage the OAuth2 SAML Bearer Assersion workflow to authenticate and authorize if you have a trusted IdP added to SAC. One of the restrictions of applying the authorization code workflow is that it generally requires the end-user to input the credentials to logon SAC explicitly thus to get the authorization code and continue the authentication. Considering the scenario that the consumption of multi-actions public API is embedded in a fully automated process with no user interference possible, you may consider the OAuth2 SAML Bearer Assersion workflow as an alternative solution as well.


You can use the SAML Bearer Token issued by your IdP to fetch the access token. The article https://blogs.sap.com/2021/04/09/sap-analytics-cloud-app-integration-with-oauth2samlbearerassertion-... has introduced the OAuth2SAMLBearerAssertion flows that can be applied in SAC app integration and has provided some comprehensive examples on how to apply the flow with and without SAP BTP Destination service involved.



Fetch CSRF token


Before sending HTTP requests with POST method (used in multi-action triggering API), you need to fetch a valid CSRF token first.


You can get a token by sending a GET request to {tenant-url}/api/v1/csrf, including the header x-csrf-token: fetch . The csrf token is then returned in the x-csrf-token response header.


Once you get the token, you can use it to send POST request in the same session (Keep the JSESSIONID in the cookie as same with the CSRF request). The x-csrf-token:{token} header must be included in the request.



API definitions


Please refer to SAC help: https://help.sap.com/docs/SAP_ANALYTICS_CLOUD/14cac91febef464dbb1efce20e3f1613/e5ade1ed7c274d929a18b... for details of the API definitions and we won't repeat it in this article.



Samples


Try out the APIs using some common http clients


Note


In the following sample we’d use Postman to try out the APIs as it offers friendly user interface and easy configuration to facilitate the OAuth2 authorization code flow. You can also try out the APIs with other typical http clients (e.g. curl: https://curl.se/docs/manual.html, swagger-ui: https://swagger.io/tools/swagger-ui/ and etc.) , as long as the they have already embedded related authentication/authorization flow or you can aslo fetch the access token with customzed solution following either authorization code flow or SAML bearer assersion flow and send the token using the authorization header.


(To consume the API in swagger-ui, you can download the API specification from https://api.sap.com/api/MultiActions_API/overview as a reference)



OAuth2 Authorization Code Flow




  1. Create an OAuth Client in SAC, set the purpose as "Interactive Usage", and the callback url: https://www.getpostman.com/oauth2/callback which is required by postman.





  2. Go to the "Authorization" tab of your request collection in Postman, define the "configure new token" section as:





  3. After configuration is done, click on "Get new access token" in the bottom of "Authorization" tab in postman. After logging on SAC in the pop-up windown, the access token should be fetched.





  4. Then the access token can be used to access the multi-actions public APIs. Meanwhile csrf token is required to access the API with POST method. Use the following request to get the csrf token first.



    And you will get the csrf token in the headers of response:






  5. Use the csrf token in the following POST request to execute multi-actions. The csrf token is only valid in the same session, thus make sure the following request use the same cookie (this is usually taken care by Postman by default and you don't need to set the cookie explicitly in the following requests in general cases )





  6. Use the query status API to get the status of multi-actions exeuction.





OAuth2 SAML Bearer Assersion Flow


The only difference to try out the APIs using the OAuth2 SAML bearer assersion flow compared to the above authorization code flow lies in the way to get the access token, and for other part they should be the same. https://blogs.sap.com/2021/04/09/sap-analytics-cloud-app-integration-with-oauth2samlbearerassertion-... has provided samples to fetch the access token with and without BTP desitination service. E.g. You can refer to https://blogs.sap.com/2021/04/08/how-to-generate-saml-bearer-assertion-token-for-oauth2samlbearerass... to create a nodejs program to get an access token following the OAuth2 SAML Bearer Assertion flow if you do not have BTP destination at hand. If you are able to use BTP destination in your solution, it can be even easier and https://blogs.sap.com/2021/03/24/oauth2samlbearerassertion-flow-with-the-sap-btp-destination-service... illustrates how to leverage BTP destination to access SAC with OAuth2 SAML Bearer Assertion flow.


Then start from step 4 in previous authorization code flow sample to use the access token to access the APIs and the following steps should be the same.



Call APIs from ABAP/NetWeaver stack


Multi-actions public APIs can be consumed from ABAP/NetWeaver stack thus it can be feasible to integrate it with products like: BW, BPC and etc. as long as they provide customized ABAP exits. In following example, we will leverage BTP destination service (as an identiy provider, it can be replaced with other service serving as role of IdP) to realize OAuth2 SAML Beaerer Assertion Flow, thus the mutli-actions APIs can be called from ABAP program with no user interference and it can be embedded in automated jobs on ABAP/NetWeaver side.


Please also note that the process illustrated below are quite common and you may also replace the ABAP stack with other programing environment by leveraging corresponding http clients provided by the selected technology.

The procedure to realize the workflow is illustrated as following steps:




Create OAuth Client in SAC


Create an OAuth client in SAC, with "Interactive Usage" as purpose, and there's no need to define the redirect url.




Create desitination and destination service in BTP


The article https://blogs.sap.com/2021/03/24/oauth2samlbearerassertion-flow-with-the-sap-btp-destination-service... provides comprehensive explaination on how to realize the OAuth2 SAML Bearer authentication in SAC leveraging the BTP desitination service as an IdP (https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/consuming-destination-service). In the context of current scenario, here are some key steps to set up the destination and destination service in BTP:



create a destination in BTP sub account


Create a destination under BTP subaccount, with authentication type: OAuth2SAMLBeaererAssertion. Refer to below snapshot for fields mapping:



Download the IDP metadata, note down the entityID which will be used when adding trust IdP in SAC.



Download Trust and copy the public certificate value here, which will also be used in adding trust IdP in SAC:




create a destination service instance in BTP (if the service did not exist before)


Create a destination service instance in BTP if there's no available service instance created before.



Open the service key, note down the client id and client secrete which will be used to access the destination service instance using OAuth2 client credential method.





Add trusted IdP in SAC


Add trusted IdP in SAC, with below settings:




Implementation on ABAP layer


Create an ABAP program and declare common variables


REPORT z_run_multi_actions_in_sac.
PARAMETERS:
pv_ma_id TYPE string LOWER CASE DEFAULT 'Input multi-actions id here'.
DATA lo_client TYPE REF TO if_http_client.
DATA lo_rest_client TYPE REF TO if_rest_client.
DATA lo_rest_entity TYPE REF TO if_rest_entity.
DATA lo_request TYPE REF TO if_rest_entity.
DATA lv_body TYPE string.
DATA lv_http_status TYPE string.
DATA lv_response TYPE string.
DATA lv_acc_token_to_destination TYPE string.
DATA lv_acc_token_to_sac TYPE string.
DATA lv_csrf TYPE string.

Get access token to query destination service



Corresponding ABAP implementation:



*----------------------------------------get access to destination service---------------------------------

cl_http_client=>create_by_url( EXPORTING url = '<your token url for the btp destination service>' IMPORTING client = lo_client ).

CREATE OBJECT lo_rest_client TYPE cl_rest_http_client
EXPORTING
io_http_client = lo_client.

lo_request = lo_rest_client->create_request_entity( ).
lo_request->set_content_type( iv_media_type = 'application/x-www-form-urlencoded' ).
lv_body = 'grant_type=client_credentials&client_id=<your oauth client id for destination service>&client_secret=<your oauth client secret for destination service>'.
lo_request->set_string_data( lv_body ).
lo_rest_client->post( EXPORTING io_entity = lo_request ).
lv_http_status = lo_rest_client->get_status( ).
lo_rest_entity = lo_rest_client->get_response_entity( ).

lv_response = lo_rest_entity->get_string_data( ).

DATA lr_data TYPE REF TO data.
/ui2/cl_json=>deserialize(
EXPORTING
json = lv_response
pretty_name = /ui2/cl_json=>pretty_mode-user
assoc_arrays = abap_true
CHANGING
data = lr_data ).

IF lr_data IS BOUND.
ASSIGN lr_data->* TO FIELD-SYMBOL(<lfs_data>).
ASSIGN COMPONENT 'access_token' OF STRUCTURE <lfs_data> TO FIELD-SYMBOL(<lfs_results>).
ASSIGN <lfs_results>->* TO FIELD-SYMBOL(<ld_token_value>).
WRITE: 'Get access to destination service successfully'.
ENDIF.

lv_acc_token_to_destination = <ld_token_value>.

Query the destination via destination service to fetch the access token to access SAC



Corresponding ABAP implementation:



*----------------------------------------get access to destination service---------------------------------

cl_http_client=>create_by_url( EXPORTING url = '<your token url for the btp destination service>' IMPORTING client = lo_client ).

CREATE OBJECT lo_rest_client TYPE cl_rest_http_client
EXPORTING
io_http_client = lo_client.

lo_request = lo_rest_client->create_request_entity( ).
lo_request->set_content_type( iv_media_type = 'application/x-www-form-urlencoded' ).
lv_body = 'grant_type=client_credentials&client_id=<your oauth client id for destination service>&client_secret=<your oauth client secret for destination service>'.
lo_request->set_string_data( lv_body ).
lo_rest_client->post( EXPORTING io_entity = lo_request ).
lv_http_status = lo_rest_client->get_status( ).
lo_rest_entity = lo_rest_client->get_response_entity( ).

lv_response = lo_rest_entity->get_string_data( ).

DATA lr_data TYPE REF TO data.
/ui2/cl_json=>deserialize(
EXPORTING
json = lv_response
pretty_name = /ui2/cl_json=>pretty_mode-user
assoc_arrays = abap_true
CHANGING
data = lr_data ).

IF lr_data IS BOUND.
ASSIGN lr_data->* TO FIELD-SYMBOL(<lfs_data>).
ASSIGN COMPONENT 'access_token' OF STRUCTURE <lfs_data> TO FIELD-SYMBOL(<lfs_results>).
ASSIGN <lfs_results>->* TO FIELD-SYMBOL(<ld_token_value>).
WRITE: 'Get access to destination service successfully'.
ENDIF.

lv_acc_token_to_destination = <ld_token_value>.


fetch the csrf token and session id of SAC


*----------------------------------------send request get csrf---------------------------------
cl_http_client=>create_by_url( EXPORTING url = '<your SAC url>/api/v1/csrf' IMPORTING client = lo_client ).
CREATE OBJECT lo_rest_client TYPE cl_rest_http_client
EXPORTING
io_http_client = lo_client.

lo_rest_client->set_request_header(
EXPORTING
iv_name = 'X-CSRF-TOKEN'
iv_value = 'FETCH' ).

lo_rest_client->set_request_header(
EXPORTING
iv_name = 'Authorization'
iv_value = lv_acc_token_to_sac ).

lo_rest_client->get( ).
lv_http_status = lo_rest_client->get_status( ).
lo_rest_entity = lo_rest_client->get_response_entity( ).
lv_csrf = lo_rest_entity->get_header_field( 'X-CSRF-TOKEN' ).
DATA lt_headers TYPE tihttpnvp.
DATA ls_header TYPE ihttpnvp.
lt_headers = lo_rest_entity->get_header_fields( ).
DATA lt_cookies TYPE TABLE OF string.
DATA lv_cookie TYPE string.
DATA lv_cookie_remaining TYPE string.
LOOP AT lt_headers INTO ls_header.
IF ls_header-name = 'set-cookie'.
IF ls_header-value CS 'JSESSIONID='.
SPLIT ls_header-value AT ';' INTO lv_cookie lv_cookie_remaining.
lv_cookie = lv_cookie+11.
EXIT.
ENDIF.
ENDIF.
ENDLOOP.
*WRITE: lv_csrf.
DATA lv_decoded_cookie TYPE string.
lv_decoded_cookie = cl_http_utility=>unescape_url(
escaped = lv_cookie ).
WRITE: / 'Get csrf token from SAC public api service'.
*WRITE: lv_csrf.
*WRITE: lv_decoded_cookie.

Send request to SAC to start Multi-actions


*----------------------------------------trigger multiactions---------------------------------
DATA lv_url TYPE string.
lv_url = '<your SAC url>/api/v1/multiActions/' && pv_ma_id && '/executions'.
cl_http_client=>create_by_url( EXPORTING url = lv_url IMPORTING client = lo_client ).

CALL METHOD lo_client->request->set_method( if_http_request=>co_request_method_post ).
lo_client->request->set_header_field( name = 'x-csrf-token' value = lv_csrf ).
lo_client->request->set_header_field( name = 'Authorization' value = lv_acc_token_to_sac ).
lo_client->request->set_header_field( name = 'Content-Type' value = 'application/json' ).
lo_client->request->set_cookie( name = 'JSESSIONID'
value = lv_decoded_cookie ).
lv_body = '{"parameterValues": [ ]}'.
lo_client->request->set_cdata( data = lv_body ).
CALL METHOD lo_client->send
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3.

ASSERT sy-subrc = 0.

CALL METHOD lo_client->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3.
lv_response = lo_client->response->get_cdata( ).
WRITE: lv_response.
WRITE: / 'Trigger multi-actions ' && pv_ma_id && ' successfully'.

 

Integrate with SAP Build Process Automation in BTP


SAP Build Process Automation (will use "BTP PA" to indicate the platform in the following descriptions) is a low-code platform available on BTP which can be used to build workflow across SAP/non-SAP applications. (https://www.sap.com/products/technology-platform/process-automation/features.html) We can also embed multi-actions API in the process of BTP PA to achieve corresponding business needs. Here are some key steps of configuration:



Subscribe a plan of SAP Build Process Automation under BTP sub-account




security configuration


Create an OAuth Client in SAC like what's mentioned in above ABAP/Netweaver section.


Create a destination in BTP with OAuth2SAMLBearerAssertion authentication type, like what's what's mentioned in above ABAP/Netweaver section as well, meanwhile there are some differences to be noticed:






  • In URL, add the suffix "api/v1" to sac tenant url, such as: https://{tenant url}/api/v1




  • In additional properties, add





    • sap.applicationdevelopment.actions.enabled = true






    • sap.processautomation.enabled = true




    • SystemUser is not necessary as you can config use the user who start the BTP PA process as the user to trigger multi-actions






Add the BTP destination as trusted IdP in SAC, similar procedure has also been introduced in the above "ABAP/Netweaver" section.



Configuration in BTP PA


Open BTP PA, go to the "settings" tab and add your destination configured in above steps.




Create a multi-actions API action


Go to the "lobby" tab, click "create" button and select to "build an automated process", and then select "actions".


Click "upload API specification" and upload the multiActions API specification





  • You can download the API specification from https://api.sap.com/api/MultiActions_API/overview. As our destination URL is defined as https://{tenant url}/api/v1 rather than https://{tenant url}/api/v1/multiActions which is defined in API specification (since BTP PA requires the csrf token url configured under the same destination url prefix), let's manually update the path name in the API specification to add the prefix "/multiActions".






Enable csrf setting for the action both in the action setting and the post request:




Release the action and publish to library.



Create a business process


Create a business process from the lobby tab of BTP PA


Under the process project, create a new data type



Create the structure of the multi-actions pararmeter as follows and save:



Create a process, add the trigger-multi-actions request as a step of the process from the action library:



Configure process inputs as follows:



Click on the multi-actions step we just added, create a destination variable which will be used to bind the destination when we deploy the process:



Configure to run action on behalf of the user starts the process (the user should exist in SAC as well 😞



Configure the action input as follows:



Release and deploy the process.



Run the process from monitor


Go to the monitor tab of BTP PA, click on "Manage - Porcesses and Workflows", select the process we just deployed, click on "Start new instance"


Provide the input of the process in Json format, and click on "start new instance":



{
"pmaid": "t.7:FD000504F025851615C5037A42DD56BE",
"pparameter":
{
"parameterId": "TargetVersion",
"value": {
"memberIds": [
"public.Actual"
],
"hierarchyId": ""
}
}
}

In "monitor - Process and Workflows", you can view the status of process:



(end)
1 Comment