Wednesday, January 18, 2012

How to hide buttons for unauthorized users

In SAP CRM, it sometimes occurs that buttons are visible and clickable, even while the current user is not authorized to execute the action. It seems to depend on the developer that has built the screen whether this has been properly taken care of or not.

Fortunately, we have the enhancement framework, so we can easily implement this by enhancement ourselves. Let's take a look at some different views in a CRM 7.0 EhP1 system.
First we take a look at the coding in component BP_HEAD_SEARCH view BP_HEAD_SEARCH/MainSearchResult controller method do_prepare_output.

Here, we see the following coding:

IF gt_button IS INITIAL.
*   here the name of the button and the event is determine
    ls_button-type     = cl_thtmlb_util=>gc_icon_new.
    ls_button-text     = cl_wd_utilities=>get_otr_text_by_alias( 'CRM_UIU_BP/CORPORATEACCOUNT' ). "#EC NOTEXT
    ls_button-on_click = 'CREATECORP'.                      "#EC NOTEXT
*   check if button should be enabled according to UIU_COMP authorization values
    IF cl_crm_uiu_bp_authority=>bp_check_authority_create( iv_object_type = if_crm_bupa_uiu_otype~gc_otyp_corp_account ) = abap_true.
      ls_button-enabled  = gc_x.
    ENDIF.
    APPEND ls_button TO gt_button.
    CLEAR ls_button.

This is standard SAP coding. I have marked the code where an authorisation check is done, and depending on the outcome, the button is either greyed out, or clickable.

So, now, let's take a look at for instance view BT126S_APPT/ApptSR. In this case, in the do_prepare_output, there is no authority check at all. So, what happens if an unauthorized user clicks the button?

Hopefully, an unauthorized user will get an error message telling that the user is not authorized. Of course, this is not the best option. My guess would be, from a usability perspective, that it would be better to check the authorization before placing the button on the screen, just like in the BP_HEAD_SEARCH/MainSearchResult.

So, we can enhance the view as described here.
Then, we redefine the do_prepare_output, and we check on authorization before appending the button, and if not authorized, we simply state 'ls_button-enabled = abap_false'. If authorization is ok, we state 'ls_button-enabled  = abap_true'. Easy as that.


So, how do we know which authorization to check on? This certainly depends on the function provided by the button, but you can easily find it by having an unauthorized user click the button while an authorization trace is running. If it is due to missing UIU_COMP authorization, it will probably not show up, as this is loaded when starting the webclient, so that will require some more analysis.


Now that we know which authorization object is causing the error, we can code the auth check easily using the following statements:
AUTHORITY-CHECK OBJECT {object}
ID {ID_1} FIELD {value_1}
ID {ID_2} FIELD {value_2}
ID ... FIELD ...
IF sy-subrc EQ 0 .
   ls_button-enabled  = abap_true.
ELSE.
   ls_button-enabled = abap_false .
ENDIF.
So, for instance we could check whether the user is authorized to delete activities before adding the delete-button. What a coincidence this is actually a good example, as deleting activities in many cases is not applied to users...

The same of course applies to the one-click-actions that are applied to many assignment blocks. It seems pretty logical to check authorization before adding a button there as well.