Перейти до вмісту

Перевірка авторизації

Перевірка авторизації (authorization check) захищає дані від несанкціонованого доступу. У SAP-системі кожен користувач має набір ролей, що дозволяють певні операції над певними обʼєктами. Ключове для ABAP: ABAP SQL не тригерить жодних перевірок у БДSELECT повертає все, на що дозволяє sql-синтаксис. Тому за авторизацію відповідає сам розробник.

Два основні механізми: явний AUTHORITY-CHECK у коді та неявний через CDS access control на CDS view entity.

  • Authorization object — іменований контейнер дозволів, містить до 10 authorization fields.
  • Authorization field — конкретний атрибут дозволу: країна, компанія, тип активності.
  • ACTVT — стандартне поле активності: 01 (create), 02 (update), 03 (display/read), 06 (delete), і т.д.

У BTP ABAP Environment auth-обʼєкти додаються у IAM appbusiness catalogbusiness role → користувач. У classic ABAP — через транзакції SU20/SU21/PFCG.

Синтаксис:

AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID id1 FIELD val1
ID id2 FIELD val2
ID id3 DUMMY.
  • FIELD value — перевірити конкретне значення поля.
  • DUMMY — поле присутнє в обʼєкті, але у цій перевірці ігнорується.

Результат — у sy-subrc:

sy-subrcЗначення
0успіх (або всі поля DUMMY — нічого не перевірено)
4значення поля не знайдено серед дозволених
8забагато полів вказано
12auth-обʼєкт не існує у ролях користувача
24-40технічні помилки виклику
" Користувач має дозвіл на ACTVT '03' для країни 'US'
AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID 'ZAUTH_CTRY' FIELD 'US'
ID 'ACTVT' FIELD '03'.
" sy-subrc = 0 → дозволено
AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID 'ZAUTH_CTRY' FIELD 'DE'
ID 'ACTVT' FIELD '03'.
" sy-subrc = 4 → для 'DE' дозволу немає

DUMMY для пропуску поля:

" Перевірити лише ACTVT, країну ігнорувати
AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID 'ZAUTH_CTRY' DUMMY
ID 'ACTVT' FIELD '03'.
" Всі поля DUMMY — фактично перевірки немає, sy-subrc = 0
AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID 'NON_EXISTENT' DUMMY
ID 'ACTVT' DUMMY.
" Неіснуючий auth-обʼєкт — sy-subrc = 12
AUTHORITY-CHECK OBJECT 'NON_EXISTENT'
ID 'ANY' DUMMY
ID 'ACTVT' DUMMY.
AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID 'ZAUTH_CTRY' FIELD country
ID 'ACTVT' FIELD '03'.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_authorization.
ENDIF.

Альтернатива явним перевіркам — неявна фільтрація у CDS view entity. Access control задається у двох місцях:

@AccessControl.authorizationCheck: #CHECK
define view entity ZDEMO_ABAP_FLSCH_VE_AUTH
as select from zdemo_abap_flsch
{
key carrid,
key connid,
countryfr,
...
}

Опції:

ЗначенняПоведінка
#NOT_REQUIREDбез перевірок, відкритий доступ
#CHECKпопередження активатора, якщо access control відсутній
#MANDATORYaccess control обовʼязковий — без нього активація падає
#NOT_ALLOWEDaccess control заборонений

Окремий обʼєкт — role з правилом доступу:

@EndUserText.label: 'Test'
@MappingRole: true
define role ZCDS_ACC_CTRL {
grant
select
on
ZDEMO_ABAP_FLSCH_VE_AUTH
where
(countryfr) = aspect pfcg_auth(zauth_obj, zauth_ctry, ACTVT = '03');
}

Сенс: SELECT з ZDEMO_ABAP_FLSCH_VE_AUTH автоматично звужується до тих рядків, де countryfr збігається зі значеннями, які користувач має в auth-обʼєкті zauth_obj (поле zauth_ctry, ACTVT = '03').

" Без WHERE — все одно фільтрується за правами користувача
SELECT * FROM zdemo_abap_flsch_ve_auth INTO TABLE @DATA(itab).
" Повернуться тільки записи з countryfr = 'US' (якщо лише 'US' у ролі)
SELECT * FROM zdemo_abap_flsch_ve_auth
WHERE countryfr = 'DE' INTO TABLE @DATA(itab2).
" itab2 порожня — DE нема у ролях

RAP має два типи authorization master:

  • global — права на операції незалежно від конкретного запису.
  • instance — права перевіряються для кожного окремого запису.

У BDEF:

...
authorization master ( global )
...

У behavior pool:

METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR some_bdef RESULT result.
METHOD get_global_authorizations.
IF requested_authorizations-%create = if_abap_behv=>mk-on.
AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID 'ZAUTH_FIELD' DUMMY
ID 'ACTVT' FIELD '01'.
result-%create = COND #(
WHEN sy-subrc = 0 THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
ENDIF.
IF requested_authorizations-%update = if_abap_behv=>mk-on.
AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID 'ZAUTH_FIELD' DUMMY
ID 'ACTVT' FIELD '02'.
result-%update = COND #(
WHEN sy-subrc = 0 THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
ENDIF.
IF requested_authorizations-%delete = if_abap_behv=>mk-on.
AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID 'ZAUTH_FIELD' DUMMY
ID 'ACTVT' FIELD '06'.
result-%delete = COND #(
WHEN sy-subrc = 0 THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
ENDIF.
ENDMETHOD.

BDEF:

...
authorization master ( global, instance )
...

Handler:

METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR some_bdef RESULT result.
METHOD get_instance_authorizations.
READ ENTITIES OF some_bdef IN LOCAL MODE
ENTITY some_entity
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(res).
IF res IS INITIAL.
RETURN.
ENDIF.
LOOP AT res INTO DATA(r).
DATA is_delete_allowed TYPE if_abap_behv=>t_auth_value.
IF requested_authorizations-%delete = if_abap_behv=>mk-on.
AUTHORITY-CHECK OBJECT 'ZAUTH_OBJ'
ID 'ZAUTH_FIELD' FIELD r-some_field
ID 'ACTVT' FIELD '06'.
is_delete_allowed = COND #(
WHEN sy-subrc = 0 THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
ENDIF.
APPEND VALUE #( %tky = r-%tky
%delete = is_delete_allowed ) TO result.
ENDLOOP.
ENDMETHOD.

RAP BO precheck — валідує значення до запису у transactional buffer, можна теж робити AUTHORITY-CHECK там.

  • У кожному SELECT з dbtab без CDS access control — явний AUTHORITY-CHECK або фільтрація за правами.
  • Після AUTHORITY-CHECK завжди перевіряється sy-subrc.
  • CDS view entity для read-доступу має анотацію @AccessControl.authorizationCheck.
  • У RAP — get_global_authorizations покриває всі операції з mk-on.
  • У draft-BO враховано %action-Edit.
  • Для юніт-тестів auth-перевірки підмінено через test seam.

Адаптовано з 25_Authorization_Checks.md (Apache 2.0). Повний перелік нюансів — в оригіналі.