Day 6: CDS Access Control (DCL)
Day 6: CDS Access Control (DCL)
Concept of Authorization in CDS
@AccessControl.authorizationCheck
Define DCL objects
Practice:
Create a DCL restricting data based on user
🔹 1. Concept of Authorization in CDS
In traditional ABAP, data access control is often implemented in the application logic. However, in ABAP CDS (Core Data Services), we implement access control at the data model level using DCL (Data Control Language).
📌 Why Authorization in CDS?
To ensure sensitive data is not exposed to unauthorised users.
To move security logic closer to the data layer.
To support reusability and consistency across apps (Fiori, OData, etc.).
🔹 2. @AccessControl.authorizationCheck
This CDS annotation tells the system how the CDS view handles authorisation.
🔹 Syntax
@AccessControl.authorizationCheck: #CHECK
📘 Options:
#CHECK: Apply authorisation as per DCL rules.
#NOT_REQUIRED: No authorisation check needed (used for public/non-sensitive data).
#PRIVILEGED_ONLY: Only privileged code can bypass access control (rarely used).
✅ Example:
CDS View:
@AccessControl.authorizationCheck: #CHECK
define view entity ZI_SalesOrder as select from vbak {
key vbeln,
erdat,
vkorg
}
This view must have a DCL object (see next section) that defines which user can access which rows.
🔹 3. What are DCL Objects?
DCL (Data Control Language) objects are special authorisation rules written separately to define row-level access to CDS views.
📌 Structure:
DCL Object (Z_SALESORDER_AUTH) controls access to CDS view (ZI_SalesOrder)
Uses PFCG Roles and Authorization Objects
🔧 Syntax of DCL:
define role Z_SALESORDER_AUTH {
grant select on ZI_SalesOrder
where vkorg = aspect p_orgid;
}
vkorg: Field in CDS view (Sales Org)
p_orgid: Authorization field (from SU24 object)
aspect: Maps to authorization objects
🔹 4. Step-by-step: Create a DCL Restricting Data Based on User
Let’s say, each sales employee should only see Sales Orders from their own Sales Org.
💼 Real-time Example
📘 Step 1: Create CDS View (ZI_SalesOrder)
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order View with Authorization'
define view entity ZI_SalesOrder as select from vbak {
key vbeln,
erdat,
vkorg
}
📘 Step 2: Identify Authorisation Object
We use the standard authorisation objects V_VBAK_VKO which includes VKORG (Sales Org).
📘 Step 3: Create DCL Object
Go to transaction SU24 to check authorization objects → Find V_VBAK_VKO.
Now, create a DCL in ADT (Eclipse):
define role ZI_SALESORDER_DCL {
grant select on ZI_SalesOrder
where vkorg = aspect P_VKORG;
}
This means: only show sales orders where the vkorg matches the VKORG from the user’s role.
📘 Step 4: Assign Role to User (via PFCG)
Create a PFCG Role
Assign Authorization Object V_VBAK_VKO
Set VKORG value (e.g., 1000)
Assign this role to your test user
3 full ADT-ready examples of CDS Views with corresponding DCL Objects and test scenarios, each targeting real-world business use cases. These examples are structured to help you practice and implement row-level security using CDS and DCL in ABAP on HANA (S/4HANA environment).
🔹 Example 1: Sales Orders by Sales Org (VKORG)
📄 CDS View: ZI_SalesOrder
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Orders by Sales Org'
define view entity ZI_SalesOrder as select from vbak
{
key vbeln,
erdat,
auart,
vkorg
}
🔐 DCL Object: ZROLE_SALESORDER
define role ZROLE_SALESORDER {
grant select on ZI_SalesOrder
where vkorg = aspect P_VKORG;
}
👤 Authorization Object Used: V_VBAK_VKO
🔸 Field: VKORG
🧪 Test Scenario
Create a PFCG role.
Add authorization object V_VBAK_VKO.
Assign value 1000 to VKORG.
Assign the role to user A.
When user A accesses a Fiori app or SE16N using this view, they will only see Sales Orders where VKORG = 1000.
🔹 Example 2: Material Master by Plant (WERKS)
📄 CDS View: ZI_MaterialMaster
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Material by Plant'
define view entity ZI_MaterialMaster as select from marc
{
key matnr,
werks,
dispo,
dispo as planner,
pstat
}
🔐 DCL Object: ZROLE_MATPLANT
define role ZROLE_MATPLANT {
grant select on ZI_MaterialMaster
where werks = aspect P_WERKS;
}
👤 Authorization Object Used: M_MATE_WWR
🔸 Field: WERKS
🧪 Test Scenario
Create a role in PFCG.
Add object M_MATE_WWR and set WERKS = 1100.
Assign the role to user B.
User B will see materials only from Plant 1100.
🔹 Example 3: Employee Records by Personnel Area (WERKS)
📄 CDS View: ZI_EmployeeInfo
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Employee Info by Personnel Area'
define view entity ZI_EmployeeInfo as select from pa0001
{
key pernr,
ename,
werks,
plans,
orgeh
}
🔐 DCL Object: ZROLE_EMPLOYEE
define role ZROLE_EMPLOYEE {
grant select on ZI_EmployeeInfo
where werks = aspect PERS_AREA;
}
👤 Authorization Object Used: P_ORGIN
🔸 Field: WERKS (Personnel Area)
🧪 Test Scenario
Create a role in PFCG.
Add object P_ORGIN, set WERKS = HR01.
Assign role to user C.
User C will only see employees from Personnel Area HR01.
📌 Summary of Access Control Flow:
User opens app/report using CDS view.
System checks CDS @AccessControl.authorizationCheck: #CHECK
Executes DCL rules.
Checks PFCG role authorizations.
Displays only allowed records.
User opens app/report using CDS view.
System checks CDS @AccessControl.authorizationCheck: #CHECK
Executes DCL rules.
Checks PFCG role authorizations.
Displays only allowed records.
✅ Best Practices
Always use #CHECK for sensitive data.
Modularise logic using DCLs and CDS views separately.
Use authorisation objects already present in SU24 (standard SAP).
Always use #CHECK for sensitive data.
Modularise logic using DCLs and CDS views separately.
Use authorisation objects already present in SU24 (standard SAP).
🧪 📋 General Testing Steps
✅ Go to Transaction: PFCG.
🔧 Create Role → Add Authorization Object(s).
🧍♂️ Assign to a test user.
🧪 Open Fiori App / SE16N / RSRT / SE11 to test CDS View.
🛑 If you get "no data", recheck your PFCG values or CDS-DCL logic.
✔ If you see filtered records → DCL is working as expected.
📝 Best Practices Recap
✅ VDM Project with DCL
Let's build a complete VDM-style CDS View project (Basic → Composite → Consumption) with DCL from scratch — step by step, error-free, ADT-ready, and explained at each stage.
Let’s assume a real-time example:
You want to display Sales Order header data but restrict it based on Sales Organization (VKORG) using DCL. This is a common use case in companies where different users should only see data from their responsible org units.
🔹 Overview of What We'll Build
1️⃣ Basic View: ZB_I_SalesOrderHeader
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Basic View for Sales Orders'
define view entity ZB_I_SalesOrderHeader
as select from vbak
{
key vbeln, -- Sales Document
erdat, -- Creation Date
vkorg, -- Sales Organization
kunnr, -- Sold-To Party
auart, -- Sales Doc Type
netwr, -- Net Value
waerk -- Currency
}
✅ Explanation:
This view directly fetches sales header fields from VBAK. It has the @AccessControl.authorizationCheck: #CHECK annotation which ensures DCL gets applied.
2️⃣ Composite View: ZC_I_SalesOrderHeaderDetails
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Composite View with Customer Association'
define view entity ZC_I_SalesOrderHeaderDetails
as select from ZB_I_SalesOrderHeader
association [0..1] to kna1 as _Customer
on ZB_I_SalesOrderHeader.kunnr = _Customer.kunnr
{
key vbeln,
erdat,
vkorg,
kunnr,
auart,
netwr,
waerk,
_Customer.name1 as CustomerName
}
✅ Explanation:
Adds association to KNA1 (customer master) to get customer name. Improves modularity — no joins are repeated.
3️⃣ Consumption View: ZC_SalesOrderConsumption
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Consumption View for UI'
@UI.headerInfo: {
typeName: 'Sales Order',
typeNamePlural: 'Sales Orders',
title: { value: 'vbeln' },
description: { value: 'auart' }
}
define view entity ZC_SalesOrderConsumption
as select from ZC_I_SalesOrderHeaderDetails
{
key vbeln,
erdat,
vkorg,
auart,
kunnr,
CustomerName,
netwr,
waerk
}
✅ Explanation:
This is your Fiori/UI consumption layer. It includes @UI.headerInfo for list/report apps. This is the view exposed in OData.
4️⃣ DCL Role: ZB_R_SalesOrderRestrict
define role ZB_R_SalesOrderRestrict {
grant select on ZB_I_SalesOrderHeader
where vkorg = session_context('S_VKORG');
}
✅ Explanation:
Restricts data to only those VKORG values set in the user's session. You can simulate in ADT:
CALL FUNCTION 'SET_SESSION_CONTEXT'
EXPORTING
name = 'S_VKORG'
value = '1000'.
✅ Real usage: Assign this dynamically through user roles (SU01 / PFCG).
🧪 Testing Setup
➤ Option 1: Test via ADT Preview
Set the session context manually (see above)
Right-click view → “Open With → Data Preview”
➤ Option 2: Test via Fiori List Report or Smart Filter App
Expose the consumption view via OData
Restriction will automatically kick in
🔄 Summary (Folder Structure)
ZB_I_SalesOrderHeader --> Basic View (from VBAK)
ZC_I_SalesOrderHeaderDetails --> Composite View (adds association)
ZC_SalesOrderConsumption --> Consumption View (Fiori-ready)
ZB_R_SalesOrderRestrict --> DCL Role (restrict by VKORG)
🔍 Verified Sources Referenced
Lets See DCL in Detail
📘 DCL — Ultimate Master Guide (SAP-verified)
1️⃣ What is DCL (Data Control Language)?
✅ DCL = Authorization for CDS Views (Core Data Services)
SAP introduced DCL so that you can control who can see what data at the data model (CDS) level itself.
It is mandatory when you work with:
Fiori apps (List Reports, Smart Fields)
Analytical Queries
RAP (ABAP RESTful Programming Model)
🧠 Think of it as a "WHERE Clause for Authorization", maintained separately from normal SELECTs.
📚 SAP Official Definition
"Data Control Language (DCL) defines declarative authorization rules for CDS entities, enforcing row-level access control at the data model layer."
(Source: SAP Help Portal - CDS Access Control)
2️⃣ How DCL Works
You create a Role for a CDS Entity using a DCL file.
You specify when and how access is granted (grant select).
SAP at runtime injects authorization checks automatically during CDS consumption.
3️⃣ Basic DCL Syntax
define role <Role_Name>
for entity <CDS_View>
{
grant select
on <CDS_View>
where <condition>;
}
4️⃣ Real Simple Example
✅ A DCL restricting users to see only their own Company Code data:
define role ZR_CompanyCodeAccess
for entity ZI_Customer
{
grant select on ZI_Customer
where bukrs = $session.company_code;
}
✅ Here:
bukrs = Company Code in CDS
$session.company_code = User's own company code from session
📋 Important Concepts inside DCL
5️⃣ Session Context Variables You Can Use
✅ Usage: Inside your where clause.
6️⃣ Example: Authorization Based on User
✅ Allow only logged-in user's Sales Orders:
define role ZR_SalesOrderUser
for entity I_SalesOrder
{
grant select on I_SalesOrder
where created_by = $session.user;
}
7️⃣ Connecting DCL to PFCG Roles
✅ Important Point:
DCL is technical definition only.
➔ To make it work with SAP User Authorization Profiles, you:
Map it to Authorization Objects (S_USER_AUTH, etc.)
Use authorizationCheck: #CHECK in the consuming CDS
Maintain user profiles in SU01 / PFCG
Example:
@AccessControl.authorizationCheck: #CHECK
define view entity ZI_SalesOrder
as select from vbak
{
vbeln,
erdat
}
Here, CDS expects DCL to be enforced during read.
8️⃣ Advanced DCL: Using Authorization Objects (PFCG)
✅ You can bind DCL conditions to Authorization Object Fields!
define role ZR_SalesOrderAuthObj
for entity I_SalesOrder
{
grant select on I_SalesOrder
where sales_organization = $user.s_salesorg;
}
Where:
$user.s_salesorg → user's assigned sales org value in Authorization Object S_SALESORG.
✅ This way DCL + PFCG are fully linked!
9️⃣ DCL with Aspect (Reusable Authorization)
✅ You create an Aspect (modular block) separately:
define aspect ZAspectSalesOrg
aspect for I_SalesOrder
{
sales_organization;
}
✅ Then reuse inside DCL:
define role ZR_SalesOrderAccess
for entity I_SalesOrder
{
grant select on I_SalesOrder
where aspect ZAspectSalesOrg;
}
✅ Cleaner, Reusable, Professional approach!
🔟 Common Special Cases
🎯 Real-time Business Scenario Examples
✅ Allow Sales Managers to see only their Sales Org Orders:
define role ZR_SalesManagerOrders
for entity I_SalesOrder
{
grant select on I_SalesOrder
where sales_organization = $session.sales_organization;
}
✅ Allow Admins to see everything:
define role ZR_AdminFullAccess
for entity I_SalesOrder
{
grant select unrestricted;
}
✅ Restrict employees based on Department (with Aspect):
define aspect ZDeptAspect
aspect for ZI_Employee
{
department;
}
define role ZR_EmployeeAccess
for entity ZI_Employee
{
grant select on ZI_Employee
where aspect ZDeptAspect;
}
📚 SAP Official Resources Cross-Verification
SAP Help Portal - CDS Access Control
Authorization Aspects
Session Variables in CDS
Best Practices for DCL
🚀 Key Takeaways
🚀 Full Real-World Project:
Sales Order Authorization by Sales Organization (VDM + DCL + Annotations)
🧩 Project Scenario:
Users should only see Sales Orders that belong to their own Sales Organization (sales_org) based on session context.
UI should allow:
Searching Orders
Filtering Orders
Authorization control must be modularized using Aspect.
Should be ready for OData/Fiori publishing.
🏗 Step-by-Step Full Build
1️⃣ Create the Database Table (for example purpose)
@EndUserText.label: 'Sales Order Table'
@AbapCatalog.enhancementCategory: #NOT_EXTENSIBLE
@AbapCatalog.deliveryClass: #A
@AbapCatalog.dataMaintenance: #LIMITED
define table zsalesorder {
key client : abap.clnt not null;
key vbeln : abap.char(10) not null; // Sales Order Number
erdat : abap.dats; // Created On
sales_org : abap.char(4); // Sales Organization
customer : abap.char(10); // Customer Number
net_value : abap.curr(15,2); // Net Value
currency : abap.cuky; // Currency Key
}
2️⃣ Basic View Entity (VDM Layer 1 - Basic)
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Basic Sales Order Entity'
define view entity ZI_SalesOrderBasic
as select from zsalesorder
{
key vbeln,
erdat,
sales_org,
customer,
net_value,
currency
}
✅ Annotations:
@AccessControl.authorizationCheck: #CHECK → Will enforce DCL
@EndUserText.label → For user-friendly naming
3️⃣ Composite View (VDM Layer 2 - Composite)
(If you want to join other data like customer master, material master later — for now just wrap.)
abap
CopyEdit
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Composite Sales Order View'
define view entity ZC_SalesOrder
as select from ZI_SalesOrderBasic
{
key vbeln,
erdat,
sales_org,
customer,
net_value,
currency
}
✅ Same authorization enforced (#CHECK).
4️⃣ Consumption View (VDM Layer 3 - Ready for UI)
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Consumption View'
@UI.headerInfo: { typeName: 'Sales Order', title: { value: 'vbeln' }, description: { value: 'customer' } }
@UI.presentationVariant: [{ sortOrder: [{ by: 'vbeln', direction: #ASC }]}]
@Search.searchable: true
define root view entity C_SalesOrderConsumption
as select from ZC_SalesOrder
{
@UI.lineItem: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
key vbeln,
@UI.lineItem: [{ position: 20 }]
@UI.selectionField: [{ position: 20 }]
sales_org,
@UI.lineItem: [{ position: 30 }]
@UI.selectionField: [{ position: 30 }]
customer,
@UI.lineItem: [{ position: 40 }]
@Search.defaultSearchElement: true
net_value,
@UI.lineItem: [{ position: 50 }]
currency,
erdat
}
✅ Annotations Explained:
@UI.lineItem → Display fields in Smart Table
@UI.selectionField → Filters in Smart Filter Bar
@Search.searchable → Enable search
@Search.defaultSearchElement: true → Default field to search (net_value)
5️⃣ Define Authorization Aspect (for modular security)
define aspect ZAspect_SalesOrg
aspect for ZI_SalesOrderBasic
{
sales_org;
}
✅ Aspect defines modular "Sales Organization" check.
6️⃣ Define DCL Role
define role ZR_SalesOrderAccess
for entity ZI_SalesOrderBasic
{
grant select on ZI_SalesOrderBasic
where aspect ZAspect_SalesOrg;
}
✅ DCL connects to the Aspect which ensures:
Only sales_org matching user’s own sales_org will be visible.
✅ ZI_SalesOrderBasic is protected → All layers built on it (Composite, Consumption) inherit protection.
7️⃣ Activate OData Exposure (Optional)
Later, you create:
Service Definition exposing C_SalesOrderConsumption
Service Binding (OData V2 or V4)
Fiori List Report Template app from this service
🧠 Runtime Behavior Summary:
Only authorized users will see relevant Sales Orders.
Sales Org is auto-filtered using session context.
List is searchable (by Net Value).
Smart Filter has Sales Org, Customer as selectable filters.
UI labels are business-friendly.
📚 SAP Official Features Used
🎯 Final Project Recap
Day 7: CDS + OData Integration
@OData.publish annotation
Service Activation: /IWFND/MAINT_SERVICE
URI Testing, $metadata, $expand, $filter
Tasks:
Expose CDS via OData
Fetch data in browser using URI
Comments
Post a Comment