Using the AUTHORITY-CHECK Statement

Objective

After completing this lesson, you will be able to use the AUTHORITY-CHECK statement.

The AUTHORITY-CHECK Statement

To perform an authorization check explicitly, you use the AUTHORITY-CHECK statement. In it, you specify the authorization object against which you want to check, along with the required values. The AUTHORITY-CHECK here performs a check against object /DMO/TRVL and requires the user to have an authorization containing the value US for field CNTRY and 03 for field ACTVT.

How to Check the Result of the Authorization Check

Unlike the filtered authorization checks that come with CDS access controls, the AUTHORITY-CHECK statement does not prevent users from seeing data for which they have no authorization.

AUTHORITY-CHECK places a return code in the system field sy-subrc. By checking the value of sy-subrc immediately after the authorization check, you can find out whether the check was successful or not.

If the authorization check was successful, sy-subrc has the value 0. Other values of sy-subrc mean that the check has failed:

  • The value 4 means that the user has an authorization for the corresponding object, but not the right values.
  • The value 12 means that the user does not have an authorization for the corresponding object at all.

If the authorization check fails, you must ensure yourself that the user cannot access the data.

In the example, the authorization check requires the user to have an authorization for country 'US'. Since that is not the case for our user, sy-subrc is unequal to zero after the authorization check. In this case, the app displays the text No authorization'.

How to Use the AUTHORITY-CHECK Statement

Watch this video to know how to use the Authority-Check statement.

Implement Authority Checks

You realize that your code gives users access to data which they are not authorized to see. To amend this you first let your code read from CDS view entities for which CDS access controls are defined. Then you implement an explicit authority check to be able to distinguish between data the user is not authorized to see and data that does not exist at all.

Template:

  • /LRN/CL_S4D401_ITS_SEC_KEY (Global Class)

Solution:

  • /LRN/CL_S4D401_ACS_AUTH_CHECK (Global Class)

Task 1: Copy Template (Optional)

Copy the template class /LRN/CL_S4D401_ITS_SEC_KEY. If you finished the previous exercise, you can skip this task and continue editing your class ZCL_##_SOLUTION.

Steps

  1. Copy class /LRN/CL_S4D401_ITS_SEC_KEY to a class in your own package (suggested name: ZCL_##_SOLUTION, where ## stands for your group number).

    1. In the Project Explorer, right-click class /LRN/CL_S4D401_ITS_SEC_KEY to open the context menu.

    2. From the context menu, choose Duplicate....

    3. Enter the name of your package in the Package field. In the Name field, enter ZCL_##_SOLUTION, where ## stands for your group number.

    4. Choose Next.

    5. Confirm the transport request and choose Finish.

  2. Activate the copy.

    1. Press Ctrl + F3 to activate the class.

Task 2: Analyze Authorizations

Starting from database table /LRN/CARRIER, find the CDS access control that protects carrier data against unauthorized access. Analyze the CDS access control to find out which authorizations a user needs to display carrier data.

Steps

  1. Display the definition of database table /LRN/CARRIER.

    1. Press Ctrl + Shift + A and enter /LRN/CARRIER in the search field.

    2. Choose OK.

  2. Analyze the where-used list for this database table.

    1. In the definition of database table /LRN/CARRIER, right-click on /lrn/carrier and choose Get Where-Used List. Alternatively, click on /lrn/carrier and press Ctrl + Shift + G.

    2. On the Select Object Types dialog, ensure that at least the Object TypeData Definition is selected, and choose Finish.

    3. In the Search view below the editor, choose the funnel icon to open the filter dialog.

    4. Place the cursor in the Object Type(s) field and press Ctrl + Space to open a value help dialog.

    5. From the suggestion list, select DDLS/DF (Data Definition) and choose Apply.

  3. Analyze the where-used list for the CDS view /LRN/I_CARRIER.

    1. In the Search view, right-click on /LRN/I_CARRIER (Data Definition) and choose Get Where-Used List. Alternatively, click on /LRN/I_CARRIER (Data Definition) and press Ctrl + Shift + G.

    2. On the Select Object Types dialog, ensure that at least the Object TypeAccess Control is selected, and choose Finish.

    3. If the Search view below the editor displays too many hits, choose the funnel icon to open the filter dialog. Place the cursor in the Object Type(s) field and press Ctrl + Space to open a value help dialog. From the suggestion list, choose DCLS/DL (Access Control) and choose Apply.

  4. Open the definition of access control /LRN/I_CARRIER.

    1. In the Search view, double click /LRN/I_CARRIER (Access Control).

    2. The authorization object name is the first input parameter for function pfcg_auth.

    3. The other input parameters supply values for the authorization fields of the authorization object.

  5. Open the definition of the authorization object /LRN/CARR to analyze the meaning of the activity values.

    1. Hold down the Ctrl key and click on /LRN/CARR in the call of function pfcg_auth.

    2. The possible activity values are listed under Permitted Activities.

Task 3: Use CDS Access Control

In the constructor method of local class LCL_CARRIER, replace database table /LRN/CARRIER with CDS view /LRN/I_CARRIER, which is protected by CDS access control /LRN/I_CARRIER. Test the code with different carrier IDs as constructor input.

Steps

  1. Open the implementation of the constructor method of local class LCL_CARRIER.

    1. Return to the code of your global class ZCL_##_SOLUTION, where ## is your group number.

    2. Expand ZCL_##_SOLUTIONLCL_CARRIER in the Outline view and click on CONSTRUCTOR.

  2. Adjust the SELECT statement. In the FROM clause, replace database table /LRN/CARRIER with the CDS view found above.

    1. Adjust the code as follows:

      ABAP
      123
      SELECT SINGLE * FROM /lrn/carrier FROM /LRN/I_Carrier
  3. Fix the syntax errors. Replace the table field names with the corresponding CDS view element names.

    1. Adjust the code as follows:

      ABAP
      1234567891011
      * SELECT SINGLE * FROM /lrn/carrier * FIELDS concat_with_space( carrier_id, name, 1 ), currency_code * WHERE carrier_id = @i_carrier_id * INTO ( @me->name, @me->currency_code ). SELECT SINGLE FROM /LRN/I_Carrier FIELDS concat_with_space( AirlineID, Name, 1 ), CurrencyCode WHERE AirlineID = @i_carrier_id INTO ( @me->name, @me->currency_code ).
  4. Activate and test your global class as console app.

    1. Press Ctrl + F3.

    2. Press F9.

  5. In your global class, change the value of local constant c_carrier_id to UA.

    1. Switch to the Global Class tab.

    2. Adjust the code as follows:

      ABAP
      12
      * CONSTANTS c_carrier_id TYPE /dmo/carrier_id VALUE 'LH'. CONSTANTS c_carrier_id TYPE /dmo/carrier_id VALUE 'UA'.
  6. Activate and test your global class as console app.

    1. Press Ctrl + F3.

    2. Press F9.

Task 4: Implement an AUTHORITY-CHECK Statement

In the constructor method of local class LCL_CARRIER, implement an AUTHORITY-CHECK statement and raise exception CX_ABAP_AUTH_CHECK_EXCEPTION if the flight carrier exists but the user is not authorized for this carrier.

Steps

  1. Open the implementation of the constructor method of local class LCL_CARRIER.

    1. Make sure you have your global class ZCL_##_SOLUTION open in the editor, where ## is your group number.

    2. Expand ZCL_##_SOLUTIONLCL_CARRIER in the Outline view and click on CONSTRUCTOR.

  2. Adjust the SELECT statement to read from database table /LRN/CARRIER again.

    1. Adjust the code as follows:

      ABAP
      1234567891011
      * SELECT SINGLE * FROM /LRN/I_Carrier * FIELDS concat_with_space( AirlineID, Name, 1 ), CurrencyCode * WHERE AirlineID = @i_carrier_id * INTO ( @me->name, @me->currency_code ). SELECT SINGLE FROM /lrn/carrier FIELDS concat_with_space( carrier_id, name, 1 ), currency_code WHERE carrier_id = @i_carrier_id INTO ( @me->name, @me->currency_code ).
  3. Implement an AUTHORITY-CHECK statement that is performed if the read access was successful, that is if exception CX_ABAP_INVALID_VALUE has not been raised. Use the authorization object, authorization fields and values found above.

    1. Adjust the code as follows:

      ABAP
      123456789101112
      IF sy-subrc <> 0. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF. AUTHORITY-CHECK OBJECT '/LRN/CARR' ID '/LRN/CARR' FIELD i_carrier_id ID 'ACTVT' FIELD '03'. IF sy-subrc <> 0. ENDIF.
  4. If the user does not have the display authorization for the requested airline ID raise exception CX_ABAP_AUTH_CHECK_EXCEPTION.

    1. Adjust the code as follows:

      ABAP
      12345678
      AUTHORITY-CHECK OBJECT '/LRN/CARR' ID '/LRN/CARR' FIELD i_carrier_id ID 'ACTVT' FIELD '03'. IF sy-subrc <> 0. RAISE EXCEPTION TYPE cx_abap_auth_check_exception. ENDIF.
  5. Use a quick fix to add the exception CX_ABAP_AUTH_CHECK_EXCEPTION to the RAISING clause of the definition of the constructor method.

    1. In the RAISE EXCEPTION statement, click on cx_abap_auth_check_exception and press Ctrl + 1. Alternatively, choose the light-bulb icon to the left of the code row with the syntax warning.

    2. From the list of suggested quick fixes, choose Add raising declaration.

    3. As result, the definition of the constructor method should now look like this:

      ABAP
      123456
      METHODS constructor IMPORTING i_carrier_id TYPE /dmo/carrier_id RAISING cx_abap_invalid_value cx_abap_auth_check_exception.
  6. In your global class, extend the TRY … ENDTRY control structure with a CATCH block for the new exception CX_ABAP_AUTH_CHECK_EXCEPTION. Issue a suitable text to indicate that the user is not authorized to display the carrier.

    1. Adjust the code as follows:

      ABAP
      123456789
      TRY. DATA(carrier) = NEW lcl_carrier( i_carrier_id = c_carrier_id ). out->write( name = `Carrier Overview` data = carrier->get_output( ) ). CATCH cx_abap_invalid_value. out->write( |Carrier { c_carrier_id } does not exist| ). CATCH cx_abap_auth_check_exception. out->write( |No authorization to display carrier { c_carrier_id }| ). ENDTRY.
  7. Similarly, extend the TRY … ENDTRY control structure in the class_setup method of your local unit test class. Use the same implementation as in the catch block for exception CX_ABAP_INVALID_VALUE.

    Note

    This is just a workaround. Later in this course, you will learn how to handle several exceptions in the same catch block.
    1. Adjust the code as follows:

      ABAP
      1234567
      TRY. the_carrier = NEW lcl_carrier( i_carrier_id = some_flight_data-carrier_id ). CATCH cx_abap_invalid_value. cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ). CATCH cx_abap_auth_check_exception. cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ). ENDTRY.
  8. Activate and test your global class as console app. Ensure that your code displays the new text on the console: No authorization to display carrier UA.

    1. Press Ctrl + F3.

    2. Press F9.

  9. In your global class, change the value of local constant c_carrier_id back to LH.

    1. Switch to the Global Class tab.

    2. Adjust the code as follows:

      ABAP
      12
      * CONSTANTS c_carrier_id TYPE /dmo/carrier_id VALUE 'UA'. CONSTANTS c_carrier_id TYPE /dmo/carrier_id VALUE 'LH'.
  10. Activate and test your global class as console app. Ensure that the code displays the carrier and flight details as before.

    1. Press Ctrl + F3.

    2. Press F9.