Skip to content

Lesson 15 — Authorization: CDS DCL and RAP Authorization ​

Lesson 14 answered:

text
Is this operation meaningful for the current business state?

For example:

text
Status = N
→ confirm can be enabled

Status = X
→ confirm can be disabled

That is:

text
feature control

Lesson 15 asks a different question:

text
Is this user allowed to see or change this data?

That is:

text
authorization

Today you will protect the Reservation Business Object at two levels:

text
CDS DCL
→ controls read access to rows

RAP authorization
→ controls modifying operations

The architecture becomes:

text
Consumer
   ↓
CDS / EML
   ↓
Authorization Layer
   ├─ CDS DCL for reads
   ├─ RAP global authorization
   └─ RAP instance authorization
   ↓
RAP Business Object
   ↓
Persistence

Lesson information ​

Teacher-led timeAbout 3 hours
Self-practice timeAbout 3 hours
EnvironmentSAP BTP ABAP Trial
PrerequisiteLesson 14 + Checkpoint 3
Business ObjectZR_RESERVATION_###
Behavior PoolZBP_R_RESV_###
Authorization test classZCL_RESV_AUTH_###
New business fieldResponsibleUser
New repository objectCDS Access Control / DCL
Main outcomeUser-dependent read and write protection

Replace:

text
###

with your own student/group suffix.


Learning objectives ​

After the teacher-led part, you should be able to:

  • explain the difference between feature control and authorization;
  • explain the difference between read authorization and write authorization;
  • explain what CDS DCL protects;
  • create a CDS Access Control object in ADT;
  • use @AccessControl.authorizationCheck: #CHECK;
  • use @MappingRole: true;
  • use grant select on;
  • use the predefined DCL aspect user;
  • explain why DCL is applied implicitly to protected CDS access;
  • explain what RAP global authorization means;
  • explain what RAP instance authorization means;
  • replace authorization master ( none ) with authorization master ( global, instance );
  • generate get_global_authorizations;
  • generate get_instance_authorizations;
  • use if_abap_behv=>auth-allowed;
  • use if_abap_behv=>auth-unauthorized;
  • use GET PERMISSIONS ONLY GLOBAL AUTHORIZATION;
  • use GET PERMISSIONS ONLY INSTANCE AUTHORIZATION;
  • delegate action authorization to update authorization;
  • prove that an action can be feature-enabled but authorization-denied;
  • explain why IN LOCAL MODE belongs to provider-side authorization implementation;
  • distinguish BTP Trial training checks from productive PFCG-based authorization design.

1. Authorization is not feature control ​

Lesson 14 used:

text
Status

to decide whether:

text
confirm
cancel
Fee editing

were currently available.

That is business-state logic.

Authorization answers:

text
Who is the user?
What is the user allowed to do?
Which instances belong to that user?

Do not merge the concepts.


2. One instance can have two different answers ​

Imagine:

text
Reservation Status = N

Feature control may say:

text
confirm = enabled

But authorization may say:

text
current user is not responsible for this Reservation
→ confirm not authorized

Both can be true:

text
business state allows it
user permission denies it

3. Read authorization vs write authorization ​

For this course:

text
CDS DCL
→ protects reads

RAP authorization
→ protects modifying operations

Questions:

text
Which rows may this user read?

May this user update/delete/execute an action?

These are complementary layers.


4. Authorization model for today ​

Add a business field:

text
ResponsibleUser

Meaning:

The technical ABAP user responsible for the Reservation.

Read rule:

text
A user may read Reservations
only when ResponsibleUser = current user

Write rule:

text
A user may update a Reservation
only when ResponsibleUser = current user

Actions:

text
confirm
cancel

reuse:

text
update authorization

Delete remains allowed in this training lesson so cleanup stays repeatable.


5. Why not use LocalCreatedBy? ​

LocalCreatedBy is an administrative audit field.

Business ownership can differ from creation identity.

Example:

text
CreatedBy       = USER_A
ResponsibleUser = USER_B

So ownership deserves its own business field.


6. Add responsible_user to persistence ​

Open:

text
ZRESV_###

Add:

abap
responsible_user : abp_creation_user;

Do not make it:

text
KEY
NOT NULL

because older Lesson 12–14 rows may already exist.

Activate:

text
Ctrl+F3

7. Why the field is nullable ​

Old rows have no Lesson 15 owner value.

A nullable field allows the table to evolve without rebuilding old data.

New Lesson 15 rows will deliberately supply:

text
ResponsibleUser

for authorization tests.


8. Add ResponsibleUser to the root CDS ​

Open:

text
ZR_RESERVATION_###

Add:

abap
Reservation.responsible_user as ResponsibleUser,

Place it with the business fields.


9. Change the CDS access-control annotation ​

Change:

abap
@AccessControl.authorizationCheck: #NOT_REQUIRED

to:

abap
@AccessControl.authorizationCheck: #CHECK

The root is now intended to participate in CDS access-control evaluation.


10. Existing rows may disappear from root preview ​

Older rows may have:

text
ResponsibleUser = initial

Once DCL becomes active, they will not satisfy:

text
ResponsibleUser = current user

They may disappear from:

text
F8 root CDS preview

That is not data loss.

They still exist in persistence.


11. What is DCL? ​

DCL means:

text
Data Control Language

A CDS Access Control object defines row-level read restrictions.

Mental model:

text
normal CDS selection
+
DCL condition
=
authorized result set

12. Create an Access Control object ​

In ADT:

text
Right-click package
→ New
→ Other ABAP Repository Object
→ Core Data Services
→ Access Control

Use:

text
Name: ZR_RESERVATION_###
Description: Reservation Read Access

13. Define the CDS role ​

Use:

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

Replace ###.


14. @MappingRole: true ​

This annotation makes the CDS role participate in implicit access-control evaluation for users.

It is not the same thing as:

text
assigning a PFCG/business role to one user

Those are different authorization concepts.


15. grant select on ​

The role grants read access to:

text
ZR_RESERVATION_###

only where:

text
ResponsibleUser = logged-on user

Rows that fail the rule are filtered from normal protected reads.


16. aspect user ​

This condition:

abap
ResponsibleUser = aspect user

compares ResponsibleUser with the current authenticated ABAP user.

Do not hard-code:

text
MYUSER
STUDENT01

into authorization logic.


17. Activate the Access Control ​

Run:

text
Ctrl+F2
Ctrl+F3

Verify:

text
Root CDS active
Access Control active

18. DCL is implicit ​

Normal protected consumers do not call a special:

text
CHECK DCL

statement.

The access condition participates automatically when the protected CDS entity is read.


19. DCL does not replace write authorization ​

DCL answers:

text
Can the user read this row?

It does not replace RAP behavior authorization for:

text
update
delete
actions

So the lesson now adds RAP authorization too.


20. Enable RAP global + instance authorization ​

Open the BDEF.

Replace:

abap
authorization master ( none )

with:

abap
authorization master ( global, instance )

This makes the Reservation root the authorization master.


21. Global authorization ​

Global authorization asks:

text
Can this user perform this operation in general?

Examples:

text
May this user create Reservations?
May this user generally update Reservations?
May this user generally delete Reservations?

It does not depend on one particular Reservation.


22. Instance authorization ​

Instance authorization asks:

text
Can this user perform the operation
on this particular Reservation?

It may depend on fields of the instance.

Today:

text
ResponsibleUser

drives the update decision.


23. Authorization result constants ​

Use:

abap
if_abap_behv=>auth-allowed

and:

abap
if_abap_behv=>auth-unauthorized

Do not use feature-control constants for authorization results.


24. Feature vs authorization constant families ​

Feature control:

text
if_abap_behv=>fc-o-...
if_abap_behv=>fc-f-...

Authorization:

text
if_abap_behv=>auth-allowed
if_abap_behv=>auth-unauthorized

This distinction matters in practical repair work.


25. Map ResponsibleUser ​

Add to BDEF persistence mapping:

abap
ResponsibleUser = responsible_user;

26. Protect owner reassignment ​

Add:

abap
field ( readonly:update ) ResponsibleUser;

For this lesson:

text
CREATE
→ consumer may assign ResponsibleUser

UPDATE
→ ResponsibleUser cannot be reassigned normally

27. Make Status read-only if necessary ​

If your current BDEF still allows ordinary external Status updates, change it so Status is read-only.

Status should be changed by:

text
setInitialStatus
confirm
cancel

not arbitrary normal update requests.


28. Delegate action authorization to update ​

Change the actions to:

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

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

The actions still keep:

text
features : instance

for state-based availability.

Authorization is delegated separately.


29. Why keep both feature and authorization control? ​

For confirm:

text
Feature question:
Is Status = N?

Authorization question:
Is current user ResponsibleUser?

An operation must respect both concerns.


30. Generate authorization handler methods ​

Use:

text
Ctrl+1

from the BDEF.

Generate methods 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.


31. Productive authorization vs Trial authorization ​

Productive RAP authorization often evaluates:

text
authorization objects
business roles
activity values
organizational restrictions
released authorization APIs

The course needs a reproducible BTP Trial exercise.

Therefore:

text
global authorization
→ allow-all training implementation

instance authorization
→ real current-user ownership comparison

32. Certification knowledge — not reproducible in BTP Trial ​

Certification knowledge — not reproducible in BTP Trial

SAP RAP examples commonly connect authorization handlers to real authorization objects or helper APIs.

A productive check can distinguish activities such as:

text
create
change
delete

The Trial course does not provision a custom PFCG authorization object and role assignment landscape for each student.

Understand where those checks belong even though the full administration scenario is not reproduced here.


33. Implement global authorization ​

Use:

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 proves the RAP global-authorization contract.

It is intentionally not a productive role design.


34. Why inspect requested_authorizations? ​

The framework tells you which permissions are currently requested.

Pattern:

text
requested?
→ calculate authorization

not requested?
→ do not do unnecessary work

35. Obtain the current technical user ​

Use:

abap
cl_abap_context_info=>get_user_technical_name( )

Store the value in a compatible user variable:

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

36. Instance authorization rule ​

Use:

text
UPDATE

ResponsibleUser = current technical user
→ allowed

otherwise
→ unauthorized

For classroom cleanup:

text
DELETE
→ allowed

37. Why delete is allowed today ​

This is a deliberate training simplification.

You will create an intentionally unauthorized/unassigned Reservation.

If delete were also owner-only, repeatable reset would be awkward.

A productive system should define delete authorization according to its real business policy.


38. Read ownership inside the authorization handler ​

Use:

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

The handler needs current BO state to calculate instance authorization.


39. Implement instance authorization ​

Use a pattern equivalent to:

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
        ).

    ENDIF.

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

  ENDLOOP.

ENDMETHOD.

40. Add an authorization message ​

When update is unauthorized, add a message equivalent to:

abap
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.

The authorization decision still comes from:

text
auth-unauthorized

The message explains it.


41. Why actions need no separate owner comparison ​

Because:

text
confirm authorization = update authorization
cancel authorization  = update authorization

via:

text
authorization: update

one owner rule protects:

text
normal update
confirm
cancel

42. Activate the full authorization model ​

Use:

text
Ctrl+F2
Ctrl+Shift+F3

Verify:

text
ZRESV_###
ZR_RESERVATION_###
Access Control
Behavior Definition
ZBP_R_RESV_###

all activate.


43. Create ZCL_RESV_AUTH_### ​

Create an ABAP class implementing:

text
IF_OO_ADT_CLASSRUN

This class is an external consumer.

Do not use:

text
IN LOCAL MODE

inside it.


44. Reserved test numbers ​

Use:

text
98000001
98000002

Meaning:

text
98000001
→ owned by current user

98000002
→ ResponsibleUser initial

45. Repeatable reset with DCL present ​

DCL can hide one training row.

For reset only, you may use a read-only persistence lookup to discover UUIDs for exactly:

text
98000001
98000002

Then:

text
delete those UUIDs through EML
commit

No direct SQL write is allowed.


46. Display the current user ​

In the consumer:

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

out->write( |Current user: { current_user }| ).

47. Create the owned Reservation ​

Create valid Lesson 13 data with:

text
ReservationNo   = 98000001
ResponsibleUser = current user
Status          = omitted

The Lesson 13 determination should default:

text
Status = N

Use:

text
%cid = OWNED

48. Create the unassigned Reservation ​

Create another valid Reservation:

text
ReservationNo   = 98000002
ResponsibleUser = initial
Status          = omitted

Use:

text
%cid = UNASSIGNED

Save both UUIDs from:

text
MAPPED

before commit.


49. Commit both creates ​

Use:

text
COMMIT ENTITIES

Expected:

text
both create operations save successfully

because global create authorization is allowed.


50. DCL proof with F8 ​

Open:

text
ZR_RESERVATION_###

with:

text
F8

Expected:

text
98000001 visible
98000002 hidden

The DCL condition is true only for the owned row.


51. Persistence proof with Alt+F8 ​

Open:

text
ZRESV_###

with:

text
Alt+F8

Expected:

text
98000001 exists
98000002 exists

This proves:

text
DCL filters reads
DCL does not delete rows

52. Create a global permission request ​

Use:

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

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

53. GET PERMISSIONS — global authorization ​

Use:

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

Output all three response structures.

Expected training result:

text
create allowed
update allowed
delete allowed

54. Create an instance authorization request ​

Use:

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

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

55. GET PERMISSIONS — owned Reservation ​

Use:

abap
GET PERMISSIONS ONLY INSTANCE AUTHORIZATION
  ENTITY ZR_Reservation_###
  FROM VALUE #(
    ( Uuid = uuid_owned )
  )
  REQUEST instance_request
  RESULT DATA(auth_owned)
  FAILED DATA(failed_auth_owned)
  REPORTED DATA(reported_auth_owned).

Expected:

text
update allowed
delete allowed

56. GET PERMISSIONS — unassigned Reservation ​

Repeat using:

text
uuid_unassigned

Expected:

text
update unauthorized
delete allowed

57. Ask for Lesson 14 instance features too ​

For the unassigned Reservation:

text
Status = N

Request its instance features.

Expected:

text
confirm feature = enabled

because Status allows it.


58. Compare feature control and authorization ​

For the same unassigned row:

text
Feature:
confirm enabled

Authorization:
update unauthorized

Because the action delegates authorization to update:

text
confirm must still be denied

This is the central Lesson 15 runtime observation.


59. Confirm the owned Reservation ​

Execute:

text
confirm

for:

text
98000001

Expected:

text
action succeeds
Status N → C
COMMIT succeeds

60. Attempt confirm on the unassigned Reservation ​

Execute:

text
confirm

using the known UUID for:

text
98000002

Expected:

text
authorization denies execution
Status remains N
message explains the denial

The feature may be enabled, but authorization wins.


61. Attempt a normal UPDATE on the unassigned row ​

Try:

text
Notes = 'Unauthorized update attempt'

Expected:

text
update denied
persisted Notes unchanged

Inspect:

text
FAILED
REPORTED

and the permission result.


62. Cleanup the unassigned training row ​

Delete:

text
98000002

through EML using its known UUID.

Delete authorization is deliberately allowed.

Commit.


63. Final guided state ​

Keep:

text
98000001

for inspection.

Expected:

text
ResponsibleUser = current user
Status = C

64. aspect user vs aspect pfcg_auth ​

Today you used:

text
aspect user

DCL can also use:

text
aspect pfcg_auth

to evaluate PFCG authorization data.


65. Certification knowledge — PFCG-based DCL ​

Certification knowledge — not reproducible in BTP Trial

A productive DCL can use a PFCG condition conceptually shaped like:

text
(Field) = aspect pfcg_auth(
  authorization_object,
  authorization_field,
  ACTVT = '03'
)

Our Trial course does not provision custom productive authorization objects and business-role assignments.

Know the purpose and location of the mechanism.


66. CDS role is not a PFCG role ​

This:

abap
define role ...

creates a CDS DCL access-control artifact.

It is not the same as:

text
a business role
a PFCG role

Do not confuse the shared word:

text
role

67. Why authorization implementation uses local mode ​

The provider needs BO data to calculate authorization.

Without provider-local access, you can create circular reasoning:

text
need authorization to read
need data to calculate authorization

The handler uses:

text
READ ENTITIES ... IN LOCAL MODE

to inspect its own BO state.


68. Local mode belongs to providers ​

Provider:

text
Behavior Pool
authorization method
IN LOCAL MODE

External consumer:

text
ZCL_RESV_AUTH_###
normal EML

Never use local mode to bypass authorization from normal application code.


69. DCL debugging ​

If a row disappears:

text
check ResponsibleUser
check current user
check @MappingRole
check #CHECK
check DCL entity name
check DCL activation

Then compare:

text
F8 root
Alt+F8 table

70. RAP authorization debugging ​

If a modification is denied:

text
GET PERMISSIONS global
GET PERMISSIONS instance
ResponsibleUser
requested_authorizations
FAILED
REPORTED
feature result

Do not assume the feature matrix is the authorization matrix.


71. Global allowed + instance denied is valid ​

Example:

text
global update = allowed
instance update = unauthorized

Meaning:

text
user may update Reservations generally
but not this Reservation

No contradiction exists.


72. Feature enabled + authorization denied is valid ​

Example:

text
Status = N
→ confirm feature enabled

ResponsibleUser <> current user
→ update authorization denied

The final operation is denied.


73. Certification alignment ​

The current Backend Developer – ABAP Cloud certification is practical/system-based.

Authorization-related tasks can therefore reward the ability to:

text
create/repair DCL
change CDS authorization annotation
change BDEF authorization declaration
generate handler methods
fill RAP authorization result
use GET PERMISSIONS
activate dependent artifacts
test runtime behavior

Hands-on ADT fluency matters more than memorizing definitions.


74. Practical repair decision tree ​

text
Wrong rows visible?
→ DCL / #CHECK / DCL condition

All writes denied?
→ global authorization

Only some instances denied?
→ instance authorization

Action greyed/disabled because of state?
→ feature control

Action business state okay but still denied?
→ authorization

75. Knowledge check ​

1. What is DCL? ​

2. What does aspect user do? ​

3. Why does the root change to #CHECK? ​

4. What is the difference between a CDS role and a PFCG role? ​

5. What is global authorization? ​

6. What is instance authorization? ​

7. Why do actions delegate to update authorization here? ​

8. What is the difference between auth-unauthorized and fc-o-disabled? ​

9. Why can an instance exist in the table but not appear in root Data Preview? ​

10. Why can feature control allow an action while authorization denies it? ​

11. Why does provider authorization code use local mode? ​

12. Why is real PFCG administration marked as certification knowledge in this course? ​


76. Teacher-led completion checklist ​


77. End-of-day mental model ​

text
                USER
                 │
        ┌────────┴────────┐
        │                 │
      READ             MODIFY
        │                 │
      DCL          RAP Authorization
        │          ┌──────┴──────┐
        │        Global       Instance
        │          │              │
        └──────────┴──────┬───────┘
                          ↓
                    RAP Business Object
                          ↓
                     Persistence

Remember:

text
DCL
→ Which rows can I read?

Global authorization
→ May this user perform this operation in general?

Instance authorization
→ May this user perform it on this instance?

Feature control
→ Is the operation meaningful for the current business state?

Lesson 16 adds:

text
Projection
Value Help
Metadata
Service Definition
Service Binding
OData V4