Implementing Authority Checks

Objectives

After completing this lesson, you will be able to:
  • Restrict read access with access controls.
  • Implement explicit authority checks.

Authorization Overview

Authorization checks for various business-related activities such as read operation, modify operation, and service consumption

Business applications require an authorization concept for their data and for the operations on their data. Display and CRUD operations, and specific business-related activities, are, therefore, allowed for authorized users only.

In a transactional development scenario in RAP, you can add authorization checks to various components of an application. In this case, different mechanisms are used to implement the authorization concept.

Authorization Checks for Read Operations

To protect data from unauthorized read access, the Core Data Services in ABAP provide their own authorization concept based on a data control language (DCL). To restrict read access to RAP business objects, it is sufficient to define CDS access controls for the CDS view entities used in RAP business object. The CDS access control objects contain conditions that are used to filter the data during any read access. In other words, access controls allow you to limit the results returned by a CDS view entity to those results you authorize a user to see.

Authorization Checks for Modify Operations

In RAP business objects, modifying operations, such as standard operations (create, update, delete) and actions can be checked against unauthorized access during runtime. To retrieve user authorizations for incoming requests, authority checks are included in the behavior definition and implementation for your business object. In case of missing authorizations, the modification request is rejected.

Note

In UI scenarios, authority checks for modify operations are important, because the rejection of a modification request is visualized to the user (Consumer hints). For example, an action button is disabled for line items for which the user lacks execution authority.

Authorizations for OData Services Consumption

SAP Gateway provides predefined roles as templates for developers, administrators, end users of the content scenarios, and support colleagues. SAP customers configure the roles based on these templates and assign users to the roles.

For you, as a service developer, there are no further steps required for the service to be consumed externally within the customer's landscape. In particular, you don't need to provide any authorization default values of the authorization objects and specific role templates required for execution of your service. SAP Gateway already provides predefined roles as templates for accessing SAP Fiori apps.

An overview of RAP authorization control

To establish authorization checks for read operations, corresponding CDS roles are defined in CDS access controls, using the data control language (DCL). A CDS role specifies access rules. Each access rule defines access to the CDS view that the role is assigned to. Individual access controls are needed for the different CDS view levels, like data model (BO definition), BO interfaces, and BO projections. While the access rules on data model level are based on ABAP authorization objects, access controls on interface or projection level often inherit the access rules from the underlying entities.

The behavior definition on data model level, contains the authorization definition. It specifies for which entities of the RAP BO individual authority checks are applied and which of the checks are performed for individual instances. The handler classes in the behavior pool then provide appropriate code exits for implementing the authorization checks, for example with the AUTHORITY-CHECK statement.

CDS Access Controls

Create access controls with PFCG Authorization and Inheritance

Access controls enable you to filter access to data in the database. If no access control is created and deployed for the CDS entity, a user who can access the CDS entity can view all the data returned.

If you use the PFCG_AUTH aspect in the access control, user-dependent authorizations are used when accessing the CDS view. To implement this, you need an authorization object in the ABAP repository on which to base your authorization check. If you want to see the data, your user must be assigned a role that includes this authorization object with the matching values in the relevant fields.

When CDS views are built on top of each other, each CDS view needs its own access control. For example, an access control defined for a data model view does not also apply to the projection view built on top of this data model view. But it is not necessary to repeat the same conditions repeatedly. By using addition INHERITING CONDITIONS FROM ENTITY, one access control can inherit the conditions from another, typically an underlying CDS entity. In this way, a projection view can inherit its conditions from the underlying data model view or interface view.

Templates for creating access controls

When creating an Access Control, ADT offers several templates for the source code.

TheDefine Role with PFCG Aspect template is a blue print for an Access Control that defines conditions based on authorization objects.

The Define Role with Inherited Conditions template uses the addition INHERITING CONDITIONS FROM ENTITY instead.

Authority Check in Behavior Implementation

Activate authorization control in behavior definition

Authorization control in RAP protects your business object against unauthorized access to data. Authorization control is defined on entity level by adding authorization master ( ... ) or authorization dependent by to the define behavior statement.

Note

With the strict syntax rules ( strict; or strict( 2 );), every entity has to be flagged as either authorization master or uthorization dependent.

In the brackets after authorization master, the following variants are available:

( global )

Global authorization control grants or refuses access for all instances of a BO entity. It does not consider any specifics of the instances. With global authorization control, a user is either authorized to update all instances or none.

Global authorization control is implemented in a handler method defined with addition FOR GLOBAL AUTHORIZATION.

( instance )

Instance-based authorization control grants or refuses access based on the state of the entity instance.

Instance-based authorization control is implemented in a handler method defined with addition FOR INSTANCE AUTHORIZATION.

Note

For compatibility reasons, FOR AUTHORITY is also accepted but not recommended.

( global, instance )

It is possible to combine global and instance-based authority control for the same BO entity. Instance-based operations are checked in the global and in the instance authority check.

Specifying both values requires the definition and implementation of two methods for authority check, one with the FOR GLOBAL AUTHORIZATION addition, the other with the FOR INSTANCE AUTHORIZATION addition.

Create an authorization handler method

If the behavior definition contains the authorization addition when you create the behavior pool, the quick fix will automatically create the local handler class and the method or methods for authorization implementation.

If you add the authorization definition when the behavior pool already exists, you have to add the missing implementation method.

There is a quick fix for updating the behavior pool. To invoke this quick fix, either choose the warning icon with the lightbulb or right-click the entity name, and choose Quick Fix or place the cursor on the entity name and press Ctrl + 1.

Implementation of the authorization handler methods

Authorization handler methods are defined with the FOR INSTANCE AUTHORIZATION addition or with the FOR GLOBAL AUTHORIZATION addition. Which methods are required depends on the behavior definition.

Like all handler methods, authorization handler methods require specific parameters that are supplied or evaluated by the RAP runtime framework. The types of these parameters are derived from the CDS data definition and the CDS behavior definition.

Note

You can rename the methods and parameters freely. In this course, however, we stick to the names suggested by the quick fixes to avoid confusion.

Parameters of the authority handler method

The authority handler methods have the following parameters:

KEYS
  • Keys of the affected entity instances
  • Only available in the FOR INSTANCE AUTHORIZATION method.
  • Typed with derived data type TABLE FOR AUTHORIZATION KEY
Requested_authorizations
  • Can be used to only perform requested checks (performance optimization)
  • Contains flags for requested basic operations (create, update, delete) and actions
  • Possible values are the components of constant IF_ABAP_BEHV~MK
  • Components depend on behavior definition
  • Typed with derived data type STRUCTURE FOR AUTHORIZATION REQUEST
Result
  • Internal table with instance keys and flags for basic operations and actions
  • Possible values are the components of constant IF_ABAP_BEHV~AUTH
  • Type depends on behavior definition
  • Typed with derived data type TABLE FOR AUTHORIZATION RESULT
Example of an instance-based authorization check

The code example shows the implementation of an instance-based authority check. The check itself is done using the AUTHORITY-CHECK ABAP statement.

First, the method uses importing parameter keys, to read the data of all entity instances for which the authority check is to be performed.

It then performs the authorization check for each data set (entity instance) in turn. If the user does not have the requested authorization, the logic adds a row to parameter result that contains the key of the entity instance and flags for the disallowed operations.

Note

The structured constant IF_ABAP_BEHV=>AUTH contains components AUTHORIZED and UNAUTHORIZED. If an authorization check is successful, you can explicitly set the flags to AUTHORIZED. It is not necessary if you properly initialize the structure, because the value of AUTHORIZED equals the built-in initial value of the flags.

Implement Authority Checks

In this exercise, you implement authority checks for your application: read access in CDS access controls, write access by implementing a method of the behavior handler class.

Note

In this exercise, replace ## with your group number.

Solution

Repository Object TypeRepository Object ID
CDS Access Control (Model)/LRN/437B_R_TRAVEL
CDS Access Control (Projection)/LRN/437B_C_TRAVEL
CDS Behavior Definition (Model)/LRN/437B_R_TRAVEL
ABAP class/LRN/BP_437B_R_TRAVEL

Task 1: Analyze Authorization Object /LRN/AGCY

Open the definition of Authorization Object /LRN/AGCY and analyze it.

Steps

  1. Open the definition of authorization object /LRN/AGCY.

    1. In ABAP Development Tools, choose Open ABAP Development Object or press Ctrl + Shift + A.

    2. Enter /LRN/AGCY.

    3. From the list of matching items, select /LRN/AGCY (Authorization Object) and choose OK.

  2. Analyze the definition of the authorization object.

Task 2: Define CDS Access Controls

Create an access control for each of your CDS view entities. In the access control for your data model view entity Z##_R_Travel, grant access to the travels that were booked at the travel agencies for which the current user has display rights. In the access control for your projection view entity Z##_C_Travel, inherit the conditions from the data model view entity.

Steps

  1. Create an access control for your data model view entity (suggested name: Z##_R_TRAVEL). When prompted for a template choose Define Role with PFCG Aspect.

    1. In the Project Explorer, right-click the data definition of your data model view entity and select New Access Control.

    2. Enter a name and a description and choose Next.

    3. Confirm the preselected transport request and choose Next.

    4. In the list of available templates, select Define Role with PFCG Aspect and choose Finish.

  2. In the brackets after the WHERE keyword, specify the view element that contains the travel agency number.

    1. Adjust the code as follows:

      Code Snippet
      12345678
      define role Z##_R_TRAVEL { grant select on Z##_R_TRAVEL where (AgencyId) = aspect pfcg_auth(...); }
  3. Supply the function pfcg_auth( ) with the name of the authority object and its authorization fields. Use authorization field ACTVT as a filter field and assign the value for display authorization as filter value.

    1. Adjust the code as follows:

      Code Snippet
      1234567891011
      define role Z##_R_TRAVEL { grant select on Z##_R_TRAVEL where (AgencyId) = aspect pfcg_auth( /LRN/AGCY, /LRN/AGCY, ACTVT = '03'); }
  4. Activate the new access control.

    1. Press Ctrl + F3 to activate the development object.

  5. Create an access control for your projection view entity (suggested name: Z##_C_TRAVEL). When prompted for a template, choose Define Role with Inherited Conditions. Let the access control inherit the conditions from your data model view entity.

    1. In the Project Explorer, right-click the data definition of your projection view entity and select New Access Control.

    2. Enter a name and a description and choose Next.

    3. Confirm the preselected transport request and choose Next.

    4. In the list of available templates, select Define Role with Inherited Conditions and choose Finish.

  6. After the keyword ENTITY, specify your data model view.

    1. Adjust the code as follows:

      Code Snippet
      12345678
      define role Z##_C_TRAVEL { grant select on Z##_C_TRAVEL where inheriting conditions from entity Z##_R_Travel; }
  7. Activate the new access control.

    1. Press Ctrl + F3 to activate the development object.

  8. Test the preview of your OData UI service to verify that now not all entries of your database table are displayed.

    1. Return to the preview of your OData UI service and choose Go.

      Result

      You should see fewer entries than before.

Task 3: Instance-Based Authorization Control

In the behavior implementation for your root entity, implement the get_instance_authorizations method. Make sure that the user needs the change authorization for the travel agency to update travels and to execute action cancel_travel.

Note

Instead of using the statement AUTHORITY-CHECK directly, use method authority_check of the helper class /LRN/CL_S4D437_MODEL. This method simulates different authorizations for different users.

Steps

  1. Navigate to the handler class for your root entity and implement the get_instance_authorizations method. Fill the result parameter with one row for each affected flight travel.

    Hint

    Use a CORRESPONDING expression to transfer the content of the keys parameter to the result parameter.
    1. Adjust the code as follows:

      Code Snippet
      1234
      METHOD get_instance_authorizations. result = CORRESPONDING #( keys ). ENDMETHOD.
  2. Implement a loop over the result parameter assigning an inline-declared field symbol (suggested name: <result>).

    1. Adjust the code as follows:

      Code Snippet
      1234567
      METHOD get_instance_authorizations. result = CORRESPONDING #( keys ). LOOP AT result ASSIGNING FIELD-SYMBOL(<result>). ENDLOOP. ENDMETHOD.
  3. Inside the loop, check whether the current user has change authorization for the respective travel agency.

    Note

    Instead of implementing an AUTHORITY-CHECK statement yourself, call the authority_check method of helper class /LRN/CL_S4D437_MODEL. This method simulates different authorization profiles for different users.
    1. Adjust the code as follows:

      Code Snippet
      12345678910
      METHOD get_instance_authorizations. result = CORRESPONDING #( keys ). LOOP AT result ASSIGNING FIELD-SYMBOL(<result>). DATA(rc) = /lrn/cl_s4d437_model=>authority_check( i_agencyid = <result>-agencyid i_actvt = '02' ). ENDLOOP. ENDMETHOD.
  4. Using the field symbol, update the current row of the result. Set the flags for the update operation and the cancel_travel action depending on the outcome of the authority_check method.

    Note

    You find suitable constants in interface IF_ABAP_BEHV.
    1. Adjust the code as follows:

      The ELSE branch is optional because the value of if_abap_behv=>auth-allowed is identical to the initial value.
      Code Snippet
      12345678910111213141516
      METHOD get_instance_authorizations. result = CORRESPONDING #( keys ). LOOP AT result ASSIGNING FIELD-SYMBOL(<result>). DATA(rc) = /lrn/cl_s4d437_model=>authority_check( i_agencyid = <result>-agencyid i_actvt = '02' ). IF rc <> 0. <result>-%action-cancel_travel = if_abap_behv=>auth-unauthorized. <result>-%update = if_abap_behv=>auth-unauthorized. ELSE. <result>-%action-cancel_travel = if_abap_behv=>auth-allowed. <result>-%update = if_abap_behv=>auth-allowed. ENDIF. ENDLOOP. ENDMETHOD.
  5. Activate your coding and test the authority check in the preview of the OData UI service.

    1. Press Ctrl + F3 to activate the development object.

    2. Restart the preview for the OData UI service.

    3. Select different travels and see if the Cancel the Travel button is displayed as active.

      Result

      You should find that for at least one of your travels the button is displayed inactive due to missing authorizations.