Skip to Content

usage of CSRF token in ABAP report for POST request

Question 1:

I have problems while using REST POST operations in ABAP report in context of the CSRF token

Background: Testing the possibilities of consuming oData services with ABAP reports and handling JSON content

Problem: I always get :

Satus: 403

Response: CSRF token validation failed finisdh

Example ABAP report:

1) first GET to fetch the token

2) make the post with HEADER parameter fetched token X-CSRF-Token

PARAMETERS: partner TYPE but000-partner,

invoice TYPE vbrk-vbeln.

START-OF-SELECTION.

TRY.

DATA: lv_service_url TYPE string,

lo_http_client TYPE REF TO if_http_client,

lo_rest_client TYPE REF TO cl_rest_http_client,

lo_response TYPE REF TO if_rest_entity,

lv_http_status TYPE i,

lv_token TYPE string.

* (1)

** GET CSRF token

cl_http_client=>create_by_url(

EXPORTING url = lv_service_url " oData service URL

IMPORTING client = lo_http_client

EXCEPTIONS OTHERS = 1 ).

CHECK sy-subrc EQ 0.

lo_http_client->request->set_content_type( 'application/json' ).

CREATE OBJECT lo_rest_client EXPORTING io_http_client = lo_http_client.

* fetching token

lo_rest_client->if_rest_client~set_request_header( EXPORTING iv_name = 'X-CSRF-Token' iv_value = 'Fetch' ).

lo_rest_client->if_rest_client~get( EXCEPTIONS OTHERS = 1 ).

CHECK sy-subrc EQ 0.

lo_response = lo_rest_client->if_rest_client~get_response_entity( ).

lv_http_status = lo_response->get_header_field( '~status_code' ).

CHECK lv_http_status EQ '200'.

" get token for POST request

lv_token = lo_response->get_header_field( 'X-CSRF-Token' ).

FREE: lo_http_client, lo_rest_client.

* (2)

** POST with CSRF token

DATA LO_REQUEST TYPE REF TO if_rest_entity.

cl_http_client=>create_by_url(

EXPORTING url = lv_service_url " oData service URL

IMPORTING client = lo_http_client

EXCEPTIONS OTHERS = 1 ).

CHECK sy-subrc EQ 0.

lo_http_client->request->set_content_type( 'application/json' ).

CREATE OBJECT lo_rest_client EXPORTING io_http_client = lo_http_client.

* build Example request data to send

DATA lv_json_post_data TYPE string.

lv_json_post_data = | \{ | &&

| "user":"{ sy-uname }", | &&

| "partner":"{ partner }", | &&

| "invoice":"{ invoice }" | &&

| \} |.

lo_request = lo_rest_client->if_rest_client~create_request_entity( ).

CHECK lo_request IS BOUND.

lo_request->set_header_field( iv_name = 'X-CSRF-Token' iv_value = lv_token ).

lo_request->set_content_type( iv_media_type = if_rest_media_type=>gc_appl_json ).

lo_request->set_string_data( lv_json_post_data ).

* POST

lo_rest_client->if_rest_resource~post( lo_request ).

* Collect response

lo_response = lo_rest_client->if_rest_client~get_response_entity( ).

lv_http_status = lo_response->get_header_field( '~status_code' ).

DATA lv_response TYPE string.

lv_response = lo_response->get_string_data( ).

CASE lv_http_status.

WHEN '201'.

* JSON to ABAP

DATA lr_json_deserializer TYPE REF TO cl_trex_json_deserializer.

CREATE OBJECT lr_json_deserializer.

DATA ls_test_content TYPE ztestrest.

lr_json_deserializer->deserialize( EXPORTING json = lv_response IMPORTING abap = ls_test_content ).

WRITE: /'CreadedBacklinkID:', ls_test_content-hashid.

WHEN OTHERS.

WRITE :/ 'Satus:', lv_http_status.

WRITE :/ 'Response:', lv_response.

ENDCASE.

CATCH cx_root.

ENDTRY.

It works without problems when I deactivate the CSRF token in the SICF for this service with parameter ~CHECK_CSRF_TOKEN = 0

When I deactivating the CSRF token there is the need to use the header parameter X-Requested-With :

lo_request->set_header_field( iv_name = 'X-Requested-With' iv_value = 'X' ).


and it also works in a browser REST test client. Problems are only visible when using the ABAP oo rest client

Question 2 :

The other problem, when the service works the response from the Gateway is XML per default and I have no clue how to say that I also want the returning entity in the server response also in JSON.

Can anyone help me here ?

Thanks in advance,

Thomas

Add comment
10|10000 characters needed characters exceeded

  • Follow
  • Get RSS Feed

2 Answers

  • Best Answer
    avatar image
    Former Member
    Aug 19, 2015 at 05:30 AM

    Question 1: You can have a look at the framework code /IWFND/CL_OCI_REQ_PROCESSOR method /IWFND/IF_OCI_REQ_PROCESSOR~UPDATE_ENTRY, especially at the line where lo_http_wrapper->put( ).

    Question 2:Add $format=json at teh URL, this will return you the data in JSON format

    Add comment
    10|10000 characters needed characters exceeded

    • There are differences in the releases :

      1. Release < 7.03/7.31 or the security session management is inactive: An own CSRF cookie gets generated (sap-XSRF_<SystemID>_<SAPClient>) and this CSRF token remains valid for 24 hours (86400 seconds).

      2. Release >= 7.03/7.31, the validity is bound to the security session, which depends on the system parameter http/security_session_timeout value (see transaction RZ11 for details on this parameter). By default, the security session management is active in these releases."

      Cross-Site Request Forgery Protection - SAP Gateway Foundation (SAP_GWFND) - SAP Library

      So it depends on the session and I found also the table the session ID and the CSRF token is saved

      SECURITY_CONTEXT and in the ->POST() call itself he generates a new entry in this table - when I hard change the token to the token from the new created table line it works ^^

      1) after get post and before POST call

      2) when I debug in POST call before method call /IWCOR/IF_REST_CSRF_HANDLER~VALIDATE_CSRF_TOKEN

      system calls fuba TH_GET_SECURITY_CONTEXT_REF which returns the LINK for the newest generated token - here 2767E995468E11E5A473005056B03327

      here the short extract from GET to POST with same object and only after execute the POST the second CSRF token is created somehow

      lo_rest_client->get( exceptions others = 1 ).

      * Get Token after GET

      lv_token = lo_rest_client->get_response_header( /iwfnd/if_oci_common=>gc_xcsrf_token ).

      ** POST with CSRF token

      * Set the CSRF token to the header

      lo_rest_client->set_request_header(

      exporting iv_name = /iwfnd/if_oci_common=>gc_xcsrf_token

      iv_value = lv_token ).

      lo_request ?= lo_rest_client->create_request_entity( ).

      * set data

      lo_request->set_string_data( lv_json_post_data ).

      * POST / until here there is only one token in table SECURITY_CONTEXT

      lo_rest_client->post( lo_request ).

  • Jul 21, 2016 at 01:57 AM

    Hello Thomas,

    For question 1, we had the same issue, every get call will return a new token, that's the problem, after we setting abap http client to accpet cookie, it works fine.

    lo_http_client->PROPERTYTYPE_ACCEPT_COOKIE = if_http_client=>co_enabled

    .

    Add comment
    10|10000 characters needed characters exceeded