Comment utiliser les API de Google sheets en ABAP avec une authentification de serveur à serveur ?

L’objectif de ce blog est de vous montrer comment créer/modifier/supprimer des feuilles Google via des programmes d’arrière-plan de SAP.

Comme il s’agit de tâches d’arrière-plan exécutées par le système SAP, ce n’est pas à l’utilisateur de s’authentifier auprès de Google puisqu’il n’y a pas d’action humaine. Nous ne pouvons donc pas choisir les méthodes où l’utilisateur s’authentifie directement pour effectuer l’extraction vers Google, comme ceci par exemple :

Pour utiliser cette méthode, vous devez consulter la documentation ici :

https://www.sap.com/documents/2018/07/56e0dd6d-0f7d-0010-87a3-c30de2ffd8ff.html

Dans le cas d’une connexion de serveur à serveur, nous travaillerons de cette manière :

Développement

Le contenu suivant est inspiré de cet article : https://blogs.sap.com/2019/11/10/connect-from-as-abap-to-google-cloud-platform-app-engine-resource-secured-with-google-identity-aware-proxy/?fbclid=IwAR2H4FpeB_HMuSw6yF9NFTpBFxKmQfTnwJwrEpKbAVxEfQdxh1P_Ae_Tm1U

  • Créer un projet Google Cloud Platform :
  • Dans le projet, créez un compte de service

Naviguez vers IAM&Admin -> Comptes de service et créez un nouveau compte de service. Saisissez un nom et une description et cliquez sur créer. Sur l’écran suivant, vous devez sélectionner un rôle.

Tapez IAP dans la recherche et sélectionnez le rôle IAP-secured Web App User.

  • Et obtenir la clé au format P12

Après la création de votre compte de service, vous pouvez créer votre clé au format P12.

Le téléchargement du fichier P12 devrait commencer sur votre machine locale. Le compte de service permet d’accéder aux ressources du nuage, il faut donc le conserver en toute sécurité. Notez le secret indiqué pour une utilisation ultérieure.

  • Importer le certificat du compte de service dans STRUST

Avant de pouvoir écrire du code ABAP et utiliser l’API Google, nous devons nous assurer de deux choses : Premièrement, nous devons importer le fichier P12 dans le système AS ABAP, deuxièmement, nous devons nous assurer que Google est une source de confiance pour la communication.

  • Créer une nouvelle application SSF

Nous devons créer une nouvelle entrée dans la table SSFAPPLIC. Allez à la transaction SE16 et ouvrez la table. Créez une nouvelle entrée.

Utilisez JWR_SI pour APPLIC et sélectionnez tout sauf B_INCCERTS, B_DETACHED, B_ASKPWD. En tant que Description, nous définissons la Signature JWT. Cette entrée sera plus tard un nouveau noeud dans la transaction STRUST où nous pourrons importer des certificats. Sauvegardez la nouvelle entrée.

Ouvrez ensuite la transaction SSFA. Appuyez sur « New Entries ». Créez une nouvelle entrée comme indiqué ci-dessous

Nous avons maintenant un nouveau nœud dans la transaction STRUST.

  • Importer des certificats dans STRUST

Ouvrez la transaction STRUST et un nouveau noeud devrait être disponible avec le nom « SSF JWT Signature ».

Passez en mode « Edition », faites un clic droit sur le nouveau nœud et sélectionnez « Créer ».

Dans la fenêtre suivante, réglez l’algorithme sur « RSA », la force de la clé sur « 2048 » et l’algorithme de signature sur « SHA256 ».

Confirmez la sélection et le nouveau nœud sera maintenant disponible pour les importations. Dans le menu du haut, sélectionnez « PSE->Import » et sélectionnez le fichier P12 du compte de service que vous avez téléchargé. Il se peut que vous deviez entrer le secret qui a été affiché lors du téléchargement du fichier P12 depuis GCP.

Le fichier P12 est maintenant chargé dans le nœud « File » de STRUST. Ensuite, nous devons le déplacer du nœud « File » vers la bonne application SSF. Dans le menu supérieur, sélectionnez « PSE->Save as ». Dans la fenêtre suivante, sélectionnez « SSF Application » et sélectionnez l’application SSF que nous avons créée dans les étapes précédentes (JWR_SI).

Confirmez la sélection et appuyez sur « Enregistrer ». Nous avons ainsi importé le fichier Service Account P12 dans l’ABAP AS et pouvons l’utiliser pour signer notre JWT pour les demandes adressées à GCP. Avec STRUST, nous disposons d’un endroit sûr pour stocker la clé privée du compte de service et les informations relatives au certificat.

La clé privée et le certificat du compte de service GCP ont été importés dans le système.

  • Créer la connexion dans SAP

Ensuite, nous devons faire de Google une source de confiance pour la communication. Cela peut être réalisé en important l’autorité de certification racine de Google dans STRUST.

Téléchargez le certificat Google nécessaire à partir du navigateur (voir avec votre équipe SAP BASIS). Dans la transaction STRUST sur le client SSL Client SSL (Anonyme).

Google est maintenant une source de confiance pour la communication et nous avons créé les connexions HTTP qui seront utilisées pour la communication dans notre code ABAP plus tard.

Note : Vous pouvez tester votre connexion en cliquant sur « Connection test » :

Vous devriez obtenir une erreur 404 (c’est normal).

Si vous avez un message d’erreur SSL, vous avez un problème avec vos certificats Google.

Essayez de voir avec votre équipe SAP BASIS les erreurs dans les journaux ICM (TCODE SMICM).

  • Créer les méthodes ABAP qui vont :

Créer et signer un jeton JWT dans SAP

L’envoyer à Google pour l’échanger contre un jeton d’authentification à placer dans l’en-tête de chaque appel API vers les ressources Google (drive, sheets, docs, etc…).

  • Créer la classe ZCL_GCP_API_HANDLER
CLASS zcl_gcp_api_handler DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

      TYPES:

     BEGIN OF zgcp_response,
        content TYPE string,
        cookies TYPE tihttpcki,
        code type i,
        reason type string,
      END OF zgcp_response.

    CLASS-METHODS create_rs256_signed_jwt
      IMPORTING
                iv_jwt_header               TYPE zgcp_jwt_header
                iv_jwt_payload              TYPE zgcp_jwt_payload
                iv_ssf_profilename          TYPE string
                iv_ssf_id                   TYPE string
                iv_ssf_result               TYPE i
      RETURNING VALUE(rv_signed_jwt_base64) TYPE string.
*      RAISING   zcx_gcp_api_handler.

    CLASS-METHODS exchange_jwt_with_oidc_token
      IMPORTING
                iv_exchange_destination TYPE c
                iv_jwt_token            TYPE string
      RETURNING VALUE(rv_oidc_base64)   TYPE string.
*      RAISING   zcx_gcp_api_handler.

    CLASS-METHODS do_api_request
      IMPORTING
                iv_destination     TYPE c
                iv_oidc_token      TYPE string
                iv_method          TYPE string
                iv_xcontent        TYPE xstring OPTIONAL
                iv_content         TYPE string  OPTIONAL
                iv_sub_uri         TYPE string  OPTIONAL
                it_header_fields   TYPE tihttpnvp OPTIONAL
                it_cookies         TYPE tihttpcki OPTIONAL
                iv_content_type    TYPE string DEFAULT 'application/json'
      RETURNING VALUE(rs_response) TYPE zgcp_response.
*      RAISING   zcx_gcp_api_handler.

    CLASS-METHODS get_iat_unixtime RETURNING VALUE(rv_iat) TYPE int4.

  PROTECTED SECTION.

  PRIVATE SECTION.

    TYPES:
      ltty_tssfbin TYPE STANDARD TABLE OF ssfbin WITH KEY table_line WITHOUT FURTHER SECONDARY KEYS,

      BEGIN OF oidc_token_json,
        access_token TYPE string,
      END OF oidc_token_json.

    CLASS-METHODS string_to_binary_tab
      IMPORTING
                iv_string         TYPE string
      RETURNING VALUE(rt_bin_tab) TYPE ltty_tssfbin.
*      RAISING   zcx_gcp_api_handler.

    CLASS-METHODS binary_tab_to_string
      IMPORTING
                it_bin_tab       TYPE ltty_tssfbin
                iv_length        TYPE ssflen
      RETURNING VALUE(rv_string) TYPE string.
*      RAISING   zcx_gcp_api_handler.

    CLASS-METHODS base64_url_encode
      CHANGING
        iv_base64 TYPE string.
ENDCLASS.



CLASS ZCL_GCP_API_HANDLER IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_GCP_API_HANDLER=>BASE64_URL_ENCODE
* +-------------------------------------------------------------------------------------------------+
* | [<-->] IV_BASE64                      TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD base64_url_encode.
    REPLACE ALL OCCURRENCES OF '=' IN iv_base64 WITH ''.
    REPLACE ALL OCCURRENCES OF '+' IN iv_base64 WITH '-'.
    REPLACE ALL OCCURRENCES OF '/' IN iv_base64 WITH '_'.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_GCP_API_HANDLER=>BINARY_TAB_TO_STRING
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_BIN_TAB                     TYPE        LTTY_TSSFBIN
* | [--->] IV_LENGTH                      TYPE        SSFLEN
* | [<-()] RV_STRING                      TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD binary_tab_to_string.
    CALL FUNCTION 'SCMS_BINARY_TO_STRING'
      EXPORTING
        input_length = iv_length
        encoding     = '4110'
      IMPORTING
        text_buffer  = rv_string
      TABLES
        binary_tab   = it_bin_tab
      EXCEPTIONS
        failed       = 1
        OTHERS       = 2.
*    IF sy-subrc <> 0.
*      RAISE EXCEPTION TYPE zcx_gcp_api_handler
*        EXPORTING
*          textid = zcx_gcp_api_handler=>zcx_bintostr_conversion_failed.
*    ENDIF.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_GCP_API_HANDLER=>CREATE_RS256_SIGNED_JWT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_JWT_HEADER                  TYPE        ZGCP_JWT_HEADER
* | [--->] IV_JWT_PAYLOAD                 TYPE        ZGCP_JWT_PAYLOAD
* | [--->] IV_SSF_PROFILENAME             TYPE        STRING
* | [--->] IV_SSF_ID                      TYPE        STRING
* | [--->] IV_SSF_RESULT                  TYPE        I
* | [<-()] RV_SIGNED_JWT_BASE64           TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD create_rs256_signed_jwt.
    DATA lt_input_bin TYPE STANDARD TABLE OF ssfbin.
    DATA lt_output_bin TYPE STANDARD TABLE OF ssfbin.
    DATA lv_input_length TYPE ssflen.
    DATA lv_output_length TYPE ssflen.
    DATA lv_output_crc TYPE ssfreturn.
    DATA lt_signer TYPE STANDARD TABLE OF ssfinfo.
    DATA lv_unix_iat TYPE string.

    DATA(lv_jwt_payload) = /ui2/cl_json=>serialize(
         data  = iv_jwt_payload
         pretty_name = /ui2/cl_json=>pretty_mode-low_case
    ).
    DATA(lv_jwt_header) = /ui2/cl_json=>serialize(
           data  = iv_jwt_header
           pretty_name = /ui2/cl_json=>pretty_mode-low_case
    ).

    DATA(lv_jwt_header_base64) = cl_http_utility=>encode_base64( unencoded = lv_jwt_header ).
    DATA(lv_jwt_payload_base64) = cl_http_utility=>encode_base64( unencoded = lv_jwt_payload ).

    DATA(lv_data_base64) = |{ lv_jwt_header_base64 }.{ lv_jwt_payload_base64 }|.
    base64_url_encode(
      CHANGING
        iv_base64 = lv_data_base64
    ).

    TRY.
        lt_input_bin = string_to_binary_tab( iv_string = lv_data_base64 ).
*      CATCH zcx_gcp_api_handler INTO DATA(lo_cx).
*        RAISE EXCEPTION TYPE zcx_gcp_api_handler
*          EXPORTING
*            textid = lo_cx->textid.
    ENDTRY.

    lt_signer = VALUE #( ( id = iv_ssf_id profile = iv_ssf_profilename result = iv_ssf_result ) ).

    lv_input_length = strlen( lv_data_base64 ).

    CALL FUNCTION 'SSF_KRN_SIGN'
      EXPORTING
        str_format                   = 'PKCS1-V1.5'
        b_inc_certs                  = abap_false
        b_detached                   = abap_false
        b_inenc                      = abap_false
        ostr_input_data_l            = lv_input_length
        str_hashalg                  = 'SHA256'
      IMPORTING
        ostr_signed_data_l           = lv_output_length
        crc                          = lv_output_crc    " SSF Return code
      TABLES
        ostr_input_data              = lt_input_bin
        signer                       = lt_signer
        ostr_signed_data             = lt_output_bin
      EXCEPTIONS
        ssf_krn_error                = 1
        ssf_krn_noop                 = 2
        ssf_krn_nomemory             = 3
        ssf_krn_opinv                = 4
        ssf_krn_nossflib             = 5
        ssf_krn_signer_list_error    = 6
        ssf_krn_input_data_error     = 7
        ssf_krn_invalid_par          = 8
        ssf_krn_invalid_parlen       = 9
        ssf_fb_input_parameter_error = 10.
*    IF sy-subrc <> 0.
*      RAISE EXCEPTION TYPE zcx_gcp_api_handler
*        EXPORTING
*          textid = zcx_gcp_api_handler=>zcx_signature_failed.
*    ENDIF.

    TRY.
        DATA(lv_signature) = binary_tab_to_string(
                        it_bin_tab = lt_output_bin
                        iv_length  = lv_output_length
                    ).
*      CATCH zcx_gcp_api_handler INTO DATA(lo_zcx).
*        RAISE EXCEPTION TYPE zcx_gcp_api_handler
*          EXPORTING
*            textid = lo_zcx->textid.
    ENDTRY.

    DATA(lv_jwt) = |{ lv_data_base64 }.{ cl_http_utility=>encode_base64( unencoded = lv_signature ) }|.
    base64_url_encode(
      CHANGING
        iv_base64 = lv_jwt
    ).

    rv_signed_jwt_base64 = lv_jwt.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_GCP_API_HANDLER=>DO_API_REQUEST
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_DESTINATION                 TYPE        C
* | [--->] IV_OIDC_TOKEN                  TYPE        STRING
* | [--->] IV_METHOD                      TYPE        STRING
* | [--->] IV_XCONTENT                    TYPE        XSTRING(optional)
* | [--->] IV_CONTENT                     TYPE        STRING(optional)
* | [--->] IV_SUB_URI                     TYPE        STRING(optional)
* | [--->] IT_HEADER_FIELDS               TYPE        TIHTTPNVP(optional)
* | [--->] IT_COOKIES                     TYPE        TIHTTPCKI(optional)
* | [--->] IV_CONTENT_TYPE                TYPE        STRING (default ='application/json')
* | [<-()] RS_RESPONSE                    TYPE        ZGCP_RESPONSE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD do_api_request.
    DATA lo_client_api  TYPE REF TO if_http_client.
    DATA lv_response TYPE string.
    DATA lv_oidc TYPE string.

    CALL METHOD cl_http_client=>create_by_destination
      EXPORTING
        destination              = iv_destination
      IMPORTING
        client                   = lo_client_api
      EXCEPTIONS
        argument_not_found       = 1
        destination_not_found    = 2
        destination_no_authority = 3
        plugin_not_active        = 4
        internal_error           = 5
        OTHERS                   = 6.
*    IF sy-subrc <> 0.
*      RAISE EXCEPTION TYPE zcx_gcp_api_handler
*        EXPORTING
*          textid = zcx_gcp_api_handler=>zcx_api_dest_not_found.
*    ENDIF.

    IF lo_client_api IS BOUND.
      lv_oidc = |Bearer { iv_oidc_token }|.

      lo_client_api->request->set_header_fields( fields = it_header_fields ).

      lo_client_api->request->set_content_type( content_type = iv_content_type ).
      lo_client_api->request->set_method( method = iv_method ).

*         set jwt token auth
      lo_client_api->request->set_header_field(
          name  = 'Authorization' ##NO_TEXT
          value = lv_oidc
      ).
      lo_client_api->request->set_header_field(
          name  = 'content-type'
          value = iv_content_type
      ).


      IF iv_sub_uri IS NOT INITIAL.
        cl_http_utility=>set_request_uri(
            request = lo_client_api->request
            uri     = iv_sub_uri
        ).
      ENDIF.

      IF iv_xcontent IS NOT INITIAL.
        lo_client_api->request->set_data( data = iv_xcontent ).
      ENDIF.

      IF iv_content IS NOT INITIAL.
        lo_client_api->request->set_cdata( data = iv_content ).
      ENDIF.

      LOOP AT it_cookies ASSIGNING FIELD-SYMBOL(<cookie>).
        lo_client_api->request->set_cookie(
          EXPORTING
            name    = <cookie>-name                 " Name of cookie
            path    = <cookie>-path               " Path of Cookie
            value   = <cookie>-value                 " Cookie value
            domain  = <cookie>-xdomain               " Domain Name of Cookie
            expires = <cookie>-expires               " Cookie expiry date
            secure  = <cookie>-secure                " 0: unsaved; 1:saved
        ).
      ENDLOOP.

      lo_client_api->send( ).
      lo_client_api->receive(
        EXCEPTIONS
          http_communication_failure = 1
          http_invalid_state         = 2
          http_processing_failed     = 3
      ).
*      IF sy-subrc <> 0.
*        RAISE EXCEPTION TYPE zcx_gcp_api_handler
*          EXPORTING
*            textid = zcx_gcp_api_handler=>zcx_api_receive_failed.
*      ENDIF.

      rs_response-content = lo_client_api->response->get_data( ).
      lo_client_api->response->get_status( IMPORTING code   = rs_response-code
                                                     reason = rs_response-reason ).
      lo_client_api->response->get_cookies( CHANGING cookies = rs_response-cookies ).
    ENDIF.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_GCP_API_HANDLER=>EXCHANGE_JWT_WITH_OIDC_TOKEN
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_EXCHANGE_DESTINATION        TYPE        C
* | [--->] IV_JWT_TOKEN                   TYPE        STRING
* | [<-()] RV_OIDC_BASE64                 TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD exchange_jwt_with_oidc_token.
    DATA lo_client  TYPE REF TO if_http_client.
    DATA ls_response TYPE oidc_token_json.

    CALL METHOD cl_http_client=>create_by_destination
      EXPORTING
        destination              = iv_exchange_destination
      IMPORTING
        client                   = lo_client
      EXCEPTIONS
        argument_not_found       = 1
        destination_not_found    = 2
        destination_no_authority = 3
        plugin_not_active        = 4
        internal_error           = 5
        OTHERS                   = 6.
*    IF sy-subrc <> 0.
*      RAISE EXCEPTION TYPE zcx_gcp_api_handler
*        EXPORTING
*          textid = zcx_gcp_api_handler=>zcx_oauth_dest_not_found.
*    ENDIF.

    IF lo_client IS BOUND.
      lo_client->request->set_method( if_http_request=>co_request_method_post ).
      lo_client->request->set_formfield_encoding( formfield_encoding = if_http_entity=>co_formfield_encoding_encoded ).

      lo_client->request->set_form_field(
        EXPORTING
          name  = 'grant_type'
          value = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
      ).

      lo_client->request->set_form_field(
        EXPORTING
          name  = 'assertion'
          value = iv_jwt_token
      ).

      lo_client->send( ).
      lo_client->receive(
        EXCEPTIONS
          http_communication_failure = 1
          http_invalid_state         = 2
          http_processing_failed     = 3
      ).
*      IF sy-subrc <> 0.
*        RAISE EXCEPTION TYPE zcx_gcp_api_handler
*          EXPORTING
*            textid = zcx_gcp_api_handler=>zcx_oauth_token_receive_fail.
*      ENDIF.

      DATA(lv_response_json) = lo_client->response->get_cdata( ).

      /ui2/cl_json=>deserialize(
        EXPORTING
          json = lv_response_json
          pretty_name = /ui2/cl_json=>pretty_mode-camel_case
        CHANGING data = ls_response ).

*      IF ls_response-id_token IS INITIAL.
*        RAISE EXCEPTION TYPE zcx_gcp_api_handler
*          EXPORTING
*            textid = zcx_gcp_api_handler=>zcx_oauth_token_receive_fail.
*      ENDIF.

      rv_oidc_base64 = ls_response-access_token.
    ENDIF.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_GCP_API_HANDLER=>GET_IAT_UNIXTIME
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_IAT                         TYPE        INT4
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_iat_unixtime.
    DATA lv_unix_iat TYPE string.

    GET TIME STAMP FIELD DATA(lv_timestamp).

    CONVERT TIME STAMP lv_timestamp TIME ZONE 'UTC' INTO DATE DATA(lv_date) TIME DATA(lv_time).

    cl_pco_utility=>convert_abap_timestamp_to_java(
      EXPORTING
        iv_date      = lv_date
        iv_time      = lv_time
        iv_msec      = 0
      IMPORTING
        ev_timestamp = lv_unix_iat
    ).

    rv_iat = substring( val = lv_unix_iat off = 0 len = strlen( lv_unix_iat ) - 3 ).
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_GCP_API_HANDLER=>STRING_TO_BINARY_TAB
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_STRING                      TYPE        STRING
* | [<-()] RT_BIN_TAB                     TYPE        LTTY_TSSFBIN
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD string_to_binary_tab.
    DATA lv_xstring TYPE xstring.
    CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
      EXPORTING
        text     = iv_string
        encoding = '4110'
      IMPORTING
        buffer   = lv_xstring
      EXCEPTIONS
        failed   = 1
        OTHERS   = 2.
*    IF sy-subrc <> 0.
*      RAISE EXCEPTION TYPE zcx_gcp_api_handler
*        EXPORTING
*          textid = zcx_gcp_api_handler=>zcx_strtobin_conversion_failed.
*    ENDIF.

    CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
      EXPORTING
        buffer     = lv_xstring
      TABLES
        binary_tab = rt_bin_tab.
  ENDMETHOD.
ENDCLASS.
  • Créer 2 structures zgcp_jwt_header et zgcp_jwt_payload.

ALG signifie Algorithme et comprendra l’algorithme utilisé pour le cryptage, à savoir RS256.

TYP signifie « token type » (type de jeton) et sera JWT.

ISS signifie émetteur et sera le nom de notre compte de service Google.

AUD signifie audience, c’est-à-dire le consommateur du jeton.

TARGET_AUDIENCE est l’identifiant de notre client OAUTH chez Google.

IAT signifie issued at time (émis à l’heure) et correspond à l’heure UNIX à laquelle nous avons créé le jeton.

EXP signifie expires et correspond à la date d’expiration du jeton en heure UNIX.

https://blogs.sap.com/2019/11/10/connect-from-as-abap-to-google-cloud-platform-app-engine-resource-secured-with-google-identity-aware-proxy/?fbclid=IwAR2H4FpeB_HMuSw6yF9NFTpBFxKmQfTnwJwrEpKbAVxEfQdxh1P_Ae_Tm1U

  • Créez un programme qui appellera les méthodes ci-dessus pour s’identifier.
*&---------------------------------------------------------------------*
*& Report ZCL_GCP_JWT_AUTH_TEST
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ZCL_GCP_JWT_AUTH_TEST.

*1
DATA(lv_iat) = zcl_gcp_api_handler=>get_iat_unixtime( ).
    DATA(ls_jwt_payload) = VALUE zgcp_jwt_payload( iss = 'your email google service account'
*                                              aud = 'https://www.googleapis.com/oauth2/v4/token'
                                              scope = 'https://www.googleapis.com/auth/drive'
                                              aud = 'https://oauth2.googleapis.com/token'
*                                              target_audience = '110934787806204234349'
                                              iat = lv_iat
                                              exp = lv_iat + 30 ).

    DATA(ls_jwt_header) = VALUE zgcp_jwt_header( typ = 'JWT'
                                                 alg = 'RS256' ).

*2
    TRY.
        DATA(lv_signed_jwt) = zcl_gcp_api_handler=>create_rs256_signed_jwt(
          EXPORTING
            iv_jwt_header        = ls_jwt_header
            iv_jwt_payload       = ls_jwt_payload
            iv_ssf_profilename   = 'SAPJWR_SI400.pse'
            iv_ssf_id            = '<implicit>'
            iv_ssf_result        = 28
        ).
*      CATCH zcx_gcp_api_handler.
    ENDTRY.

*3
    TRY.
        DATA(lv_oidc) = zcl_gcp_api_handler=>exchange_jwt_with_oidc_token(
                        iv_exchange_destination = 'GCP_OAUTH2_TOKEN'
                        iv_jwt_token            = lv_signed_jwt
        ).
*      CATCH zcx_gcp_api_handler.
    ENDTRY.
  1. Nous spécifions toutes les variables nécessaires à la création du JWT et à sa signature
  2. Lancement du programme pour générer et signer le JWT.
  3. Lancer la classe pour générer le jeton d’authentification en envoyant le JWT signé à Google qui renvoie un jeton. Le jeton Google se trouve dans la variable lv_oidc.

With this token, it is now possible to call google APIs by specifying the token in the call header.

Now we can create a test program calling the google sheets APIs with our authentication token 

You can test your calls here : 

https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/update

By inspecting, it is possible to find the url to specify in the call to have this operation:

Pour voir des exemples d’appels dans SAP, j’ai créé un programme de test :

Exemple pour créer une feuille blanche :

Exemple d’ajout de valeurs dans la feuille de calcul :

Conclusion

Vous pouvez maintenant créer/modifier/supprimer des feuilles Google. En utilisant cette technique vous pouvez interagir avec toutes les API de google (drive, doc, sheet, etc…).