
CDS - Authority check (Part 2)
How do you deal with the issue of access control in Core Data Services in ABAP and how can you analyze errors? Read more in the article.
Table of contents
A while ago there was the first part of the authorization checks and in the meantime a number of points have accumulated that we would like to share with you in this article.
Introduction
With the new Table Entities there are now authorization checks directly at table level. But what about the analysis of errors and missing data? In this article we look at the topic of authorizations in the Core Data Service environment, how you can do an analysis and what inheritance actually has to do with it and what mistakes you can make.
Example
In the first step we need an example that we can practice on. Last time we used an authorization object, but there are other alternatives to restrict the data and thus give the user a restricted view.
Core Data Service
To do this, let's create a new Core Data Service on the ZBS_DMO_MATERIAL table. To do this, we go to the context menu:
We give the view a name and generate a VIEW ENTITY. Since we went to the object, the package is already suggested to us.
We then normalize the fields and set the annotation "AccessControl.authorizationCheck" to #CHECK, so that we receive a warning from the compiler if we do not create an authorization check.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Authority base view'
define view entity ZBS_B_DMOAuthBase
as select from zbs_dmo_material
{
key material as Material,
name as MaterialName,
description as Description,
stock as Stock,
stock_unit as Unit,
price_per_unit as PricePerUnit,
currency as Currency
}
If we now start the preview via F8 in the object or via ALT + F8 (Start objects), then we can look at the data as it appears in the database without any restrictions.
Access Control
Finally, we generate an access control on our Core Data Service in order to restrict the data for the user. Here we can go to the Core Data Service in the Project Explorer, this method is generally recommended as you can get to the right objects and information more quickly.
We name the access control like the Core Data Service, but the control can also have a different name. In the last step we choose "defineRoleWithSimpleCondition" as the template, but this is not necessarily important for the content as we can change it later.
@EndUserText.label: 'Access Control for ZBS_B_DMOAuthBase'
@MappingRole: true
define role ZBS_B_DMOAUTHBASE {
grant
select
on
ZBS_B_DMOAUTHBASE
where
Material LIKE 'F%';
}
If we now look at the "CDS Navigator" view of our Core Data Service, we will find our newly created access control. The view is a good first point of contact if we want to start analyzing the authorizations.
If we now look at the data in the "Data Preview", the amount has been reduced to all materials starting with an F. The access control is therefore active on the data. The compiler warning in the CDS view should now also have disappeared.
Inheritance
Now that we have generated our core data service and the access control, we create an interface view based on our first view. Basically, we don't make any further adjustments to the view.
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Base for Auth Test'
define view entity ZBS_I_DMOAuthBase
as select from ZBS_B_DMOAuthBase
{
key Material,
MaterialName,
Description,
Stock,
Unit,
PricePerUnit,
Currency
}
If we now check the CDS Navigator, we will see that access control is no longer active on the CDS views, since we only defined this for the lower view.
So if we run the data preview for our new Core Data Service, we see all the data and our defined authorization check has been bypassed. In certain scenarios this also makes sense, especially when it comes to complex checks and we want to use a Core Data Service in a new scenario. For example, if we only want to set up a value help and use non-critical data from the Core Data Service for it, then we do not need all the authorization checks of the lower view, but perhaps a new check.
To correct the behavior, we create an access control on the CDS view, using the template "defineRoleWithInheritedConditions". This saves us the implementation of perhaps complex authorization checks and objects and inherits the check from our base view.
@EndUserText.label: 'Inherit access control'
@MappingRole: true
define role ZBS_I_DMOAUTHBASE {
grant
select
on
ZBS_I_DMOAUTHBASE
where
inheriting conditions from entity ZBS_B_DMOAUTHBASE;
}
Access
In this chapter we look at access via ABAP, but also in ABAP Unit and how we can test the authorizations.
ABAP
In the next step we read the data in our process and use a simple SELECT. Since we should no longer read directly from the table, we use the Core Data Service for access. This way we have included the authorization check and the English long names.
SELECT FROM ZBS_I_DMOAuthBase
FIELDS Material, MaterialName, Description
INTO TABLE @DATA(data_with_restriction).
However, if we are in a technical process, for example in validation or background processing, then we may want to be able to access all the data. In that case, restricting the data makes no sense. However, we also do not want to create an additional Core Data Service without an ACL. Therefore, it is worth using the PRIVILEGED ACCESS addition.
SELECT FROM ZBS_I_DMOAuthBase
FIELDS Material, MaterialName, Description
INTO TABLE @DATA(data_without_restriction)
PRIVILEGED ACCESS.
If we now look at the result, we see the restricted data in the first step and then the access without restriction in the second access.
ABAP Unit
What does access via ABAP Unit look like? To do this, we first create our basic setup so that we can then carry out the test. To do this, we create a Core Data Service Double and mock up the first data for access. Since we only read materials with F at the beginning, we also create other materials.
CLASS ltc_cds_access DEFINITION FINAL
FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PRIVATE SECTION.
CLASS-DATA cds_environment TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS with_access_control FOR TESTING.
ENDCLASS.
CLASS ltc_cds_access IMPLEMENTATION.
METHOD class_setup.
DATA double_data TYPE STANDARD TABLE OF ZBS_B_DMOAuthBase WITH EMPTY KEY.
cds_environment = cl_cds_test_environment=>create( 'ZBS_I_DMOAuthBase' ).
double_data = VALUE #( ( Material = 'F001'
MaterialName = 'Find 1' )
( Material = 'F002'
MaterialName = 'Find 2' )
( Material = 'Z001'
MaterialName = 'Find 3' ) ).
cds_environment->insert_test_data( double_data ).
ENDMETHOD.
METHOD class_teardown.
cds_environment->destroy( ).
ENDMETHOD.
METHOD with_access_control.
SELECT FROM ZBS_I_DMOAuthBase
FIELDS Material, MaterialName, Description
INTO TABLE @DATA(data_with_restriction).
cl_abap_unit_assert=>assert_equals( exp = 2
act = lines( data_with_restriction ) ).
ENDMETHOD.
ENDCLASS.
Basically, we would expect the access control to take effect in the setup without any intervention from us. However, if we execute the method, we receive all the data from the test double without restriction and our unit test fails.
If we now want to validate the access control, we have to activate it in our test case. To do this, we use the class CL_CDS_TEST_DATA to get a control object. Since we do not want to check any PFCG objects, we pass an empty table to the method. We then activate the check in our test method using the ENABLE method on the CDS Double.
DATA(control_data) = cl_cds_test_data=>create_access_control_data( VALUE #( ) ).
cds_environment->get_access_control_double( )->enable_access_control( control_data ).
The documentation states that we always have to call DISABLE in the SETUP method when we use ENABLE. Therefore, we implement the SETUP method and insert the following code.
cds_environment->get_access_control_double( )->disable_access_control( ).
Our unit test now works and with a second method we can test with and without access control. You can find the entire unit test in the GitHub repository linked below.
Data Preview
In the example above we used the data preview, but got a limited view of the data there. You can also start the preview in the SQL Console and add WITH PRIVILEGED ACCESS to the SELECT statement, then you can also see all the data in the database.
The credits for the tip go to the SAP Developers YouTube channel, you can find the link to the video in the sources below.
Analysis
How can we start the analysis if our user cannot see all the data? In this chapter we want to look at different ways and methodologies.
Debugging
If it is a remote scenario where the user comes into the system via RFC or HTTP connection, we as developers can support another user via debugging. Depending on the complexity of the scenario or the code, we can look at the SELECTs and analyze the data returned.
Access Control
If we know which Core Data Service is returning too little data, it is usually worth taking a look at the access control of the view to find the necessary authorization objects or restrictions. In some cases, it may not even be a lack of authorization, but as in our example above, the view does not provide all the data because it was delimited using values.
Trace
When dealing with traces, we have often found that an authorization trace only tells half the truth and that restrictions in Core Data Services are already made when accessing the database level. This means that they do not appear in the classic analysis tools and must be analyzed using other methods.
On-Premise / Private Cloud
How can you get more detailed information about analyzing authorizations when you are using an on-premise system? The transaction SACMSEL is used to check a view in detail. Here we use a very complex view (I_OperationalAcctgDocItem) with many authorization checks from the financial area. You can run the report for any user and check the result for them.
After execution, we receive a detailed result of the test for the user and can therefore better understand missing authorizations.
If the user has no authorizations or is still missing authorizations, the image would look different accordingly. The authorization administrator can now search for which authorizations the user is still missing.
Summary
The access control offers a simple way to restrict the data of the Core Data Service for the user and to only pass on the required information. However, when reusing you should also make sure to define an access control in addition to the new view, otherwise you will lose the advantage again.
If you use the view in a SELECT, you save yourself the manual authorization check of the data and thus also lost performance compared to classic development. If you need full access, you can add a simple addition.
Full example
Today's example can be found in our documentation for Core Data Services in the GitHub repository. In this commit you will find the changes from this article in order to understand them specifically.
Conclusion
Protecting data during access is now easier than before, as we receive an authorization check via delivery to the Core Data Service. However, with new objects we also have to make sure that the authorization check is present and that it does not block us in our processing.
Source:
SAP Help - PRIVILEGED ACCESS
YouTube - Short Data Preview
YouTube - SAP TechBytes Access Control