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 a comment
10|10000 characters needed characters exceeded

Assigned Tags

Related questions

2 Answers

  • Best Answer
    Posted on 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 a 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 ).

  • Posted on 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 a comment
    10|10000 characters needed characters exceeded

Before answering

You should only submit an answer when you are proposing a solution to the poster's problem. If you want the poster to clarify the question or provide more information, please leave a comment instead, requesting additional details. When answering, please include specifics, such as step-by-step instructions, context for the solution, and links to useful resources. Also, please make sure that you answer complies with our Rules of Engagement.
You must be Logged in to submit an answer.

Up to 10 attachments (including images) can be used with a maximum of 1.0 MB each and 10.5 MB total.