Skip to content

Lesson 15 Companion — CDS DCL and RAP Authorization ​

This companion supports:

text
Lesson 15 — Authorization: CDS DCL and RAP Authorization

Use it as:

text
instructor reference
syntax reference
troubleshooting guide
solution review

1. Authorization layers ​

The lesson separates four concepts:

ConceptMain question
DCLWhich rows may the user read?
Global authorizationMay this user perform an operation generally?
Instance authorizationMay this user perform it on this instance?
Feature controlIs it meaningful for the current business state?

These mechanisms complement one another.


2. Guided ownership field ​

Add to:

text
ZRESV_###
abap
responsible_user : abp_creation_user;

It is intentionally nullable because existing rows may already exist.


3. Root CDS change ​

Add:

abap
Reservation.responsible_user as ResponsibleUser,

and change:

abap
@AccessControl.authorizationCheck: #NOT_REQUIRED

to:

abap
@AccessControl.authorizationCheck: #CHECK

4. Access Control reference ​

abap
@EndUserText.label: 'Reservation Read Access'
@MappingRole: true
define role ZR_Reservation_###
{
  grant select on ZR_Reservation_###
    where ResponsibleUser = aspect user;
}

5. DCL mental model ​

For normal access:

text
application WHERE
+
DCL WHERE
=
effective row restriction

A row that fails DCL is not returned through the protected CDS read.

The row is not physically deleted.


6. Why aspect user is useful here ​

It gives a real user-dependent rule without requiring custom PFCG role provisioning:

text
ResponsibleUser
=
current authenticated ABAP user

This is reproducible in BTP Trial.


7. aspect user and current syntax ​

Use:

text
aspect user

inside DCL.

Do not use obsolete older forms such as:

text
ASPECT_USER

The predefined user aspect is the appropriate authorization-language construct for this condition.


8. PFCG authorization concept ​

Productive DCL can also use:

text
aspect pfcg_auth

to map CDS elements to authorization-object fields.

Example shape:

text
(Field) = aspect pfcg_auth(
  AUTH_OBJECT,
  AUTH_FIELD,
  ACTVT = '03'
)

The exact object and field names are application-specific.


9. Trial boundary ​

Certification knowledge — not reproducible in BTP Trial

This course does not provision custom productive PFCG authorization objects and business-role assignments.

Students should recognize:

text
AUTHORITY-CHECK
aspect pfcg_auth
activity values
PFCG/business roles

but the guided runtime proof uses the current user and ResponsibleUser.


10. BDEF authorization header ​

Replace:

abap
authorization master ( none )

with:

abap
authorization master ( global, instance )

This tells RAP that the root is the authorization master.


11. Field changes in BDEF ​

Recommended additions:

abap
field ( readonly:update ) ResponsibleUser;

If not already present:

abap
field ( readonly ) Status;

Keep existing:

text
managed Uuid
admin fields
ReservationNo field control
Fee/Currency instance features

12. Action authorization delegation ​

Reference:

abap
action ( features : instance, authorization: update )
  confirm result [1] $self;

action ( features : instance, authorization: update )
  cancel result [1] $self;

Meaning:

text
feature availability
→ still calculated independently

authorization
→ delegated to update authorization

13. Full BDEF excerpt ​

abap
managed implementation in class zbp_r_resv_### unique;
strict ( 2 );

define behavior for ZR_Reservation_### alias Reservation
persistent table zresv_###
lock master
authorization master ( global, instance )
etag master LocalLastChangedAt
{
  create;
  update;
  delete;

  field ( numbering : managed, readonly ) Uuid;

  field ( readonly )
    Status,
    LocalCreatedBy,
    LocalCreatedAt,
    LocalLastChangedBy,
    LocalLastChangedAt,
    LastChangedAt;

  field ( mandatory:create, readonly:update ) ReservationNo;

  field ( readonly:update ) ResponsibleUser;

  field ( features : instance ) Fee, CurrencyCode;

  determination setInitialStatus on modify { create; }

  validation validateCustomer on save
    { create; field CustomerName; }

  validation validateDate on save
    { create; field ReservationDate; }

  validation validateFee on save
    { create; field Fee, CurrencyCode; }

  action ( features : instance, authorization: update )
    confirm result [1] $self;

  action ( features : instance, authorization: update )
    cancel result [1] $self;

  mapping for zresv_###
  {
    Uuid               = uuid;
    ReservationNo      = reservation_no;
    CustomerName       = customer_name;
    CustomerEmail      = customer_email;
    WorkshopCode       = workshop_code;
    ReservationDate    = reservation_date;
    Status             = status;
    ResponsibleUser    = responsible_user;
    Fee                = fee;
    CurrencyCode       = currency_code;
    Notes              = notes;
    LocalCreatedBy     = local_created_by;
    LocalCreatedAt     = local_created_at;
    LocalLastChangedBy = local_last_changed_by;
    LocalLastChangedAt = local_last_changed_at;
    LastChangedAt      = last_changed_at;
  }
}

14. Generated authorization signatures ​

Use Quick Fix.

Expected declarations are equivalent to:

abap
METHODS get_global_authorizations
  FOR GLOBAL AUTHORIZATION
  IMPORTING
    REQUEST requested_authorizations FOR Reservation
  RESULT result.

METHODS get_instance_authorizations
  FOR INSTANCE AUTHORIZATION
  IMPORTING
    keys
    REQUEST requested_authorizations FOR Reservation
  RESULT result.

Prefer ADT-generated signatures.


15. Global authorization implementation ​

Training implementation:

abap
METHOD get_global_authorizations.

  IF requested_authorizations-%create = if_abap_behv=>mk-on.
    result-%create = if_abap_behv=>auth-allowed.
  ENDIF.

  IF requested_authorizations-%update = if_abap_behv=>mk-on.
    result-%update = if_abap_behv=>auth-allowed.
  ENDIF.

  IF requested_authorizations-%delete = if_abap_behv=>mk-on.
    result-%delete = if_abap_behv=>auth-allowed.
  ENDIF.

ENDMETHOD.

This is an implementation-contract exercise, not a production role model.


16. Productive global authorization pattern ​

SAP documentation commonly demonstrates logic equivalent to:

text
operation requested
→ run an authority check
→ return allowed or unauthorized

Activities can include:

text
01 create
02 change
06 delete

Do not invent a fake custom authorization object just to imitate production in Trial.


17. Instance authorization implementation ​

Reference:

abap
METHOD get_instance_authorizations.

  READ ENTITIES OF ZR_Reservation_### IN LOCAL MODE
    ENTITY Reservation
      FIELDS ( ResponsibleUser )
      WITH CORRESPONDING #( keys )
    RESULT DATA(reservations)
    FAILED failed.

  DATA current_user TYPE abp_creation_user.
  current_user = cl_abap_context_info=>get_user_technical_name( ).

  LOOP AT reservations INTO DATA(reservation).

    APPEND VALUE #(
      %tky = reservation-%tky
    ) TO result ASSIGNING FIELD-SYMBOL(<authorization>).

    IF requested_authorizations-%update = if_abap_behv=>mk-on.

      <authorization>-%update =
        COND #(
          WHEN reservation-ResponsibleUser = current_user
          THEN if_abap_behv=>auth-allowed
          ELSE if_abap_behv=>auth-unauthorized
        ).

      IF reservation-ResponsibleUser <> current_user.

        APPEND VALUE #(
          %tky = reservation-%tky
          %msg = new_message_with_text(
            severity = if_abap_behv_message=>severity-error
            text     = 'You are not responsible for this reservation'
          )
        ) TO reported-reservation.

      ENDIF.

    ENDIF.

    IF requested_authorizations-%delete = if_abap_behv=>mk-on.
      <authorization>-%delete = if_abap_behv=>auth-allowed.
    ENDIF.

  ENDLOOP.

ENDMETHOD.

18. Why reported matters ​

Authorization can be denied without an obvious explanation.

A reported message tells the consumer why.

The actual authorization decision remains:

text
auth-unauthorized

19. Why delete is allowed in the lesson ​

The lesson creates an intentionally unauthorized/unassigned row.

To keep repeated classroom runs simple:

text
update/actions
→ owner-controlled

delete
→ allowed

This is a training policy, not a general production recommendation.


20. Current user API ​

Use:

abap
cl_abap_context_info=>get_user_technical_name( )

SAP uses this API in ABAP Cloud examples for user-dependent logic.


21. Global permission request ​

abap
DATA request_global
  TYPE STRUCTURE FOR PERMISSIONS REQUEST ZR_Reservation_###.

request_global-%create = if_abap_behv=>mk-on.
request_global-%update = if_abap_behv=>mk-on.
request_global-%delete = if_abap_behv=>mk-on.

GET PERMISSIONS ONLY GLOBAL AUTHORIZATION
  ENTITY ZR_Reservation_###
  REQUEST request_global
  RESULT DATA(global_permissions)
  FAILED DATA(failed_global)
  REPORTED DATA(reported_global).

No instance key is supplied for a global authorization query.


22. Instance permission request ​

abap
DATA request_instance
  TYPE STRUCTURE FOR PERMISSIONS REQUEST ZR_Reservation_###.

request_instance-%update = if_abap_behv=>mk-on.
request_instance-%delete = if_abap_behv=>mk-on.

GET PERMISSIONS ONLY INSTANCE AUTHORIZATION
  ENTITY ZR_Reservation_###
  FROM VALUE #(
    ( Uuid = uuid )
  )
  REQUEST request_instance
  RESULT DATA(instance_permissions)
  FAILED DATA(failed_instance)
  REPORTED DATA(reported_instance).

Instance authorization requests need instance keys.


23. Permission result families ​

Authorization:

text
auth-allowed
auth-unauthorized

Feature control:

text
fc-o-enabled
fc-o-disabled
fc-f-unrestricted
fc-f-read_only

Never interpret one family as the other.


24. Feature-vs-authorization test ​

For the unassigned row:

text
Status = N
ResponsibleUser = initial

Expected:

text
feature:
confirm enabled

authorization:
update unauthorized

Because:

text
confirm authorization delegates to update

the action must still be denied.


25. DCL test design ​

Create:

text
98000001
ResponsibleUser = current user

98000002
ResponsibleUser = initial

After commit:

text
root F8
→ only 98000001

table Alt+F8
→ both rows

This is a direct, visible DCL proof.


26. Safe reset pattern ​

Because the protected root hides one training row, reset may use a read-only persistence lookup:

abap
SELECT FROM zresv_###
  FIELDS uuid
  WHERE reservation_no = '98000001'
     OR reservation_no = '98000002'
  INTO TABLE @DATA(old_keys).

Then modify only through EML:

text
DELETE by those UUIDs
COMMIT ENTITIES

No direct SQL writes.


27. Why the read-only reset exception is acceptable ​

The normal application path remains:

text
Consumer → EML → RAP BO

The read-only persistence lookup exists only because:

text
the lesson deliberately hides one test row with DCL

It is a repeatability technique, not application architecture.


28. Existing rows after DCL ​

Older Lesson 12–14 rows may have:

text
ResponsibleUser initial

They will no longer appear through the protected root.

Use:

text
table preview

when you need to prove they still exist.


29. Action delegation details ​

With:

text
authorization: update

the action's authorization follows the update permission.

This avoids separate owner logic for:

text
confirm
cancel

30. When delegation would be wrong ​

A future action might require a stronger privilege.

Example:

text
ordinary update
→ standard editor

approve high-value request
→ manager-only

Then:

text
authorization: update

may not be appropriate.


31. DCL and RAP authorization solve different problems ​

An instance may be:

text
readable but not writable

or:

text
globally writable in principle
but unauthorized for this instance

A robust backend uses the correct layer for each concern.


32. Why authorization belongs before OData ​

Lesson 16 exposes the BO through OData.

Authorization should already exist before exposure.

Otherwise the architecture risks:

text
consumer-facing service
without backend authorization

33. #CHECK vs #NOT_REQUIRED ​

Before Lesson 15:

text
#NOT_REQUIRED

was appropriate because no DCL protected the root.

After DCL:

text
#CHECK

expresses the intended protected model.


34. DCL troubleshooting ​

If expected rows are missing:

text
check current technical user
check ResponsibleUser
check #CHECK
check Access Control activation
check @MappingRole
check protected CDS entity name

35. Authorization troubleshooting ​

If a write/action fails:

text
global authorization
instance authorization
ResponsibleUser
requested_authorizations
action delegation
feature result
FAILED
REPORTED

36. Global allowed + instance unauthorized ​

This is valid:

text
global update = allowed
instance update = unauthorized

Meaning:

text
the user may update Reservations generally
but not this particular Reservation

37. Feature enabled + authorization unauthorized ​

Also valid:

text
feature:
confirm enabled

authorization:
update unauthorized

The operation is denied.

Business state and user permission are independent dimensions.


38. Provider-side local mode ​

Authorization handlers read BO data with:

text
IN LOCAL MODE

because the provider needs its own state to calculate authorization.

External consumer classes must not use local mode.


39. DCL is read protection ​

DCL is primarily a CDS read-access mechanism.

RAP modifying operations require RAP authorization design.

Do not assume:

text
hidden row
=
all write operations automatically secure

40. Certification relevance ​

Practical certification work can require:

text
creating an Access Control
repairing a DCL condition
changing #NOT_REQUIRED to #CHECK
changing authorization master settings
generating authorization handlers
using requested_authorizations
returning RAP auth constants
testing with GET PERMISSIONS

The skill is tracing the full authorization path.


41. Practice BO mapping ​

Practice uses:

text
ZR_ISSUE_###

Add:

text
ResponsibleUser

Then:

text
DCL
→ ResponsibleUser = aspect user

instance update auth
→ current user must equal ResponsibleUser

startProcessing
close
→ authorization delegates to update

42. Lesson 16 boundary ​

Do not add:

text
projection CDS
projection BDEF
value help
metadata extension
Service Definition
Service Binding
OData V4

Authorization should already work before those layers appear.