Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
0 Kudos
1,858

Summary


In this blog you will learn about a program that can be used to remove sensitive information from your test systems.  You can schedule this program as a background job after system refresh from production.  This program can  replace data at table field level with a masking text of your choice.

How does it work?


This program  replaces table field data with a text to mask the data in test systems after production refresh. The clients may need to remove the customer/vendor address information and contact details for security purposes.

This program has a selection screen where you can enter the table fields that needs to be replaced with a dummy text or masking text.  Code snippets provided.

Selection screen




 

Source code


*&---------------------------------------------------------------------*
*& Report ZMASK_TABLE_FIELD_DATA
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zmask_table_field_data.

DATA:lv_field(47) TYPE c.

SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME .
SELECT-OPTIONS:s_fields FOR lv_field OBLIGATORY NO INTERVALS.
SELECTION-SCREEN SKIP .
SELECTION-SCREEN COMMENT /1(79) text-001.
SELECTION-SCREEN COMMENT /1(79) text-002.
SKIP 1.
PARAMETERS p_mask(50) TYPE c OBLIGATORY.
SELECTION-SCREEN END OF BLOCK b1 .

CLA$$ cl_tab_field DEFINITION.

PUBLIC SECTION.

TYPES:BEGIN OF ty_tab_field,
table TYPE tabname16,
field TYPE name_feld,
END OF ty_tab_field,

tt_tab_field TYPE TABLE OF ty_tab_field.

* DATA: it_tab_field TYPE STANDARD TABLE OF ty_tab_field.

METHODS: scramble_table_data IMPORTING it_table_field TYPE tt_tab_field ,
process_each_table IMPORTING it_tab TYPE tt_tab_field.

ENDCLA$$.

CLA$$ cl_report DEFINITION.

PUBLIC SECTION.

TYPE-POOLS sscr.


DATA: lw_restrict TYPE sscr_restrict,
lw_opt_list TYPE sscr_opt_list,
lw_as TYPE sscras,
gv_clA$$ TYPE klA$$e_d.

DATA: it_tab_field TYPE STANDARD TABLE OF cl_tab_field=>ty_tab_field.

METHODS: initialize,
collect_table_field_names.

ENDCLA$$.



INITIALIZATION.
DATA go_report TYPE REF TO cl_report.
CREATE OBJECT go_report .

go_report->initialize( ).

START-OF-SELECTION.

CHECK NOT s_fields[] IS INITIAL.
DATA: go_tab_field TYPE REF TO cl_tab_field.
CREATE OBJECT go_tab_field.

go_report->collect_table_field_names( ).
IF NOT go_report->it_tab_field[] IS INITIAL.
go_tab_field->mask_table_data( EXPORTING it_table_field = go_report->it_tab_field[] ).
ELSE.
MESSAGE 'No valid table fields found for data masking' TYPE 'S' DISPLAY LIKE 'I'.
ENDIF.



**********************************************************************
********ClA$$ Implementations*****************************************
**********************************************************************

CLA$$ cl_report IMPLEMENTATION.
METHOD initialize.

CLEAR: lw_restrict,
lw_opt_list,
lw_as.

lw_opt_list-name = 'EQUAL'.
lw_opt_list-options-eq = 'X'. " Restrict to equal
APPEND lw_opt_list TO lw_restrict-opt_list_tab.

lw_as-kind = 'S'.
lw_as-name = 'S_FIELDS'. " select option which you want
"to restrict
lw_as-sg_main = 'I'.
lw_as-sg_addy = ''.
lw_as-op_main = 'EQUAL'.
APPEND lw_as TO lw_restrict-A$$_tab.
*** To apply restrictions to select option
CALL FUNCTION 'SELECT_OPTIONS_RESTRICT'
EXPORTING
restriction = lw_restrict
EXCEPTIONS
too_late = 1
repeated = 2
selopt_without_options = 3
selopt_without_signs = 4
invalid_sign = 5
empty_option_list = 6
invalid_kind = 7
repeated_kind_a = 8
OTHERS = 9.

ENDMETHOD.
METHOD collect_table_field_names.
DATA: lw_tab_field TYPE cl_tab_field=>ty_tab_field.
LOOP AT s_fields INTO s_fields.

SPLIT s_fields-low AT '-' INTO lw_tab_field-table lw_tab_field-field .
APPEND lw_tab_field TO it_tab_field.
CLEAR lw_tab_field.

ENDLOOP.

IF NOT it_tab_field[] IS INITIAL.
SORT it_tab_field.
DELETE ADJACENT DUPLICATES FROM it_tab_field COMPARING ALL FIELDS.
ENDIF.

ENDMETHOD.

ENDCLA$$.

CLA$$ cl_tab_field IMPLEMENTATION.

METHOD mask_table_data .
DATA: lw_table_field LIKE LINE OF it_table_field,
lt_indv_tab TYPE STANDARD TABLE OF ty_tab_field.
LOOP AT it_table_field INTO lw_table_field.
* Collect the fields of invidual tables and process table by table
APPEND lw_table_field TO lt_indv_tab.
AT END OF table.
process_each_table( EXPORTING it_tab = lt_indv_tab ).
REFRESH lt_indv_tab.
ENDAT.


ENDLOOP.

ENDMETHOD.

METHOD process_each_table.

DATA: lw_tab LIKE LINE OF it_tab,
lo_tdata TYPE REF TO data,
lo_tline TYPE REF TO data,
lv_field(100) TYPE c,
lv_text TYPE string,
lv_line TYPE i,
lv_line_c(10) TYPE c.

* Generate internal table dynamically
FIELD-SYMBOLS:<fs_tab_data> TYPE ANY TABLE,
<fs_tab_line> TYPE any,
<fs_field_name> TYPE name_feld,
<fs_field_data> TYPE any.

READ TABLE it_tab INTO lw_tab INDEX 1.
CHECK lw_tab-table IS NOT INITIAL.

* Create dynamic internal table
CREATE DATA lo_tdata TYPE TABLE OF (lw_tab-table).
CHECK sy-subrc EQ 0.
A$$IGN lo_tdata->* TO <fs_tab_data>.
CHECK <fs_tab_data> IS A$$IGNED.
SELECT * FROM (lw_tab-table)
INTO TABLE <fs_tab_data>.
* CREATE DATA lo_tline TYPE (lw_tab-table).
* CHECK sy-subrc EQ 0.
* A$$IGN lo_tline->* TO <fs_tab_line>.
* CHECK <fs_tab_line> IS A$$IGNED.

LOOP AT <fs_tab_data> A$$IGNING <fs_tab_line> .
LOOP AT it_tab INTO lw_tab.
CONCATENATE '<fs_tab_line>-' lw_tab-field INTO lv_field.
A$$IGN (lv_field) TO <fs_field_data>.
IF <fs_field_data> IS NOT INITIAL.
<fs_field_data> = p_mask.
ENDIF.
ENDLOOP.
ENDLOOP.

* Update the table with modified fields
IF NOT <fs_tab_data> IS INITIAL.
UPDATE (lw_tab-table) FROM TABLE <fs_tab_data>.
IF sy-subrc EQ 0.
ULINE.
CONCATENATE 'The following fields are updated in table' lw_tab-table 'with masking text' p_mask INTO lv_text SEPARATED BY space.
WRITE:/ lv_text.
LOOP AT it_tab INTO lw_tab.
WRITE:/ lw_tab-field.
ENDLOOP.
CLEAR: lv_text,lv_line.
DESCRIBE TABLE <fs_tab_data> LINES lv_line.
lv_line_c = lv_line.
CONCATENATE 'Number of records updated:' lv_line_c INTO lv_text SEPARATED BY space.
WRITE:/ lv_text.

ENDIF.
ENDIF.
ENDMETHOD.

ENDCLA$$.





 

 

Conclusion


This simple program can be a handy tool in system refresh activities. Execution of this program can be added as a post refresh activity to ensure that no sensitive information is copied to Quality systems from production.  This program is designed to work on any number of table fields and there are no restrictions based on tables.
3 Comments
pjl
Participant
Hi Sanu,

a question for you. Did you spent any time in research of existing solutions? Since this problem is a very common one, it is hard to believe that there aren’t any solutions out there. Personally I don’t know, but maybe you came across one or two?

Actually I don’t like this simplistic approach much, since you might easily destroy data consistency in your test system, which in turn renders all tests as useless.

Cheers,

Peter

 
Sandra_Rossi
Active Contributor
0 Kudos

That’s called data anonymization and there are softwares to do that.

0 Kudos
Our client did not want to procure any new license and they are aware of the impact of such a solution. I did my research and this custom solution was the method client chose.  Thank you for your comments.
Labels in this area