Implementation d

Catégorie
Security
Publié
Auteur
Johannes

Un Audit Trail documente toutes les modifications pertinentes apportees aux donnees metier - qui a modifie quoi et quand. Dans ABAP Cloud, il existe differentes approches, des Audit Logs personnalises a l’integration avec le SAP Audit Log Service.

Audit Trail vs. Documents de modification

Avant de plonger dans l’implementation, il est important de comprendre la difference entre Audit Trail et Documents de modification :

AspectDocuments de modificationAudit Trail
FocusModifications techniques des champsActions pertinentes pour le metier
GranulariteNiveau champ (avant/apres)Niveau action (ce qui a ete fait)
ContenuAutomatique tous les champsInformations pertinentes selectionnees
ObjectifTracabiliteConformite, forensique
SuppressionArchivableSouvent immuable
Conformite legaleOptionnelSouvent obligatoire

Quand utiliser Audit Trail plutot que Documents de modification ?

  • Exigences reglementaires (SOX, RGPD, GxP)
  • Exigences d’audit externe
  • Evenements lies a la securite (connexions, modifications d’autorisations)
  • Transactions critiques pour l’entreprise (paiements, contrats)

Exigences de l’Audit Trail

Un Audit Trail professionnel doit repondre aux exigences suivantes :

Exigences fonctionnelles

  1. Exhaustivite : Capturer tous les evenements pertinents
  2. Immuabilite : Pas de manipulation ulterieure
  3. Horodatage : Capture precise du moment
  4. Identification de l’utilisateur : Qui a execute l’action
  5. Informations contextuelles : Ce qui a ete modifie (objet, valeurs)

Exigences techniques

  1. Performance : Overhead minimal sur les transactions
  2. Efficacite de stockage : Structure de donnees compacte
  3. Interrogeabilite : Recherche et filtrage rapides
  4. Archivabilite : Stockage a long terme possible

Table de log d’audit personnalisee

Pour un controle maximal, nous implementons notre propre Audit Trail.

Structure de table

@EndUserText.label: 'Log Audit Trail"
@AbapCatalog.enhancement.category: #NOT_EXTENSIBLE
@AbapCatalog.tableCategory: #TRANSPARENT
@AbapCatalog.deliveryClass: #L
@AbapCatalog.dataMaintenance: #RESTRICTED
define table zaudit_log {
key client : abap.clnt not null;
key log_uuid : sysuuid_x16 not null;
created_at : timestampl;
created_by : syuname;
object_type : abap.char(30);
object_key : abap.char(100);
action_type : abap.char(20);
action_details : abap.string(0);
ip_address : abap.char(45);
user_agent : abap.char(255);
session_id : abap.char(40);
}

Types de donnees pour les actions

INTERFACE zif_audit_constants
PUBLIC.
CONSTANTS:
" Types d'action
BEGIN OF gc_action,
create TYPE string VALUE 'CREATE',
update TYPE string VALUE 'UPDATE',
delete TYPE string VALUE 'DELETE',
read TYPE string VALUE 'READ',
approve TYPE string VALUE 'APPROVE',
reject TYPE string VALUE 'REJECT',
export TYPE string VALUE 'EXPORT',
login TYPE string VALUE 'LOGIN',
logout TYPE string VALUE 'LOGOUT',
auth_fail TYPE string VALUE 'AUTH_FAIL',
END OF gc_action.
CONSTANTS:
" Types d'objet
BEGIN OF gc_object,
sales_order TYPE string VALUE 'SALES_ORDER',
purchase_order TYPE string VALUE 'PURCHASE_ORDER',
customer TYPE string VALUE 'CUSTOMER',
vendor TYPE string VALUE 'VENDOR',
user TYPE string VALUE 'USER',
role TYPE string VALUE 'ROLE',
END OF gc_object.
ENDINTERFACE.

Classe Audit Logger

CLASS zcl_audit_logger DEFINITION
PUBLIC
FINAL
CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS:
get_instance
RETURNING VALUE(ro_instance) TYPE REF TO zcl_audit_logger,
log_action
IMPORTING
iv_object_type TYPE string
iv_object_key TYPE string
iv_action_type TYPE string
iv_details TYPE string OPTIONAL.
PRIVATE SECTION.
CLASS-DATA:
go_instance TYPE REF TO zcl_audit_logger.
METHODS:
constructor,
get_session_context
EXPORTING
ev_ip_address TYPE string
ev_user_agent TYPE string
ev_session_id TYPE string.
ENDCLASS.
CLASS zcl_audit_logger IMPLEMENTATION.
METHOD get_instance.
IF go_instance IS NOT BOUND.
go_instance = NEW #( ).
ENDIF.
ro_instance = go_instance.
ENDMETHOD.
METHOD constructor.
" Initialisation
ENDMETHOD.
METHOD log_action.
DATA: ls_audit TYPE zaudit_log.
" Generer UUID
TRY.
ls_audit-log_uuid = cl_system_uuid=>create_uuid_x16_static( ).
CATCH cx_uuid_error.
" Fallback
GET TIME STAMP FIELD DATA(lv_ts).
ls_audit-log_uuid = |{ lv_ts }{ sy-uname }|.
ENDTRY.
" Horodatage
GET TIME STAMP FIELD ls_audit-created_at.
" Utilisateur
ls_audit-created_by = cl_abap_context_info=>get_user_technical_name( ).
" Donnees d'audit
ls_audit-object_type = iv_object_type.
ls_audit-object_key = iv_object_key.
ls_audit-action_type = iv_action_type.
ls_audit-action_details = iv_details.
" Contexte de session
get_instance( )->get_session_context(
IMPORTING
ev_ip_address = ls_audit-ip_address
ev_user_agent = ls_audit-user_agent
ev_session_id = ls_audit-session_id
).
" Ecrire en base de donnees
INSERT zaudit_log FROM @ls_audit.
" En cas d'erreur : journalisation alternative
IF sy-subrc <> 0.
" Fallback vers Application Log
" Voir application-logging.md
ENDIF.
ENDMETHOD.
METHOD get_session_context.
" Adresse IP depuis la requete HTTP
TRY.
DATA(lo_request) = cl_http_server=>if_http_server~get_request( ).
ev_ip_address = lo_request->get_header_field( 'x-forwarded-for' ).
IF ev_ip_address IS INITIAL.
ev_ip_address = lo_request->get_header_field( 'remote_addr' ).
ENDIF.
ev_user_agent = lo_request->get_header_field( 'user-agent' ).
CATCH cx_root.
ev_ip_address = 'N/A'.
ev_user_agent = 'N/A'.
ENDTRY.
" ID de session
ev_session_id = cl_abap_context_info=>get_session_id( ).
ENDMETHOD.
ENDCLASS.

Determination RAP pour la journalisation

Dans RAP, nous utilisons des determinations pour creer automatiquement des logs d’audit. Voir aussi Determinations et validations RAP.

Definition de comportement

managed implementation in class zbp_i_salesorder unique;
strict ( 2 );
define behavior for ZI_SalesOrder alias SalesOrder
persistent table zsalesorder
lock master
authorization master ( instance )
{
create;
update;
delete;
" Determination pour Audit Trail
determination auditCreate on save { create; }
determination auditUpdate on save { update; }
determination auditDelete on save { delete; }
" Tous les champs
field ( readonly ) OrderId;
field ( readonly ) CreatedAt, CreatedBy, LastChangedAt, LastChangedBy;
}

Implementation des determinations

CLASS lhc_salesorder DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS:
auditCreate FOR DETERMINE ON SAVE
IMPORTING keys FOR SalesOrder~auditCreate,
auditUpdate FOR DETERMINE ON SAVE
IMPORTING keys FOR SalesOrder~auditUpdate,
auditDelete FOR DETERMINE ON SAVE
IMPORTING keys FOR SalesOrder~auditDelete.
ENDCLASS.
CLASS lhc_salesorder IMPLEMENTATION.
METHOD auditCreate.
" Lire les donnees creees
READ ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
LOOP AT lt_orders INTO DATA(ls_order).
" Creer le log d'audit
zcl_audit_logger=>log_action(
iv_object_type = zif_audit_constants=>gc_object-sales_order
iv_object_key = |{ ls_order-OrderId }|
iv_action_type = zif_audit_constants=>gc_action-create
iv_details = |Client: { ls_order-CustomerId }, | &&
|Montant: { ls_order-NetAmount } { ls_order-Currency }|
).
ENDLOOP.
ENDMETHOD.
METHOD auditUpdate.
" Lire les donnees mises a jour
READ ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
" Optionnel : Valeurs precedentes pour comparaison
" Cela necessite une logique supplementaire ou des Documents de modification
LOOP AT lt_orders INTO DATA(ls_order).
zcl_audit_logger=>log_action(
iv_object_type = zif_audit_constants=>gc_object-sales_order
iv_object_key = |{ ls_order-OrderId }|
iv_action_type = zif_audit_constants=>gc_action-update
iv_details = |Statut: { ls_order-Status }|
).
ENDLOOP.
ENDMETHOD.
METHOD auditDelete.
" Pour Delete, nous n'avons plus que les cles
LOOP AT keys INTO DATA(ls_key).
zcl_audit_logger=>log_action(
iv_object_type = zif_audit_constants=>gc_object-sales_order
iv_object_key = |{ ls_key-OrderId }|
iv_action_type = zif_audit_constants=>gc_action-delete
iv_details = '"
).
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Audit pour les actions RAP

Pour les actions particulierement importantes comme les approbations :

" Dans la definition de comportement
action approve result [1] $self;
action reject result [1] $self;
" Dans l'implementation
METHOD approve.
MODIFY ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
UPDATE FIELDS ( Status ApprovedAt ApprovedBy )
WITH VALUE #( FOR key IN keys (
%tky = key-%tky
Status = 'APPROVED"
ApprovedAt = cl_abap_context_info=>get_system_time( )
ApprovedBy = cl_abap_context_info=>get_user_technical_name( )
) )
FAILED DATA(lt_failed)
REPORTED DATA(lt_reported).
" Log d'audit pour l'approbation
LOOP AT keys INTO DATA(ls_key).
zcl_audit_logger=>log_action(
iv_object_type = zif_audit_constants=>gc_object-sales_order
iv_object_key = |{ ls_key-OrderId }|
iv_action_type = zif_audit_constants=>gc_action-approve
iv_details = '"
).
ENDLOOP.
" Retour
READ ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
result = VALUE #( FOR order IN lt_orders (
%tky = order-%tky
%param = order
) ).
ENDMETHOD.

Analyse du log d’audit

Vue CDS pour l’analyse du log d’audit

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Analyse du Log Audit"
define view entity ZI_AuditLogAnalysis
as select from zaudit_log
{
key log_uuid as LogUuid,
created_at as CreatedAt,
created_by as CreatedBy,
object_type as ObjectType,
object_key as ObjectKey,
action_type as ActionType,
action_details as ActionDetails,
ip_address as IpAddress,
session_id as SessionId,
" Champs calcules
cast( created_at as abap.dats ) as CreatedDate,
substring( cast( created_at as abap.char( 26 ) ), 12, 8 ) as CreatedTime,
" Agregations
@Aggregation.default: #COUNT
1 as ActionCount
}

Application Fiori pour le log d’audit

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Log Audit"
@Metadata.allowExtensions: true
@Search.searchable: true
define view entity ZC_AuditLog
as projection on ZI_AuditLogAnalysis
{
@UI.facet: [
{ id: 'General', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Details', position: 10 },
{ id: 'Context', purpose: #STANDARD, type: #FIELDGROUP_REFERENCE, label: 'Contexte', position: 20, targetQualifier: 'Context' }
]
@UI: { lineItem: [{ position: 10 }], identification: [{ position: 10 }] }
key LogUuid,
@UI: { lineItem: [{ position: 20, importance: #HIGH }],
identification: [{ position: 20 }],
selectionField: [{ position: 10 }] }
@Search.defaultSearchElement: true
CreatedAt,
@UI: { lineItem: [{ position: 30 }],
identification: [{ position: 30 }],
selectionField: [{ position: 20 }] }
@Search.defaultSearchElement: true
CreatedBy,
@UI: { lineItem: [{ position: 40, importance: #HIGH }],
identification: [{ position: 40 }],
selectionField: [{ position: 30 }] }
@Search.defaultSearchElement: true
ObjectType,
@UI: { lineItem: [{ position: 50 }],
identification: [{ position: 50 }] }
ObjectKey,
@UI: { lineItem: [{ position: 60, importance: #HIGH }],
identification: [{ position: 60 }],
selectionField: [{ position: 40 }] }
@Consumption.valueHelpDefinition: [{ entity: { name: 'ZI_ActionTypeVH', element: 'ActionType' } }]
ActionType,
@UI: { identification: [{ position: 70 }] }
ActionDetails,
@UI: { fieldGroup: [{ qualifier: 'Context', position: 10 }] }
IpAddress,
@UI: { fieldGroup: [{ qualifier: 'Context', position: 20 }] }
SessionId,
CreatedDate,
CreatedTime,
ActionCount
}

Service de requete pour les analyses

CLASS zcl_audit_query_service DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_audit_summary,
object_type TYPE string,
action_type TYPE string,
action_count TYPE i,
END OF ty_audit_summary,
tt_audit_summary TYPE STANDARD TABLE OF ty_audit_summary WITH EMPTY KEY.
METHODS:
get_user_activity
IMPORTING
iv_user TYPE syuname
iv_from_date TYPE timestampl OPTIONAL
iv_to_date TYPE timestampl OPTIONAL
RETURNING
VALUE(rt_log) TYPE STANDARD TABLE OF zaudit_log,
get_object_history
IMPORTING
iv_object_type TYPE string
iv_object_key TYPE string
RETURNING
VALUE(rt_log) TYPE STANDARD TABLE OF zaudit_log,
get_suspicious_activity
RETURNING
VALUE(rt_log) TYPE STANDARD TABLE OF zaudit_log,
get_action_summary
IMPORTING
iv_from_date TYPE timestampl OPTIONAL
RETURNING
VALUE(rt_summary) TYPE tt_audit_summary.
ENDCLASS.
CLASS zcl_audit_query_service IMPLEMENTATION.
METHOD get_user_activity.
DATA(lv_from) = COND #( WHEN iv_from_date IS INITIAL
THEN CONV timestampl( '00000000000000' )
ELSE iv_from_date ).
DATA(lv_to) = COND #( WHEN iv_to_date IS INITIAL
THEN CONV timestampl( '99991231235959' )
ELSE iv_to_date ).
SELECT * FROM zaudit_log
WHERE created_by = @iv_user
AND created_at BETWEEN @lv_from AND @lv_to
ORDER BY created_at DESCENDING
INTO TABLE @rt_log.
ENDMETHOD.
METHOD get_object_history.
SELECT * FROM zaudit_log
WHERE object_type = @iv_object_type
AND object_key = @iv_object_key
ORDER BY created_at DESCENDING
INTO TABLE @rt_log.
ENDMETHOD.
METHOD get_suspicious_activity.
" Exemple : Beaucoup de connexions echouees
SELECT * FROM zaudit_log
WHERE action_type = @zif_audit_constants=>gc_action-auth_fail
AND created_at >= @( cl_abap_context_info=>get_system_date( ) - 1 )
ORDER BY created_at DESCENDING
INTO TABLE @rt_log.
" Autres criteres :
" - Heures inhabituelles
" - Beaucoup de suppressions
" - Acces a des objets sensibles
ENDMETHOD.
METHOD get_action_summary.
DATA(lv_from) = COND #( WHEN iv_from_date IS INITIAL
THEN CONV timestampl( '00000000000000' )
ELSE iv_from_date ).
SELECT object_type, action_type, COUNT(*) AS action_count
FROM zaudit_log
WHERE created_at >= @lv_from
GROUP BY object_type, action_type
ORDER BY action_count DESCENDING
INTO TABLE @rt_summary.
ENDMETHOD.
ENDCLASS.

Integration avec le SAP Audit Log Service

Le SAP Audit Log Service sur BTP offre une solution d’audit centralisee et inviolable.

Configuration du Service Binding

Dans le BTP Cockpit :

  1. Services > Service Marketplace ouvrir
  2. Rechercher Audit Log Service
  3. Create Instance avec le plan “standard”
  4. Creer un Service Key pour l’acces ABAP

Communication Arrangement

Communication Scenario: SAP_COM_0193 (Audit Log Integration)
1. Fiori Launchpad > Communication Arrangements
2. Choisir "New"
3. Scenario: SAP_COM_0193
4. Lier le Communication System avec la destination BTP
5. Activer le service entrant

Appel du Audit Log Service

CLASS zcl_audit_log_service DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS:
write_audit_log
IMPORTING
iv_object_type TYPE string
iv_object_id TYPE string
iv_action TYPE string
iv_attributes TYPE string_table OPTIONAL
RAISING
cx_static_check.
ENDCLASS.
CLASS zcl_audit_log_service IMPLEMENTATION.
METHOD write_audit_log.
" Creer le client HTTP
DATA(lo_destination) = cl_http_destination_provider=>create_by_cloud_destination(
i_name = 'AUDIT_LOG_SERVICE"
).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination( lo_destination ).
" Construire la requete
DATA(lo_request) = lo_client->get_http_request( ).
" Message d'audit en JSON
DATA(lv_timestamp) = |{ sy-datum }T{ sy-uzeit }Z|.
DATA(lv_user) = cl_abap_context_info=>get_user_technical_name( ).
DATA(lv_json) = |\{| &&
|"uuid":"{ cl_system_uuid=>create_uuid_c36_static( ) }",| &&
|"time":"{ lv_timestamp }",| &&
|"user":"{ lv_user }",| &&
|"object":\{| &&
|"type":"{ iv_object_type }",| &&
|"id":\{"key":"{ iv_object_id }"\}| &&
|\},| &&
|"action":"{ iv_action }"| &&
|\}|.
lo_request->set_text( lv_json ).
lo_request->set_header_field(
i_name = 'Content-Type"
i_value = 'application/json"
).
" Envoyer la requete
DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
IF lo_response->get_status( )-code <> 201.
RAISE EXCEPTION TYPE cx_abap_not_a_number
MESSAGE e001(zaudit) WITH lo_response->get_status( )-reason.
ENDIF.
lo_client->close( ).
ENDMETHOD.
ENDCLASS.

Approche hybride : Local + Cloud

Pour de meilleurs resultats, nous combinons les logs locaux et cloud :

METHOD log_action_hybrid.
" 1. Log d'audit local (rapide, toujours disponible)
zcl_audit_logger=>log_action(
iv_object_type = iv_object_type
iv_object_key = iv_object_key
iv_action_type = iv_action_type
iv_details = iv_details
).
" 2. Log d'audit cloud (asynchrone, inviolable)
TRY.
NEW zcl_audit_log_service( )->write_audit_log(
iv_object_type = iv_object_type
iv_object_id = iv_object_key
iv_action = iv_action_type
).
CATCH cx_static_check INTO DATA(lx_error).
" En cas d'erreur cloud : le log local suffit
" Optionnel : Application Log pour la surveillance
ENDTRY.
ENDMETHOD.

Durees de conservation et archivage

Exigences legales

ReglementationDuree de conservationDomaine d’application
HGB (DE)10 ansDocuments commerciaux
GoBD (DE)10 ansDonnees comptables
SOX (US)7 ansEntreprises cotees en bourse
RGPD/DSGVOMinimisationDonnees personnelles
GxP15+ ansPharma/Medical

Job d’archivage

CLASS zcl_audit_archiver DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS:
archive_old_entries
IMPORTING
iv_retention_days TYPE i DEFAULT 365.
ENDCLASS.
CLASS zcl_audit_archiver IMPLEMENTATION.
METHOD archive_old_entries.
" Calculer la date limite
DATA(lv_cutoff_date) = CONV timestampl(
|{ cl_abap_context_info=>get_system_date( ) - iv_retention_days }000000|
).
" 1. Exporter les anciennes entrees (par ex. en JSON)
SELECT * FROM zaudit_log
WHERE created_at < @lv_cutoff_date
INTO TABLE @DATA(lt_archive).
IF lt_archive IS NOT INITIAL.
" Creer l'export JSON
DATA(lo_json) = /ui2/cl_json=>serialize( lt_archive ).
" Sauvegarder dans le stockage d'archive
" (par ex. Object Store, Document Management Service)
" Voir: sap-document-management-service.md
" 2. Supprimer les entrees archivees
DELETE FROM zaudit_log WHERE created_at < @lv_cutoff_date.
" 3. Journaliser l'archivage
zcl_audit_logger=>log_action(
iv_object_type = 'AUDIT_LOG"
iv_object_key = |ARCHIVE_{ sy-datum }|
iv_action_type = 'ARCHIVE"
iv_details = |{ lines( lt_archive ) } entrees archivees|
).
ENDIF.
ENDMETHOD.
ENDCLASS.

Configurer le job en arriere-plan

" Job pour archivage regulier
CLASS zcl_audit_archive_job DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES: if_apj_dt_exec_object,
if_apj_rt_exec_object.
ENDCLASS.
CLASS zcl_audit_archive_job IMPLEMENTATION.
METHOD if_apj_dt_exec_object~get_parameters.
" Definir les parametres du job
et_parameter_def = VALUE #(
( selname = 'P_DAYS"
kind = if_apj_dt_exec_object=>parameter
datatype = 'INT4"
mandatory = abap_false
changeable_ind = abap_true )
).
et_parameter_val = VALUE #(
( selname = 'P_DAYS' sign = 'I' option = 'EQ' low = '365' )
).
ENDMETHOD.
METHOD if_apj_rt_exec_object~execute.
" Lire le parametre
DATA(lv_days) = CONV i( it_parameters[ selname = 'P_DAYS' ]-low ).
" Executer l'archivage
NEW zcl_audit_archiver( )->archive_old_entries( lv_days ).
ENDMETHOD.
ENDCLASS.

Bonnes pratiques

1. Optimisation des performances

" Mauvais : INSERT individuels
LOOP AT lt_changes INTO DATA(ls_change).
zcl_audit_logger=>log_action( ... ). " Chaque appel = 1 INSERT BD
ENDLOOP.
" Meilleur : INSERT en masse
CLASS zcl_audit_logger DEFINITION.
CLASS-METHODS:
log_actions_bulk
IMPORTING
it_audit_entries TYPE tt_audit_entries.
ENDCLASS.
METHOD log_actions_bulk.
INSERT zaudit_log FROM TABLE @it_audit_entries.
ENDMETHOD.

2. Journalisation asynchrone

Pour les transactions critiques en temps :

" BGPF pour journalisation d'audit asynchrone
CLASS zcl_audit_async DEFINITION.
INTERFACES: if_bgmc_op_single.
DATA: ms_audit TYPE zaudit_log.
ENDCLASS.
METHOD if_bgmc_op_single~execute.
INSERT zaudit_log FROM @ms_audit.
ENDMETHOD.
" Utilisation
DATA(lo_async) = NEW zcl_audit_async( ).
lo_async->ms_audit = ls_audit_entry.
cl_bgmc_process_factory=>get_default( )->create(
)->set_operation_single( lo_async
)->save_for_execution( ).

3. Journalisation selective

Ne pas tout journaliser - seulement les evenements pertinents :

METHOD should_log_action.
" Liste blanche configurable
SELECT SINGLE @abap_true
FROM zaudit_config
WHERE object_type = @iv_object_type
AND action_type = @iv_action_type
AND is_active = @abap_true
INTO @rv_should_log.
ENDMETHOD.

4. Masquer les donnees sensibles

METHOD mask_sensitive_data.
" Masquer le numero de carte de credit
rv_masked = replace(
val = iv_data
regex = '\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?(\d{4})"
with = '****-****-****-$1"
).
" Supprimer le mot de passe
rv_masked = replace(
val = rv_masked
regex = '"password"\s*:\s*"[^"]*""
with = '"password":"***""
).
ENDMETHOD.

Resume

Un Audit Trail professionnel dans ABAP Cloud necessite :

ComposantImplementation
StockageTable personnalisee + optionnel SAP Audit Log Service
CaptureDeterminations RAP pour journalisation automatique
ContexteUtilisateur, horodatage, IP, session
AnalyseVues CDS + application Fiori
ArchivageJob en arriere-plan avec politique de retention
PerformanceINSERT en masse, journalisation asynchrone

Sujets connexes