使用ABAP CL_HTTP_CLIENT类消费OData服务时,如何避免CSRF令牌验证失败错误

简介: 使用ABAP CL_HTTP_CLIENT类消费OData服务时,如何避免CSRF令牌验证失败错误

Recently I meet with this cookie issue so I document it as a blog in case any other guys might meet with the same problem.


I am trying to create some Opportunity transaction data by consuming OData service via CL_HTTP_CLIENT. Since this is a update operation which needs to be finished by HTTP POST, so a CSRF token is needed in this HTTP post. Let’s first have a look what is a typical scenario running in Chrome extension postman:


(1) Perform a HTTP get operation with header field x-csrf-token = fetch to get a valid CSRF token from http response header field.


image.png


(2) launch a HTTP post request using the CSRF token got from previous step,


image.png


And a new opportunity could successfully be created in postman:


image.png


However, when I implement the above mentioned scenario in ABAP, I meet with trouble. Instead of the expected successful creation message, I always get the error message “CSRF token validation failed”.


image.png


Issue trouble shooting

Let’s go back to postman scenario. Although it seems only the header field x-csrf-token is specified in http request, however there is another field cookie which is added to http request under the hood.


image.png


We could get this cookie field from previous HTTP get request which is responsible for CSRF token retrieve:


image.png


It means in ABAP implementation, we need to first retrieve BOTH CSRF token and cookie field from the first HTTP GET request, and then added these two fields to the request of second HTTP POST request which actually performs the opportunity creation.


This solution is also explained in this thread

usage of CSRF token in ABAP report for POST request.


I just added the complete source code of my implementation here and feel free to reuse it.

The ABAP report to create Opportunity by consuming OData service:

zcl_odata_tool=>get_csrf_token_and_cookie( IMPORTING et_cookies = DATA(lt_cookie)
                                                     ev_token = DATA(lv_token)  ).
zcl_odata_tool=>create_opp( iv_token = lv_token it_cookies = lt_cookie ).

Source code for ZCL_ODATA_TOOL:

CLASS zcl_odata_tool DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .
  PUBLIC SECTION.
    CLASS-METHODS get_csrf_token_and_cookie
      EXPORTING
        !et_cookies TYPE tihttpcki
        !ev_token TYPE string .
    CLASS-METHODS create_opp
      IMPORTING
        !iv_token TYPE string
        !it_cookies TYPE tihttpcki .
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_ODATA_TOOL IMPLEMENTATION.
  METHOD create_opp.
    DEFINE insert_line.
      lv_body = lv_body && &1.
      lv_body = lv_body && cl_abap_char_utilities=>newline.
    END-OF-DEFINITION.
    DATA:lo_http_client TYPE REF TO if_http_client,
             lv_status      TYPE i,
             lt_fields      TYPE tihttpnvp,
             lv_sysubrc     TYPE sysubrc.
    CALL METHOD cl_http_client=>create_by_url
      EXPORTING
        url                = 'https://<your C4C host>/sap/c4c/odata/v1/c4codata/$batch'
      IMPORTING
        client             = lo_http_client
      EXCEPTIONS
        argument_not_found = 1
        plugin_not_active  = 2
        internal_error     = 3
        OTHERS             = 4.
    ASSERT sy-subrc = 0.
    lo_http_client->propertytype_accept_cookie = if_http_client=>co_enabled.
    CALL METHOD lo_http_client->request->set_method( if_http_request=>co_request_method_post ).
    lo_http_client->request->set_header_field( name = 'Content-Type' value = 'multipart/mixed; boundary=batch_1' ).
    lo_http_client->request->set_header_field( name = 'x-csrf-token' value = iv_token ).
    lo_http_client->request->set_header_field( name = 'Authorization' value = 'your basic authentication code' ).
    LOOP AT it_cookies ASSIGNING FIELD-SYMBOL(<cookie>).
      lo_http_client->request->set_cookie( name = <cookie>-name
                                           value = <cookie>-value ).
    ENDLOOP.
    DATA: lv_body TYPE string.
    insert_line '--batch_1'.
    insert_line 'Content-Type: multipart/mixed; boundary=changeset_1'.
    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.
*
    insert_line '--changeset_1'.
    insert_line 'Content-Type: application/http'.
    insert_line 'Content-Transfer-Encoding: binary'.
    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.
    insert_line 'POST OpportunityCollection HTTP/1.1'.
    insert_line 'Content-Length: 5000'.
    insert_line 'Accept: application/json'.
    insert_line 'Content-Type: application/json'.
    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.
    insert_line '{'.
    insert_line '"AccountID": "8000018122",'.
    insert_line '"OwnerID": "8000018122",'.
    insert_line `"Name": {"content": "Testing ticket creation via OData Jerry1"}`.
    insert_line '}'.
    insert_line '--changeset_1--'.
    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.
    insert_line '--batch_1--'.
    lo_http_client->request->set_cdata( data = lv_body ).
    CALL METHOD lo_http_client->send
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3.
    ASSERT sy-subrc = 0.
    CALL METHOD lo_http_client->receive
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3.
    IF sy-subrc <> 0.
      CALL METHOD lo_http_client->get_last_error
        IMPORTING
          code    = lv_sysubrc
          message = DATA(ev_message).
      WRITE: / 'error occurred during receive data' COLOR COL_NEGATIVE.
      RETURN.
    ENDIF.
    DATA(lv_json) = lo_http_client->response->get_cdata( ).
    WRITE:/ lv_json.
  ENDMETHOD.
  METHOD get_csrf_token_and_cookie.
    DATA:  lo_http_client TYPE REF TO if_http_client,
           lv_status      TYPE i,
           lt_fields      TYPE tihttpnvp,
           lv_sysubrc     TYPE sysubrc.
    CALL METHOD cl_http_client=>create_by_url
      EXPORTING
        url                = 'https://<your C4C host>/sap/c4c/odata/v1/c4codata/'
      IMPORTING
        client             = lo_http_client
      EXCEPTIONS
        argument_not_found = 1
        plugin_not_active  = 2
        internal_error     = 3
        OTHERS             = 4.
    ASSERT sy-subrc = 0.
    lo_http_client->propertytype_accept_cookie = if_http_client=>co_enabled.
    CALL METHOD lo_http_client->request->set_method( if_http_request=>co_request_method_get ).
    lo_http_client->request->set_header_field( name = 'x-csrf-token' value = 'Fetch' ).
    lo_http_client->request->set_header_field( name = 'Accept' value = 'application/json' ).
    lo_http_client->request->set_header_field( name = 'Content-Type' value = 'application/json' ).
    lo_http_client->request->set_header_field( name = 'Authorization' value = 'Your basic authentication' ).
    CALL METHOD lo_http_client->send
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3.
    ASSERT sy-subrc = 0.
    CALL METHOD lo_http_client->receive
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3.
    IF sy-subrc <> 0.
      CALL METHOD lo_http_client->get_last_error
        IMPORTING
          code    = lv_sysubrc
          message = DATA(ev_message).
      WRITE: / 'Error when getting token:', ev_message.
      RETURN.
    ENDIF.
    lo_http_client->response->get_header_fields( CHANGING fields = lt_fields ).
    READ TABLE lt_fields ASSIGNING FIELD-SYMBOL(<field>) WITH KEY name = 'x-csrf-token'.
    ev_token = <field>-value.
    lo_http_client->response->get_cookies( CHANGING cookies = et_cookies ).
    lo_http_client->close( ).
  ENDMETHOD.
ENDCLASS.

Further reading

You can find a list of all other blogs related to OData written by Jerry.


Consume standard C4C OData service via ABAP code

Leverage C4C Odata notification to monitor C4C Opportunity change in CRM system

OData Service backend implementation in C4C, CRM and S4 HANA

JMeter beginner – how to use JMeter to measure performance of OData service accessed parallelly

Regarding cookie manipulation in CL_HTTP_CLIENT to avoid CSRF token validation failure issue


相关文章
|
1月前
|
JSON 数据格式
第三方系统或者工具通过 HTTP 请求发送给 ABAP 系统的数据,应该如何解析试读版
第三方系统或者工具通过 HTTP 请求发送给 ABAP 系统的数据,应该如何解析试读版
27 0
|
6月前
|
开发者
SAP ABAP 中,if_http_extension 接口的flow_rc 字段含义
SAP ABAP 中,if_http_extension 接口的flow_rc 字段含义
87 0
|
6月前
|
Web App开发 JavaScript 前端开发
如何给 SAP ABAP SEGW 开发的 OData 服务添加 Access-Control-Allow-Origin 响应头试读版
如何给 SAP ABAP SEGW 开发的 OData 服务添加 Access-Control-Allow-Origin 响应头试读版
49 0
|
6月前
|
JSON 数据处理 数据格式
关于 SAP ABAP OData 服务响应里的 d,results 和 __metadata 这几个字段的作用
关于 SAP ABAP OData 服务响应里的 d,results 和 __metadata 这几个字段的作用
70 2
|
6月前
|
存储 Web App开发 数据库
如何自行查找出 SAP ABAP 标准的 OData 服务返回数据的后台数据库表和表字段名称试读版
如何自行查找出 SAP ABAP 标准的 OData 服务返回数据的后台数据库表和表字段名称试读版
95 0
|
6月前
|
缓存 安全
SAP ABAP Gateway 系统里 HTTP 请求响应头部字段 DataServiceVersion 的可能取值范围
SAP ABAP Gateway 系统里 HTTP 请求响应头部字段 DataServiceVersion 的可能取值范围
62 0
|
6月前
|
JavaScript 前端开发 API
如何使用 JavaScript 代码连接部署在 SAP ABAP 服务器上的 OData 服务试读版
如何使用 JavaScript 代码连接部署在 SAP ABAP 服务器上的 OData 服务试读版
35 0
|
6月前
|
测试技术 BI
如何使用 ABAP 代码消费需要传递 CSRF token 的 OData 服务试读版
如何使用 ABAP 代码消费需要传递 CSRF token 的 OData 服务试读版
44 0
|
6月前
|
Web App开发 测试技术 开发者
SAP ABAP OData 服务的 $count 操作实现试读版
SAP ABAP OData 服务的 $count 操作实现试读版
25 0
|
6月前
|
测试技术
SAP ABAP OData 服务的 $count 和 $inlinecount 两个操作的区别试读版
SAP ABAP OData 服务的 $count 和 $inlinecount 两个操作的区别试读版
51 0