Skip to Content
Technical Articles
Author's profile photo Saurabh Sharma

Authorization checks in apps using SAP Fiori elements

In one of my developments we came across a requirement to provide display access to a transactional app. This was for a wider audience than the app was previously designed for. Now to cater to this we had two options –

  1. Build a brand-new app which is not transactional. Have a new tile and provide access to the new user group to this tile.
  2. Incorporate authority checks in the existing app.

I would have loved to go with the first option, but it was quickly ruled out since along with using the standard template for list report and object page we also had a lot of custom logic like integrating the 3rd party APIs to display aggregated data in form of KPIs based on business requirement. New consumption CDS views would have to be built in case we had to build a new app. Then we also had to consider double maintenance effort that would be required in future to maintain two parallel source code, double regression testing for any variation etc.

Another driving factor was that we found this statement in “SAP UI5 SDK in the Security section

“Moreover, common security mechanisms, which are usually taken for granted, like user authentication, session handling, authorization handling, or encryption are not part of SAPUI5 and need to be handled by the server-side framework and/or custom code of the application

In this blog I will discuss the second approach and how I implemented it. I have used the same app as my previous blog “10 Interesting hacks for UI5 apps using Fiori Elements”. So if someone would like to experiment you can get the entire source code from there and just plug in the parts that I will discuss here.

The video of the app will show it in action. First, I login with as a user who is authorized to edit. Later as a display only user.

Steps are as follows –

1.  Create a new Authorization Object (SU21)

 

2.  Create two roles in PFCG and assign the new authorization object to the roles. One is a “Display” role and other is a “Admin” role. Assign the roles to distinct users to test (SU01). You will most probably need SAP security team help for this step. Here is the screenshot of the “Display” user’s role.

3.  To do the authority checks I created a new entity called ETY_AUTHORITY in the odata service. The reason for this is that we need to do the authority checks in ABAP. The actual data for the app is still coming from CDS views (which are referenced in oData service to leverage SADL capabilities)

METHOD ets_authority_get_entityset.
    DATA ls_entity LIKE LINE OF et_entityset.
    AUTHORITY-CHECK OBJECT 'ZORDER'
     ID 'ACTVT' FIELD '02'.
    "if authority check fails set it to uneditable
    IF sy-subrc <> 0.
      ls_entity-editable = ''.
    ELSE.
      ls_entity-editable = 'X'.
    ENDIF.
    APPEND ls_entity TO et_entityset.
ENDMETHOD.

4.  Now the frontend. In our UI5 app create a simple model file with methods to handle authority checks from backend. I have done this to ensure that the backend is called only once to check for authorization during the app lifecycle(The JavaScript file name is Model.js).

sap.ui.define([], function() {
	"use strict";
	var auth;
	return {
		setAuthority:function(){
			auth = 'X';
		},
		
		getAuthority: function(){
			return auth;
		}
	};
});

5.  In the onInit() method of ListReportExt I make the oData backend call for authority and the result I save it in the Model(see step 4). If the authority check fails, I set the Create and Delete button to invisible.

jQuery.sap.require("zcustomorder.model.Model");

sap.ui.controller("zcustomorder.ext.controller.ListReportExt", {
	//Local Model declaration 
	Model: sap.ui.require("zcustomorder/model/Model"),
	
	onInit: function(){
		//Somehow the chart entity is not called automatically so we need to call it explicitly to load
		this._loadChart();
		that = this;
		
		//Authority Check Logic
		var url = "/ETS_AUTHORITY";
		var functionSucess = function (oData, controller) {
			sap.ui.core.BusyIndicator.hide();
			var result = oData.results[0];
			if(result.Editable == ''){
				that.Model.setAuthority();
				var creButAll = that.getView().byId(
					"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--addEntry-t0"
				);
				var delButAll = that.getView().byId(
					"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--deleteEntry-t0"
				);
				if(creButAll){
					creButAll.setVisible(false);
				}
				if(delButAll){
					delButAll.setVisible(false);
				}
			}
		};
		var params = {
			async: false,
			success: function (oData, controller) {
				functionSucess(oData, controller);
			},
			error: function (oError) {
				sap.ui.core.BusyIndicator.hide();
			}
		};
		var oModel = this.getOwnerComponent().getModel();
		oModel.read(url, params);
		//End of Authority Check Logic
		
		//Auto value help logic for Smart Filter 
		var smFilt = this.getView().byId(
			"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--listReportFilter"
		);
		var conConfig = smFilt.getControlConfiguration();
		conConfig.forEach(function(item, idx, arr){
			smFilt.removeControlConfiguration(item);
			item.setPreventInitialDataFetchInValueHelpDialog(false);
			smFilt.addControlConfiguration(item);
		}, this);
	}
});

6.  It was a bit challenging for ObjectPage changes as we have to deal with line item level navigation and initialization is done only once. So, if we simply put the checks in onAfterRendering() method then the checks will work only for first entry and not the subsequent ones. To overcome this problem I put the logic to hide the “Edit” and “Delete” buttons in attachRequestCompleted() method which is called every time since the view data needs to be fetched from backend. Also note that I now use the Model.getAuthority() instead of making a backend call.

jQuery.sap.require("zcustomorder.model.Model");
sap.ui.controller("zcustomorder.ext.controller.ObjectPageExt", {
	//Local Model declaration 
	Model: sap.ui.require("zcustomorder/model/Model"),
	onInit: function () {
		that = this;
		
		//Automatic value help for Object Page smart field
		var fld = this.oView.byId("zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--RF1::qmnum::Field");
		if (fld) {
			var oConfig = fld.getConfiguration();
			if (!oConfig) {
				oConfig = new sap.ui.comp.smartfield.Configuration();
			}
			oConfig.setPreventInitialDataFetchInValueHelpDialog(false);
			oConfig.setDisplayBehaviour(sap.ui.comp.smartfield.DisplayBehaviour.descriptionAndId);
			fld.setConfiguration(oConfig);
		}
		
		//Convert Smart field into URL
		var notifFld = this.getView().byId(
			"zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--RF1::qmnum::Field"
		);
		if (notifFld) {
			notifFld.attachPress(this.onNotifPress);
		}
		
		// This will ensure that view context is loaded and Stndard buttons can be accessed
		this.getOwnerComponent().getModel().attachRequestCompleted(function () {
			var sPath = that.getView().getBindingContext() ? that.getView().getBindingContext().getPath() : '';
			if (sPath != '') {
				that.hideButtons();
			}
		});
	},
	
	hideButtons : function(){
		var oEdit = this.getView().byId(
			"zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--edit");
		var oDelete = this.getView().byId(
			"zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--delete");
		if(that.Model.getAuthority()){
			oEdit.setVisible(false);
			oDelete.setVisible(false);
		}
	}
});

 

That’s all folks. Hope you enjoyed the Blog.

Assigned Tags

      9 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo srinivasulu bandi
      srinivasulu bandi

      Nice blog.thanks a lot

      Author's profile photo Saurabh Sharma
      Saurabh Sharma
      Blog Post Author

      Thanks Srini


       

      Author's profile photo Pierre Dominique
      Pierre Dominique

      Hi,

      Is there a reason why you don't use the sap:creatable and sap:updatable annotations? This way the visibility of the New and Edit button is bound to a boolean property. Here's a blog post explaining the concept: https://blogs.sap.com/2017/06/06/dynamic-field-control-using-annotations-in-sapui5/

      Cheers,

      Pierre

      Author's profile photo Saurabh Sharma
      Saurabh Sharma
      Blog Post Author

      Hi Pierre,

      Thanks for your comment. I am aware of the field-control annotations and in fact I have used them in productive applications. As the name suggests they control the updatable and creatable properties of individual fields. The SAP documentation for the same is here –

      https://wiki.scn.sap.com/wiki/display/EmTech/SAP+Annotations+for+OData+Version+2.0#SAPAnnotationsforODataVersion2.0-Property_field_controlAttributesap:field-control

      Let’s suppose for a moment that we tie a field control to each field (which would be a lot of work for a complex view) and tie it to a Boolean value which we control through authority checks. But still the edit, create and delete buttons will appear in case of a transactional UI5 apps and will confuse the users.

      One alternative to the approach that I discussed here is to use capability annotations. I discussed that in my previous blog “10 Interesting hacks for UI5 apps using Fiori Elements” point 1. But there is no “creatable” option available yet which will remove the “Create” button from List Report. Even the "Updatable" and "Deletable" options are quite new in SAP framework and not so stable yet.

      Best regards,

      Saurabh

      Author's profile photo Pierre Dominique
      Pierre Dominique

      Hi Saurabh,

      I was indeed talking about the capability annotations as I’ve already used them in the past to show/hide the New and Edit buttons.

      EDIT: I just checked and sap:creatable cannot be bound to a boolean property so it's not perfect but using sap:updatable-path should work to show/hide the Edit button -> https://wiki.scn.sap.com/wiki/display/EmTech/SAP+Annotations+for+OData+Version+2.0

      Cheers,

      Pierre

      Author's profile photo Jocelyn Dart
      Jocelyn Dart

      Thanks Saurabh! I've added this to the Fiori elements wiki

      Author's profile photo Shilpa R
      Shilpa R

      Nice blog sir,It helped me so much

      Author's profile photo poonam kshirsagar
      poonam kshirsagar

      Hi,

      User can change button visibility using chrome console log. So dont we need to implement authorization check in actual entity creation time in backend again.

       

      Author's profile photo Telmo Soeiro
      Telmo Soeiro

      Hello every one.

      Thank you Saurabh Sharma,

      Since, in fact, the entire application is loaded on the browser, some users can change the button visibility on the dev tools of the browser or via console what makes the solution ineffective, therefore, Anyone know if there is already a more correct and safer way to authorize inside the SAPUI5 application?

       

      The example above complies visually the requirement, but I don't feel any confidence in putting such solution in a productive environment.

       

      Best Regards, and many thanks for your blog.